Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OpenAI MCP Server

The complete OpenAI API surface as Model Context Protocol tools for Claude Code, Cursor, Windsurf, and any MCP client.

npm version License: MIT Node MCP

A single stdio MCP server that exposes 42 tools covering every major OpenAI endpoint: Responses, Chat Completions, Images (gpt-image-1.5), Audio (TTS + transcription + translation), Embeddings, Moderation, Files, Batch, Vector Stores, Fine-tuning, and multipart Large Uploads.

Features

  • Responses API (primary): reasoning, built-in tools (web_search, file_search, code_interpreter, image_generation), background mode, stored responses, input-item retrieval.
  • Chat Completions: legacy endpoint with auto-routing between reasoning-model params (reasoning_effort, max_completion_tokens) and standard params.
  • Images: gpt-image-1.5 generate + edit with mask, save-to-disk, base64 streaming, input fidelity.
  • Audio: gpt-4o-mini-tts text-to-speech, gpt-4o-transcribe + whisper-1 transcription with word/segment timestamps, English translation.
  • Embeddings: text-embedding-3-large at full 3072 dimensions.
  • Files: upload, list, retrieve, download, delete (gated).
  • Batch: 50%-cost async jobs for Responses/Chat/Embeddings/Moderation/Images.
  • Vector Stores: create, list, retrieve, attach files (single + batch), search, delete.
  • Fine-tuning: create jobs, list, retrieve, cancel, events, checkpoints.
  • Large Uploads: multipart streaming up to 8 GB in 64 MB chunks with MD5 integrity.
  • Max-capability defaults: reasoning_effort=high, verbosity=high, image quality high, 1024x1536 portrait, per-model auto-fill for max_output_tokens.
  • Security built-in: path deny-list, write-basename deny, hosted-tool block (mcp/shell/computer_use), destructive-action gate, 401 cache invalidation, SSRF guard on image URLs.

Installation

From npm

npm install -g openai-mcp-server

Binary openai-mcp-server is placed on your PATH.

From source

git clone https://github.com/salviz/openai-mcp-server.git
cd openai-mcp-server
npm install
node index.js   # sanity check — it will wait for an MCP client on stdio

Requires Node.js >= 20. Works on Linux, macOS, Windows (WSL), and Android/Termux.

API key

The server resolves your OpenAI API key from three sources, in this order — the first match wins:

1. Environment variable (simplest)

export OPENAI_API_KEY="sk-proj-..."
openai-mcp-server

2. File reference (good for secret managers, 1Password CLI, pass, etc.)

echo -n "sk-proj-..." > ~/.config/openai/api_key
chmod 600 ~/.config/openai/api_key
export OPENAI_API_KEY_FILE="~/.config/openai/api_key"
openai-mcp-server

Path is ~-expanded. Only the first line is read, whitespace trimmed.

3. Google Cloud Secret Manager fallback

If neither of the above is set and gcloud is available, the server will attempt:

gcloud secrets versions access latest \
  --secret="$OPENAI_MCP_GCP_SECRET" \
  --project="$OPENAI_MCP_GCP_PROJECT"

Set the project and secret name yourself:

export OPENAI_MCP_GCP_PROJECT="my-gcp-project"
export OPENAI_MCP_GCP_SECRET="openai-api-key"        # default if unset
export OPENAI_MCP_GCLOUD_BIN="/usr/bin/gcloud"       # override if non-standard
openai-mcp-server

The gcloud subprocess runs with a scrubbed environment (no inherited PATH tricks).

Register with Claude Code

Add to ~/.claude.json (user scope) or ~/.claude/settings.json under mcpServers:

{
  "mcpServers": {
    "openai": {
      "command": "openai-mcp-server",
      "env": {
        "OPENAI_API_KEY": "sk-proj-..."
      }
    }
  }
}

If installed from source, point at the absolute path:

{
  "mcpServers": {
    "openai": {
      "command": "node",
      "args": ["~/openai-mcp-server/index.js"],
      "env": { "OPENAI_API_KEY": "sk-proj-..." }
    }
  }
}

Restart Claude Code. Tools appear as mcp__openai__openai_responses, etc.

Register with Cursor / Windsurf / other MCP clients

Cursor (~/.cursor/mcp.json)

{
  "mcpServers": {
    "openai": {
      "command": "openai-mcp-server",
      "env": { "OPENAI_API_KEY": "sk-proj-..." }
    }
  }
}

Windsurf (~/.codeium/windsurf/mcp_config.json)

{
  "mcpServers": {
    "openai": {
      "command": "openai-mcp-server",
      "env": { "OPENAI_API_KEY": "sk-proj-..." }
    }
  }
}

Any MCP stdio client works — the server speaks standard MCP over stdin/stdout.

Tool catalog

Responses (5)

Tool Description
openai_responses Primary endpoint — create a Response with text, images, files, reasoning effort, and built-in tools. Hosted mcp/shell/computer_use types blocked by default. Auto-fills max_output_tokens per model family.
openai_response_get Retrieve a stored Response by id.
openai_response_cancel Cancel a background Response.
openai_response_delete Delete a stored Response. Gated by OPENAI_MCP_ALLOW_DESTRUCTIVE=1.
openai_response_input_items List input items of a stored Response.

Chat (1)

Tool Description
openai_chat Chat Completions endpoint. Prefer openai_responses for new models and built-in tools.

Images (2)

Tool Description
openai_image_generate Generate images. Default gpt-image-1.5 at quality=high, 1024x1536. Save to local path or return base64.
openai_image_edit Edit image(s) with optional mask. Reference-based edit via gpt-image-1.5.

Audio (3)

Tool Description
openai_tts Text-to-speech. Default gpt-4o-mini-tts, voice nova, mp3. Writes audio file to save_to.
openai_transcribe Speech-to-text. Default gpt-4o-transcribe (json). Use whisper-1 for verbose_json + word/segment timestamps.
openai_translate_audio Translate audio into English (Whisper translation endpoint).

Files (5)

Tool Description
openai_file_upload Upload local file (up to 500 MB). Returns file_id for Responses/Chat/Assistants/Batch.
openai_file_list List uploaded files, optionally filtered by purpose.
openai_file_get Retrieve metadata for a single file.
openai_file_delete Delete an uploaded file. Gated by OPENAI_MCP_ALLOW_DESTRUCTIVE=1.
openai_file_content Download raw file content to a local path.

Batch (4)

Tool Description
openai_batch_create Create a batch job (50% cost, async). Supports Responses, Chat, Completions, Embeddings, Moderations, Images, Videos endpoints.
openai_batch_retrieve Retrieve a batch job by id.
openai_batch_cancel Cancel a batch job.
openai_batch_list List batch jobs.

Vector Stores (9)

Tool Description
openai_vector_store_create Create a vector store (used by file_search tool).
openai_vector_store_list List vector stores.
openai_vector_store_retrieve Retrieve a vector store.
openai_vector_store_delete Delete a vector store. Gated by OPENAI_MCP_ALLOW_DESTRUCTIVE=1.
openai_vector_store_file_add Attach an uploaded file to a vector store.
openai_vector_store_file_list List files attached to a vector store.
openai_vector_store_file_remove Detach a file. Gated by OPENAI_MCP_ALLOW_DESTRUCTIVE=1.
openai_vector_store_file_batch_create Bulk-attach multiple files in one batch.
openai_vector_store_search Search a vector store by query.

Fine-tuning (6)

Tool Description
openai_fine_tune_create Create a fine-tuning job from an uploaded JSONL training file.
openai_fine_tune_retrieve Retrieve a fine-tuning job.
openai_fine_tune_list List fine-tuning jobs.
openai_fine_tune_cancel Cancel a fine-tuning job.
openai_fine_tune_events List events (progress stream) for a job.
openai_fine_tune_list_checkpoints List intermediate checkpoint model ids.

Large Uploads (2)

Tool Description
openai_upload_large_file Multipart upload up to 8 GB. Streams 64 MB parts with incremental MD5.
openai_upload_cancel Cancel an in-progress Upload.

Embeddings, Moderation, Models, Health (5)

Tool Description
openai_embed Create embeddings. Default text-embedding-3-large at 3072 dims.
openai_moderation Run a moderation check via omni-moderation-latest (multimodal).
openai_list_models List all models on the account (dynamic, always current).
openai_model_retrieve Retrieve metadata for a single model.
openai_ping Health check — loads the key and returns redacted fingerprint + visibility probe.

Total: 42 tools.

Environment variables

Variable Purpose Default
OPENAI_API_KEY Primary API key source.
OPENAI_API_KEY_FILE Read key from a file path (~ expanded).
OPENAI_ORG_ID Organization id for the OpenAI client.
OPENAI_PROJECT_ID Project id for the OpenAI client.
OPENAI_BASE_URL Override API base URL (proxies, Azure-compatible gateways). https://api.openai.com/v1
OPENAI_MCP_GCP_PROJECT GCP project for Secret Manager fallback.
OPENAI_MCP_GCP_SECRET Secret name for Secret Manager fallback. openai-api-key
OPENAI_MCP_GCLOUD_BIN Absolute path to the gcloud binary.
OPENAI_MCP_ALLOW_PATHS Colon-separated paths to ALLOW (overrides deny-list).
OPENAI_MCP_DENY_PATHS Colon-separated extra paths to DENY.
OPENAI_MCP_MAX_FILE_BYTES Max bytes for inline file reads (images, attachments). 52428800 (50 MB)
OPENAI_MCP_MAX_AUDIO_BYTES Max bytes for audio transcription uploads. 209715200 (200 MB)
OPENAI_MCP_ALLOW_HOSTED_TOOLS 1 to permit hosted mcp/shell/computer_use tool types. 0
OPENAI_MCP_ALLOW_DESTRUCTIVE 1 to permit file/response/vector-store deletion tools. 0
OPENAI_MCP_TIMEOUT_MS Per-request timeout for the OpenAI SDK. 600000 (10 min)

Security model

This server is designed to be safe by default when connected to an LLM that can issue arbitrary tool calls on your behalf.

Path deny-list

All tools that read or write local paths (image_paths, file_path, save_to, etc.) route through a resolver that:

  • Expands ~ to the current user's home.
  • Calls realpathSync so symlink escapes don't bypass the deny-list.
  • Blocks the following by default (targets a prompt-injected LLM exfiltrating secrets):
    • ~/.ssh, ~/.gnupg, ~/.aws, ~/.config/gcloud, ~/.docker, ~/.kube
    • ~/.claude, ~/.claude.json
    • ~/.bash_history, ~/.zsh_history, ~/.netrc, ~/.npmrc, ~/.pypirc, ~/.git-credentials
    • /etc/shadow, /etc/gshadow, /proc
    • Any path you add via OPENAI_MCP_DENY_PATHS
  • Allow-list is additive: anything under OPENAI_MCP_ALLOW_PATHS is permitted even if it would otherwise be denied.

Write-basename deny

Even outside the deny-list, writes to these shell-init / auth basenames are blocked:

.bashrc  .bash_profile  .bash_login  .profile  .zshrc  .zprofile  .zlogin
.zshenv  .kshrc  .cshrc  .tcshrc  .inputrc  .termux.properties
authorized_keys  known_hosts  .vimrc  .viminfo  .config

This prevents an LLM from overwriting your shell rc files with prompt-injected content, regardless of where in the filesystem the file lives.

Hosted-tool block

The Responses API lets you pass hosted tool types like mcp, shell, and computer_use. These let remote infrastructure (OpenAI's sandbox, or a third-party MCP endpoint) execute actions. We block these by default:

  • mcp — would let a prompt-injected LLM register a malicious MCP server mid-call.
  • shell — arbitrary remote shell execution.
  • computer_use — screen control.

Set OPENAI_MCP_ALLOW_HOSTED_TOOLS=1 only when you explicitly trust the tool payload source.

Destructive-action gate

Deletion tools (openai_file_delete, openai_response_delete, openai_vector_store_delete, openai_vector_store_file_remove) are disabled unless OPENAI_MCP_ALLOW_DESTRUCTIVE=1. This prevents a prompt-injected "please clean up your files" instruction from wiping your dataset, cached responses, or vector store corpus.

401 cache invalidation

The OpenAI client is cached across calls for speed. On any HTTP 401, the cached client is invalidated so a rotated key takes effect immediately without restarting the server.

SSRF guard

image_urls are validated before being forwarded:

  • Only http: / https: schemes.
  • Rejects localhost, 127.0.0.1, 0.0.0.0, ::1, metadata.google.internal.
  • Rejects RFC1918 (10.x, 192.168.x, 172.16.x-172.31.x), link-local (169.254.x, fe80::), and unique-local (fc00::/7).

Prevents an LLM from coaxing the server into fetching cloud metadata or your internal network on its behalf.

Defaults

Knob Default
Text model gpt-5.4
reasoning_effort high
verbosity high
reasoning_summary auto
Image model gpt-image-1.5
Image size 1024x1536
Image quality high
TTS model gpt-4o-mini-tts
TTS voice nova
Transcription model gpt-4o-transcribe
Embedding model text-embedding-3-large @ 3072 dims
Moderation model omni-moderation-latest
Per-request timeout 10 minutes
Per-model max_output_tokens gpt-5.* 128K, o-series 100K, gpt-4.1* 32K, gpt-4o* 16K, gpt-4* 8K

Model availability varies by account and date. Run openai_list_models to see what your key actually has access to before wiring a default.

Examples

All examples show the JSON input the LLM passes to the tool.

1. Quick reasoning call

{
  "tool": "openai_responses",
  "input": {
    "input": "Explain the CAP theorem to a junior engineer in three paragraphs.",
    "reasoning_effort": "high"
  }
}

2. Analyze a local PDF

{
  "tool": "openai_responses",
  "input": {
    "input": "Summarize the key findings and list every statistical test used.",
    "file_paths": ["~/papers/clinical-trial.pdf"],
    "reasoning_effort": "high",
    "verbosity": "high"
  }
}

3. Generate an image to disk

{
  "tool": "openai_image_generate",
  "input": {
    "prompt": "A minimalist watercolor illustration of a lighthouse at dawn.",
    "size": "1024x1536",
    "quality": "high",
    "save_to": "~/images/lighthouse.png"
  }
}

4. Background reasoning + poll

Kick off a long job:

{
  "tool": "openai_responses",
  "input": {
    "input": "Produce a 20-page technical design doc for a multi-region Kafka deployment.",
    "reasoning_effort": "high",
    "background": true,
    "store": true
  }
}

Then poll:

{
  "tool": "openai_response_get",
  "input": { "response_id": "resp_abc123", "response_format": "text" }
}

5. Upload a large dataset and fine-tune

{
  "tool": "openai_upload_large_file",
  "input": {
    "path": "~/datasets/corpus.jsonl",
    "purpose": "fine-tune"
  }
}
{
  "tool": "openai_fine_tune_create",
  "input": {
    "model": "gpt-4.1-nano",
    "training_file": "file-xyz789",
    "suffix": "my-domain-v1",
    "method": { "type": "supervised" }
  }
}

6. Embed a batch of documents

{
  "tool": "openai_embed",
  "input": {
    "input": ["first doc", "second doc", "third doc"],
    "dimensions": 3072,
    "include_vectors": false
  }
}

Troubleshooting

"OpenAI API key not found"

None of the three resolution paths returned a key. Verify with:

echo "$OPENAI_API_KEY" | head -c 10
ls -la "$OPENAI_API_KEY_FILE"
gcloud secrets versions access latest --secret="$OPENAI_MCP_GCP_SECRET" --project="$OPENAI_MCP_GCP_PROJECT"

"Path is on the deny-list"

You're trying to read or write a protected location. Either move the file, or whitelist its parent directory:

export OPENAI_MCP_ALLOW_PATHS="/home/me/workdir:/tmp/safe"

"Hosted tool type ... is disabled by default"

You passed tools: [{type: "mcp"}] (or shell / computer_use). Set OPENAI_MCP_ALLOW_HOSTED_TOOLS=1 only if you trust the payload.

"Destructive actions disabled"

Set OPENAI_MCP_ALLOW_DESTRUCTIVE=1 to enable deletion tools.

"File is N bytes; exceeds ... cap"

Raise OPENAI_MCP_MAX_FILE_BYTES (inline attachments) or OPENAI_MCP_MAX_AUDIO_BYTES (transcription), or use openai_upload_large_file for files up to 8 GB.

status=failed in openai_responses output

The model returned an error state. The tool response is marked isError: true. Switch to response_format: "json" to see the full error payload, or call openai_response_get with the id.

HTTP 401 on every call

Your key is invalid or rotated. The server will re-load on next call once 401 is observed — you don't need to restart it.

Reasoning model ignores max_tokens

Reasoning models (gpt-5.*, o*) use max_completion_tokens, not max_tokens. The server's openai_chat tool routes this automatically based on the model id.

Contributing

Pull requests welcome.

  1. Fork the repo on GitHub.
  2. Create a branch: git checkout -b fix/my-issue.
  3. Syntax-check every file you touch: node --check tools/your_file.js.
  4. Manually smoke-test via an MCP client before pushing.
  5. Open a PR against main with a description of what changed and why.

When adding a tool, follow the existing pattern in tools/*.js:

  • Register via server.tool(name, description, zodSchema, handler).
  • Validate any tools/messages arrays through validateTools / validateInputMessages to keep the hosted-tool block in force.
  • Route writes through resolvePath(path, { forWrite: true }).
  • Use ok, fail, asJson from client.js for consistent response shape.

License

MIT. See LICENSE.

About

MCP server exposing the full OpenAI API (Responses, Chat, Images, Audio, Embed, Files, Batch, Vector Stores, Fine-tune, Uploads) — 42 tools for Claude Code, Cursor, and any MCP client.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages