Model Context Protocol (MCP) server for OpenAI Sora 2 video generation
10K+
A production-ready Model Context Protocol (MCP) server for OpenAI Sora 2 video generation.
Exposes Sora 2 video workflows as MCP tools so AI clients can generate, edit, extend, and manage videos safely and reliably.
git clone <repo-url> && cd yomrishon-mcp-sora
npm install
npm run build
cp .env.example .env
# Edit .env and set OPENAI_API_KEY
| Variable | Required | Default | Description |
|---|---|---|---|
OPENAI_API_KEY | stdio | — | OpenAI API key (required in stdio mode; optional in HTTP mode) |
OPENAI_BASE_URL | No | https://api.openai.com/v1 | API base URL |
SORA_DEFAULT_MODEL | No | sora-2 | Default model for generation |
SORA_MAX_POLL_SECONDS | No | 300 | Max polling duration |
SORA_POLL_INTERVAL_MS | No | 5000 | Polling interval |
SORA_DEBUG | No | false | Enable debug logging |
SORA_ALLOWED_UPLOAD_DIRS | No | /tmp | Comma-separated allowed upload directories |
MCP_TRANSPORT | No | stdio | Transport mode: stdio or http |
MCP_HTTP_PORT | No | 3000 | HTTP listen port (HTTP mode only) |
MCP_HTTP_HOST | No | 127.0.0.1 | HTTP listen host (HTTP mode only) |
# Stdio mode (default)
node dist/index.js
# HTTP mode
MCP_TRANSPORT=http node dist/index.js
# Build
docker build -t yomrishon-mcp-sora .
# Run
docker run -e OPENAI_API_KEY=sk-... yomrishon-mcp-sora
A GitHub Actions workflow at .github/workflows/docker-publish.yml automatically builds and pushes the Docker image to Docker Hub on:
mainv*)Required GitHub repo secrets:
| Secret | Description |
|---|---|
DOCKERHUB_USERNAME | Your Docker Hub username |
DOCKERHUB_TOKEN | Docker Hub access token |
Add to your MCP settings (e.g., claude_desktop_config.json or VS Code MCP settings):
{
"mcpServers": {
"sora": {
"command": "node",
"args": ["/absolute/path/to/yomrishon-mcp-sora/dist/index.js"],
"env": {
"OPENAI_API_KEY": "sk-..."
}
}
}
}
{
"mcpServers": {
"sora": {
"command": "npx",
"args": ["yomrishon-mcp-sora"],
"env": {
"OPENAI_API_KEY": "sk-..."
}
}
}
}
When MCP_TRANSPORT=http, the server starts a Streamable HTTP endpoint instead of using stdio.
Each request carries its own API key via the Authorization header, so a single server instance can serve many clients with different OpenAI accounts.
MCP_TRANSPORT=http MCP_HTTP_PORT=3000 node dist/index.js
Or with Docker:
docker run -p 3000:3000 \
-e MCP_TRANSPORT=http \
-e MCP_HTTP_HOST=0.0.0.0 \
yomrishon-mcp-sora
Point your MCP client at the HTTP endpoint:
{
"mcpServers": {
"sora": {
"url": "http://localhost:3000/mcp",
"headers": {
"Authorization": "Bearer sk-..."
}
}
}
}
| Method | Path | Description |
|---|---|---|
POST | /mcp | MCP JSON-RPC endpoint (requires Authorization: Bearer <key>) |
GET | /mcp | SSE stream for server-initiated messages |
DELETE | /mcp | Session close (no-op in stateless mode) |
GET | /health | Health check — returns {"status":"ok"} |
GET | /download/:token | Proxy download — streams video content using a short-lived token (no API key needed) |
MCP_HTTP_HOST defaults to 127.0.0.1 (loopback only). Set to 0.0.0.0 to accept remote connections.OPENAI_API_KEY is set alongside HTTP mode, it acts as a fallback when clients omit the header.sora_describe_capabilitiesCall this first to understand what parameters are valid.
{}
Returns supported models, sizes, durations, and feature flags.
sora_create_videoCreate a new video generation job.
{
"prompt": "A golden retriever runs through a sunlit meadow at dawn. Slow tracking shot from the side, golden hour light streaming through tall grass. Cinematic, shallow depth of field, 35mm film grain.",
"model": "sora-2",
"size": "1920x1080",
"seconds": 10
}
With image reference:
{
"prompt": "The same landscape transforms from winter to spring. Time-lapse style, static camera.",
"input_reference": {
"type": "image_url",
"url": "https://example.com/winter-landscape.jpg"
},
"seconds": 15
}
With characters:
{
"prompt": "Luna the astronaut floats through the space station corridor. Close-up tracking shot, blue ambient lighting.",
"characters": [
{ "id": "char_abc123", "name": "Luna" }
],
"seconds": 10
}
sora_get_videoCheck a job's status.
{
"video_id": "vid_abc123"
}
sora_wait_for_videoBlock until the job completes or times out.
{
"video_id": "vid_abc123",
"poll_interval_ms": 5000,
"max_wait_seconds": 120
}
sora_list_videosList recent jobs with optional filters.
{
"status": "completed",
"model": "sora-2",
"limit": 10
}
sora_download_video_contentGet a download URL for a completed video. Returns a proxy URL that can be used directly without an API key.
{
"video_id": "vid_abc123"
}
Returns:
{
"download_url": "http://localhost:3000/download/<token>",
"content_type": "video/mp4",
"expires_in_seconds": 600
}
The download_url is single-use and expires after 10 minutes. Call the tool again to get a fresh URL.
sora_edit_videoEdit an existing video with a new prompt.
{
"source_video_id": "vid_abc123",
"prompt": "Change the lighting to a warm sunset tone and slow the camera movement.",
"model": "sora-2"
}
sora_extend_videoExtend a completed video with additional footage.
{
"video_id": "vid_abc123",
"prompt": "The camera continues to pan right, revealing a hidden waterfall behind the trees.",
"seconds": 10
}
sora_create_characterUpload a character for cross-shot consistency.
{
"name": "Luna",
"file_path": "/tmp/luna-reference.mp4",
"description": "Female astronaut, short dark hair, blue flight suit"
}
Or from a previously uploaded file:
{
"name": "Luna",
"file_id": "file_abc123",
"description": "Female astronaut, short dark hair, blue flight suit"
}
sora_get_character{
"character_id": "char_abc123"
}
sora_remix_videoDeprecated — use
sora_edit_videoinstead.
{
"source_video_id": "vid_abc123",
"prompt": "Same scene but in anime style.",
"model": "sora-2"
}
sora_help_promptGet a structured prompt brief from a rough idea. Does not call the API.
{
"idea": "a cat exploring a neon-lit Tokyo alley at night",
"style": "cyberpunk",
"constraints": ["no text", "single take"]
}
Returns a framework with sections (subject, action, setting, camera, lighting, style, continuity) plus composition tips and an example.
All model capabilities are defined in src/capabilities.ts. When Sora 2 capabilities change:
src/capabilities.tsnpm run buildThe capability file is extensively commented. Do not scatter capability checks throughout the codebase.
| Category | Description |
|---|---|
ValidationError | Invalid user input (missing fields, bad types) |
CapabilityError | Unsupported operation for selected model |
OpenAIAPIError | Upstream API call failed |
RateLimitError | OpenAI rate-limited the request |
AssetError | File/asset issue (missing, wrong type, expired) |
TimeoutError | Polling timed out before completion |
NotFoundError | Requested resource not found |
All errors include a category, message, and optional details with allowed values.
"OPENAI_API_KEY environment variable is required"
Set the key in your environment or MCP client config's env block.
"Size X is not supported for model Y"
Call sora_describe_capabilities to see valid sizes for your model.
"Video did not reach terminal status within Ns"
Video generation can take minutes. Increase max_wait_seconds or use sora_get_video to poll manually.
"File path is outside allowed upload directories"
Set SORA_ALLOWED_UPLOAD_DIRS to include your upload directory.
Debug mode
Set SORA_DEBUG=true to see full request/response bodies in stderr logs (API keys are still redacted).
SORA_ALLOWED_UPLOAD_DIRS)MCP_HTTP_HOST defaults to loopback (127.0.0.1)MIT
Content type
Image
Digest
sha256:c437e4474…
Size
60.4 MB
Last updated
7 months ago
docker pull yomrishon/mcp-sora