This guide provides practical examples for interacting with the BRI MCP Server API.
- Getting Started
- Server Information
- Tool Discovery
- Frame Extraction
- Image Captioning
- Audio Transcription
- Object Detection
- Batch Processing
- Cache Management
- Error Handling
- Python Client Examples
http://localhost:8000
- MCP server running (
python mcp_server/main.py) - Video uploaded and stored in the system
- Video ID from the database
- curl: Command-line HTTP client
- Python requests: Python HTTP library
- jq: JSON processor (optional, for formatting)
curl http://localhost:8000/Response:
{
"name": "BRI MCP Server",
"version": "1.0.0",
"status": "running",
"tools_available": 4
}curl http://localhost:8000/healthResponse:
{
"status": "healthy",
"cache_enabled": true,
"tools_registered": 4
}curl http://localhost:8000/tools | jqResponse:
{
"tools": [
{
"name": "extract_frames",
"type": "function",
"description": "Extract frames from video at regular intervals or specific timestamps",
"parameters": {
"type": "object",
"properties": {
"interval_seconds": {
"type": "number",
"description": "Interval between frames in seconds",
"default": 2.0
},
"max_frames": {
"type": "integer",
"description": "Maximum number of frames to extract",
"default": 100
}
}
}
}
]
}curl -X POST http://localhost:8000/tools/extract_frames/execute \
-H "Content-Type: application/json" \
-d '{
"video_id": "video_123",
"parameters": {
"interval_seconds": 2.0,
"max_frames": 50
}
}' | jqResponse:
{
"status": "success",
"result": {
"frames": [
{
"timestamp": 0.0,
"frame_number": 0,
"image_path": "data/frames/video_123/frame_0000.jpg"
},
{
"timestamp": 2.0,
"frame_number": 60,
"image_path": "data/frames/video_123/frame_0060.jpg"
}
],
"count": 50,
"video_metadata": {
"duration": 120.5,
"fps": 30.0,
"width": 1920,
"height": 1080
}
},
"cached": false,
"execution_time": 3.45
}curl -X POST http://localhost:8000/tools/extract_frames/execute \
-H "Content-Type: application/json" \
-d '{
"video_id": "video_123",
"parameters": {
"timestamp": 45.5
}
}' | jqResponse:
{
"status": "success",
"result": {
"frame": {
"timestamp": 45.5,
"frame_number": 1365,
"image_path": "data/frames/video_123/frame_1365.jpg"
}
},
"cached": false,
"execution_time": 0.23
}curl -X POST http://localhost:8000/tools/caption_frames/execute \
-H "Content-Type: application/json" \
-d '{
"video_id": "video_123",
"parameters": {
"frame_paths": [
"data/frames/video_123/frame_0000.jpg",
"data/frames/video_123/frame_0060.jpg",
"data/frames/video_123/frame_0120.jpg"
],
"timestamps": [0.0, 2.0, 4.0]
}
}' | jqResponse:
{
"status": "success",
"result": {
"captions": [
{
"frame_timestamp": 0.0,
"text": "a person sitting at a desk with a laptop computer",
"confidence": 0.92
},
{
"frame_timestamp": 2.0,
"text": "a close up of a computer screen showing code",
"confidence": 0.88
},
{
"frame_timestamp": 4.0,
"text": "a person typing on a keyboard",
"confidence": 0.91
}
],
"count": 3
},
"cached": false,
"execution_time": 2.15
}curl -X POST http://localhost:8000/tools/transcribe_audio/execute \
-H "Content-Type: application/json" \
-d '{
"video_id": "video_123",
"parameters": {}
}' | jqResponse:
{
"status": "success",
"result": {
"transcript": {
"segments": [
{
"start": 0.0,
"end": 3.5,
"text": "Hello everyone, welcome to this tutorial.",
"confidence": 0.95
},
{
"start": 3.5,
"end": 7.2,
"text": "Today we're going to learn about video processing.",
"confidence": 0.93
}
],
"language": "en",
"full_text": "Hello everyone, welcome to this tutorial. Today we're going to learn about video processing."
}
},
"cached": false,
"execution_time": 15.67
}curl -X POST http://localhost:8000/tools/transcribe_audio/execute \
-H "Content-Type: application/json" \
-d '{
"video_id": "video_123",
"parameters": {
"start_time": 30.0,
"end_time": 45.0
}
}' | jqResponse:
{
"status": "success",
"result": {
"segment": {
"start": 30.0,
"end": 45.0,
"text": "This is the most important part of the process. Make sure to follow these steps carefully.",
"confidence": 0.94
}
},
"cached": false,
"execution_time": 3.21
}curl -X POST http://localhost:8000/tools/detect_objects/execute \
-H "Content-Type: application/json" \
-d '{
"video_id": "video_123",
"parameters": {
"frame_paths": [
"data/frames/video_123/frame_0000.jpg",
"data/frames/video_123/frame_0060.jpg"
],
"timestamps": [0.0, 2.0],
"confidence_threshold": 0.5
}
}' | jqResponse:
{
"status": "success",
"result": {
"detections": [
{
"frame_timestamp": 0.0,
"objects": [
{
"class_name": "person",
"confidence": 0.92,
"bbox": [100, 50, 300, 400]
},
{
"class_name": "laptop",
"confidence": 0.87,
"bbox": [150, 200, 250, 150]
}
]
},
{
"frame_timestamp": 2.0,
"objects": [
{
"class_name": "person",
"confidence": 0.91,
"bbox": [105, 52, 295, 398]
}
]
}
],
"total_objects": 3
},
"cached": false,
"execution_time": 1.89
}curl -X POST http://localhost:8000/tools/detect_objects/execute \
-H "Content-Type: application/json" \
-d '{
"video_id": "video_123",
"parameters": {
"frame_paths": [
"data/frames/video_123/frame_0000.jpg",
"data/frames/video_123/frame_0060.jpg",
"data/frames/video_123/frame_0120.jpg"
],
"timestamps": [0.0, 2.0, 4.0],
"object_class": "cat"
}
}' | jqResponse:
{
"status": "success",
"result": {
"occurrences": [
{
"timestamp": 2.0,
"frame_path": "data/frames/video_123/frame_0060.jpg",
"confidence": 0.89,
"bbox": [200, 150, 180, 200]
},
{
"timestamp": 4.0,
"frame_path": "data/frames/video_123/frame_0120.jpg",
"confidence": 0.91,
"bbox": [210, 155, 175, 195]
}
],
"total_found": 2
},
"cached": false,
"execution_time": 1.45
}curl -X POST http://localhost:8000/videos/video_123/process \
-H "Content-Type: application/json" \
-d '{
"tools": ["extract_frames", "caption_frames", "transcribe_audio", "detect_objects"]
}' | jqResponse:
{
"status": "complete",
"video_id": "video_123",
"results": {
"extract_frames": {
"status": "success",
"result": {
"frames": [...],
"count": 50
},
"cached": false,
"execution_time": 3.45
},
"caption_frames": {
"status": "success",
"result": {
"captions": [...],
"count": 50
},
"cached": false,
"execution_time": 12.34
},
"transcribe_audio": {
"status": "success",
"result": {
"transcript": {...}
},
"cached": false,
"execution_time": 15.67
},
"detect_objects": {
"status": "success",
"result": {
"detections": [...],
"total_objects": 127
},
"cached": false,
"execution_time": 8.92
}
},
"errors": null,
"total_execution_time": 40.38
}curl -X POST http://localhost:8000/videos/video_123/process \
-H "Content-Type: application/json" \
-d '{
"tools": ["extract_frames", "caption_frames"]
}' | jqcurl http://localhost:8000/cache/stats | jqResponse:
{
"enabled": true,
"total_keys": 42,
"redis_version": "7.0.0",
"used_memory_human": "1.23M",
"ttl_hours": 24,
"hit_rate": 0.67
}curl -X DELETE http://localhost:8000/cache/videos/video_123 | jqResponse:
{
"status": "success",
"video_id": "video_123",
"deleted_count": 4,
"message": "Cache cleared for video_123"
}curl -X DELETE http://localhost:8000/cache | jqResponse:
{
"status": "success",
"message": "All cache entries cleared",
"deleted_count": 42
}curl -X POST http://localhost:8000/tools/invalid_tool/execute \
-H "Content-Type: application/json" \
-d '{
"video_id": "video_123",
"parameters": {}
}' | jqResponse (404):
{
"detail": "Tool 'invalid_tool' not found"
}curl -X POST http://localhost:8000/tools/extract_frames/execute \
-H "Content-Type: application/json" \
-d '{
"video_id": "nonexistent_video",
"parameters": {}
}' | jqResponse (500):
{
"status": "error",
"result": {
"error": "Video file not found: data/videos/nonexistent_video.mp4"
},
"cached": false,
"execution_time": 0.05
}curl -X POST http://localhost:8000/tools/extract_frames/execute \
-H "Content-Type: application/json" \
-d '{
"video_id": "video_123",
"parameters": {
"interval_seconds": "invalid"
}
}' | jqResponse (422):
{
"detail": [
{
"loc": ["body", "parameters", "interval_seconds"],
"msg": "value is not a valid float",
"type": "type_error.float"
}
]
}import requests
import json
class BRIClient:
def __init__(self, base_url="http://localhost:8000"):
self.base_url = base_url
self.session = requests.Session()
def health_check(self):
"""Check if server is healthy"""
response = self.session.get(f"{self.base_url}/health")
return response.json()
def list_tools(self):
"""Get all available tools"""
response = self.session.get(f"{self.base_url}/tools")
return response.json()
def execute_tool(self, tool_name, video_id, parameters=None):
"""Execute a specific tool"""
payload = {
"video_id": video_id,
"parameters": parameters or {}
}
response = self.session.post(
f"{self.base_url}/tools/{tool_name}/execute",
json=payload
)
return response.json()
def process_video(self, video_id, tools=None):
"""Process video with multiple tools"""
payload = {
"tools": tools or ["extract_frames", "caption_frames",
"transcribe_audio", "detect_objects"]
}
response = self.session.post(
f"{self.base_url}/videos/{video_id}/process",
json=payload
)
return response.json()
# Usage
client = BRIClient()
# Check health
health = client.health_check()
print(f"Server status: {health['status']}")
# List tools
tools = client.list_tools()
print(f"Available tools: {len(tools['tools'])}")
# Extract frames
result = client.execute_tool(
"extract_frames",
"video_123",
{"interval_seconds": 2.0, "max_frames": 50}
)
print(f"Extracted {result['result']['count']} frames")def extract_and_caption(client, video_id):
"""Extract frames and generate captions"""
# Step 1: Extract frames
print("Extracting frames...")
frames_result = client.execute_tool(
"extract_frames",
video_id,
{"interval_seconds": 5.0, "max_frames": 20}
)
if frames_result["status"] != "success":
print(f"Error: {frames_result['result']['error']}")
return
frames = frames_result["result"]["frames"]
print(f"Extracted {len(frames)} frames")
# Step 2: Caption frames
print("Generating captions...")
frame_paths = [f["image_path"] for f in frames]
timestamps = [f["timestamp"] for f in frames]
captions_result = client.execute_tool(
"caption_frames",
video_id,
{
"frame_paths": frame_paths,
"timestamps": timestamps
}
)
if captions_result["status"] != "success":
print(f"Error: {captions_result['result']['error']}")
return
# Display results
captions = captions_result["result"]["captions"]
for caption in captions:
print(f"[{caption['frame_timestamp']:.1f}s] {caption['text']}")
# Usage
client = BRIClient()
extract_and_caption(client, "video_123")def find_object_in_video(client, video_id, object_class):
"""Find all occurrences of an object in a video"""
# First, extract frames
frames_result = client.execute_tool(
"extract_frames",
video_id,
{"interval_seconds": 2.0}
)
if frames_result["status"] != "success":
return []
frames = frames_result["result"]["frames"]
frame_paths = [f["image_path"] for f in frames]
timestamps = [f["timestamp"] for f in frames]
# Detect objects
detection_result = client.execute_tool(
"detect_objects",
video_id,
{
"frame_paths": frame_paths,
"timestamps": timestamps,
"object_class": object_class
}
)
if detection_result["status"] != "success":
return []
occurrences = detection_result["result"]["occurrences"]
print(f"Found {len(occurrences)} occurrences of '{object_class}':")
for occ in occurrences:
print(f" - At {occ['timestamp']:.1f}s (confidence: {occ['confidence']:.2f})")
return occurrences
# Usage
client = BRIClient()
find_object_in_video(client, "video_123", "cat")import aiohttp
import asyncio
class AsyncBRIClient:
def __init__(self, base_url="http://localhost:8000"):
self.base_url = base_url
async def execute_tool(self, session, tool_name, video_id, parameters=None):
"""Execute a tool asynchronously"""
payload = {
"video_id": video_id,
"parameters": parameters or {}
}
async with session.post(
f"{self.base_url}/tools/{tool_name}/execute",
json=payload
) as response:
return await response.json()
async def process_video_parallel(self, video_id):
"""Process video with multiple tools in parallel"""
async with aiohttp.ClientSession() as session:
tasks = [
self.execute_tool(session, "extract_frames", video_id),
self.execute_tool(session, "transcribe_audio", video_id),
]
results = await asyncio.gather(*tasks)
return results
# Usage
async def main():
client = AsyncBRIClient()
results = await client.process_video_parallel("video_123")
print(f"Completed {len(results)} tasks")
asyncio.run(main())Instead of calling tools individually, use the batch processing endpoint:
# Good: Single request
curl -X POST http://localhost:8000/videos/video_123/process \
-d '{"tools": ["extract_frames", "caption_frames"]}'
# Less efficient: Multiple requests
curl -X POST http://localhost:8000/tools/extract_frames/execute ...
curl -X POST http://localhost:8000/tools/caption_frames/execute ...Repeated queries with the same parameters will use cached results:
# First call: processes video
result1 = client.execute_tool("extract_frames", "video_123")
print(f"Cached: {result1['cached']}") # False
# Second call: uses cache
result2 = client.execute_tool("extract_frames", "video_123")
print(f"Cached: {result2['cached']}") # Truedef safe_execute(client, tool_name, video_id, parameters=None):
try:
result = client.execute_tool(tool_name, video_id, parameters)
if result["status"] == "error":
print(f"Tool error: {result['result']['error']}")
return None
return result["result"]
except requests.exceptions.RequestException as e:
print(f"Network error: {e}")
return Noneresult = client.execute_tool("extract_frames", "video_123")
print(f"Execution time: {result['execution_time']:.2f}s")
print(f"Cached: {result['cached']}")# Clear cache after video updates
client.session.delete(f"{client.base_url}/cache/videos/{video_id}")For more information, see:
- MCP Server README - Complete API reference
- User Guide - Using BRI through the UI
- Configuration - Server configuration options