Skip to main content
Glama
README.md
# openai-mcp-server

An [MCP](https://modelcontextprotocol.io) server that puts the OpenAI API into any MCP client — Claude Desktop, Claude Code, Cowork, Cursor, or anything else that speaks the protocol.

Nine tools: text generation, chat completions, model discovery, image generation and editing, transcription, speech synthesis, embeddings, and moderation.

## Why this exists

There is no official OpenAI plugin in the Claude plugin catalogue. This server is the equivalent, built as a normal open-source project you own and can extend.

## Tools

| Tool | What it does | Read-only |
| --- | --- | --- |
| `openai_generate_text` | Generate text via the Responses API — instructions, reasoning effort, forced JSON, response chaining | no |
| `openai_chat_completion` | Send an explicit message history via Chat Completions | no |
| `openai_list_models` | List the model IDs your key can use, filtered and paginated | yes |
| `openai_generate_image` | Create images from a prompt, written to disk | no |
| `openai_edit_image` | Edit or combine existing images, optionally with a mask | no |
| `openai_transcribe_audio` | Transcribe a local audio file | no |
| `openai_text_to_speech` | Synthesize speech to an audio file | no |
| `openai_create_embeddings` | Embed texts for semantic search, written to JSON | no |
| `openai_moderate_content` | Check text against OpenAI's moderation policy | yes |

Every tool takes `response_format: "markdown" | "json"` — markdown for reading, JSON for processing. All tools also return `structuredContent`, so clients that understand output schemas get typed data without parsing.

## Install

### As a Claude Desktop extension (easiest)

Download `openai-mcp-server-<version>.mcpb` from the [releases page](https://github.com/piorkowskim79/openai-mcp-server/releases), double-click it, and paste your API key into the field Claude Desktop shows. Nothing else to install — the bundle carries its dependencies and runs on Claude Desktop's own Node runtime, so the machine needs no Node, no toolchain and no hand-edited config file.

The same dialog also offers the output folder, the folders the server may read from, a default text model and an alternative API base URL. All of them are optional.

To build the bundle yourself:

```bash
npm install
npm run pack:mcpb     # writes build/openai-mcp-server-<version>.mcpb
```

### From source

For Claude Code, Cursor or any other MCP client:

```bash
git clone https://github.com/piorkowskim79/openai-mcp-server.git
cd openai-mcp-server
npm install
npm run build
```

Requires Node.js 20 or newer and an OpenAI API key with available quota.

Verify the build:

```bash
node dist/index.js --version   # prints 1.0.0
node dist/index.js --help      # lists all environment variables
```

## Configure your MCP client

Skip this section if you installed the `.mcpb` extension — Claude Desktop wires it up for you.

The server speaks MCP over **stdio**, so the client launches it as a subprocess.

### Claude Desktop

Edit `claude_desktop_config.json`:

- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`

```json
{
  "mcpServers": {
    "openai": {
      "command": "node",
      "args": ["/absolute/path/to/openai-mcp-server/dist/index.js"],
      "env": {
        "OPENAI_API_KEY": "sk-proj-...",
        "OPENAI_MCP_OUTPUT_DIR": "/Users/you/openai-mcp-output"
      }
    }
  }
}
```

Restart Claude Desktop afterwards.

### Claude Code

```bash
claude mcp add openai \
  --env OPENAI_API_KEY=sk-proj-... \
  -- node /absolute/path/to/openai-mcp-server/dist/index.js
```

### Any other MCP client

Point it at `node /absolute/path/to/dist/index.js` with `OPENAI_API_KEY` in the environment.

## Configuration

Only `OPENAI_API_KEY` is required. See `.env.example` for a copyable template.

| Variable | Default | Purpose |
| --- | --- | --- |
| `OPENAI_API_KEY` | — | **Required.** Your OpenAI API key |
| `OPENAI_BASE_URL` | OpenAI's default | Alternative endpoint (Azure, gateway, proxy) |
| `OPENAI_ORG_ID` | — | Organization ID |
| `OPENAI_PROJECT_ID` | — | Project ID |
| `OPENAI_MCP_OUTPUT_DIR` | `<tmp>/openai-mcp` | Where generated files are written |
| `OPENAI_MCP_ALLOWED_DIRS` | output dir only | Colon-separated absolute dirs the server may **read** from |
| `OPENAI_MCP_TIMEOUT_MS` | `120000` | Per-request timeout |
| `OPENAI_MCP_MAX_RETRIES` | `2` | Retries for transient failures |
| `OPENAI_DEFAULT_TEXT_MODEL` | `gpt-5.6-terra` | Default text model |
| `OPENAI_DEFAULT_IMAGE_MODEL` | `gpt-image-2` | Default image model |
| `OPENAI_DEFAULT_EMBEDDING_MODEL` | `text-embedding-3-small` | Default embedding model |
| `OPENAI_DEFAULT_TRANSCRIPTION_MODEL` | `gpt-transcribe` | Default transcription model |
| `OPENAI_DEFAULT_SPEECH_MODEL` | `gpt-4o-mini-tts` | Default speech model |
| `OPENAI_DEFAULT_MODERATION_MODEL` | `omni-moderation-latest` | Default moderation model |

Any **positional argument** is also treated as a readable directory and merged into `OPENAI_MCP_ALLOWED_DIRS`:

```bash
node dist/index.js /Users/you/Documents/audio /Users/you/Pictures
```

This exists because a bundle manifest expands a multi-value directory setting into several argv entries; a single colon-separated environment variable cannot express that list unambiguously. Arguments must be absolute paths.

**Model IDs change.** OpenAI adds, renames and retires models, and access differs per project. Every default is overridable, and `openai_list_models` reports what your key can actually reach — if a call fails with "model not found", start there.

## Security model

Two deliberate constraints:

**The filesystem is sandboxed.** Tools that read local files (`openai_edit_image`, `openai_transcribe_audio`) accept only absolute paths inside `OPENAI_MCP_ALLOWED_DIRS`. Paths are canonicalised with `realpath` before the check, so symlinks and `../` traversal cannot escape. The output directory is always allowed; nothing else is, until you add it. Keep that list narrow.

**Binary output never enters the conversation.** Images, audio and embedding vectors are written to disk and only their paths are returned. A single base64 PNG or a 3072-float vector would otherwise flood the model's context window.

The API key is read from the environment only — it never appears in a tool argument, a log line, or an error message.

## Examples

Ask your MCP client in plain language; it picks the tool.

> "Use the OpenAI server to summarise this text in three sentences."

→ `openai_generate_text`

> "Which OpenAI embedding models can I use?"

→ `openai_list_models` with `filter="embedding"`

> "Generate a transparent PNG logo of a blue fox."

→ `openai_generate_image` with `background="transparent"`

> "Transcribe ~/Documents/audio/interview.m4a in German."

→ `openai_transcribe_audio` with `language="de"` — requires that directory in `OPENAI_MCP_ALLOWED_DIRS`

> "Embed these 40 product descriptions so I can cluster them."

→ `openai_create_embeddings`, then read the JSON file it reports

## Development

```bash
npm run dev        # watch mode via tsx
npm run typecheck  # tsc --noEmit, strict
npm test           # unit tests, no network calls
npm run build      # compile to dist/
npm run pack:mcpb  # build the Claude Desktop extension bundle
```

The test suite covers configuration parsing, the filesystem sandbox (including symlink escape and traversal), error formatting and response shaping. It never contacts the OpenAI API.

### Project layout

```
manifest.json         Claude Desktop extension manifest (tools, user config)
scripts/
└── pack-mcpb.sh      builds the .mcpb bundle
src/
├── index.ts          entry point, server assembly, CLI flags
├── config.ts         environment parsing and validation
├── client.ts         OpenAI client construction
├── constants.ts      defaults, limits, response formats
├── errors.ts         API errors → actionable agent messages
├── files.ts          sandboxed read/write
├── format.ts         tool result shaping, character limit
└── tools/
    ├── text.ts       generate_text, chat_completion
    ├── models.ts     list_models
    ├── images.ts     generate_image, edit_image
    ├── audio.ts      transcribe_audio, text_to_speech
    └── analysis.ts   create_embeddings, moderate_content
```

### Adding a tool

1. Write a Zod schema with `.strict()` and a `.describe()` on every field.
2. Register it with `server.registerTool(name, config, handler)` — include `title`, `description`, `inputSchema`, `outputSchema` and `annotations`.
3. Return via `toolResult(...)` so markdown/JSON handling and the character limit stay consistent; catch errors with `errorResult(...)`.
4. Add the registration call in `src/index.ts` and a test in `test/`.

## Troubleshooting

| Symptom | Cause |
| --- | --- |
| Client shows no tools | Wrong path in the config, or the project was not built (`npm run build`) |
| `Configuration error: OPENAI_API_KEY is not set` (exit 78) | The key is missing from the client's `env` block |
| `Error: Access to ... is not permitted` | The path is outside `OPENAI_MCP_ALLOWED_DIRS` |
| `Error: Not found` on a generation | The model ID does not exist for your key — run `openai_list_models` |
| `Error: Rate limit or quota exceeded` | Retry later, or check billing on the project |

The server logs to stderr; stdout carries the JSON-RPC stream and must stay clean.

## License

MIT — see [LICENSE](LICENSE).

TDQS

A4.4/5.0

Scored across 9 tools

Disambiguation4/5

Each tool maps to a distinct OpenAI capability (text, chat history, images, audio, embeddings, moderation, model discovery). openai_generate_text and openai_chat_completion are the only potentially confusable pair, but their descriptions clearly separate single-prompt/chaining from explicit message histories.

Naming Consistency4/5

All tools share an openai_ prefix and snake_case, with mostly verb_noun names like generate_text, edit_image, list_models. openai_chat_completion and openai_text_to_speech break the verb_noun pattern slightly because they mirror API endpoint names, but the convention remains predictable.

Tool Count5/5

9 tools is appropriate for an OpenAI API surface: one tool per major modality (text, image, audio, embeddings, moderation) plus model discovery. No tool feels redundant or missing at the count level.

Completeness4/5

The set covers text generation, chat completions, image generation/editing, transcription, speech synthesis, embeddings, and moderation, which are the core OpenAI workflows. Minor gaps exist—notably no vision/analysis of image inputs and no fine-tuning/batch management—but agents can accomplish typical tasks without dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues