MM

matthewhand/mcp-openapi-proxy

API development
153 stars 0 forks 품질 80 트렌드 80

is a Python package that implements a Model Context Protocol (MCP) server, designed to dynamically expose REST APIs—defined by OpenAPI specifications—as MCP tools.

개요

is a Python package that implements a Model Context Protocol (MCP) server, designed to dynamically expose REST APIs—defined by OpenAPI specifications—as MCP tools.

README

mcp-openapi-proxy

mcp-openapi-proxy is a Python package that implements a Model Context Protocol (MCP) server, designed to dynamically expose REST APIs—defined by OpenAPI specifications—as MCP tools. This facilitates seamless integration of OpenAPI-described APIs into MCP-based workflows.

What’s New in 0.2.0

Works with every modern MCP-enabled client we tested. Strict MCP clients can now discover and call tools — the low-level server advertises correct capabilities and no longer crashes during resource/prompt discovery, and a slow spec download no longer crash-loops short-timeout clients. Verified live against the full list of mainstream agent CLIs:

  • Codex, Gemini, Qwen, Kilocode, opencode — native tool calls over stdio
  • Vibe — native discovery and read calls (writes were CLI-flaky, not a proxy issue)
  • Letta — Cloud (via a remote streamable-HTTP MCP URL) and self-hosted (via stdio)

See the client matrix for attach mechanisms, models, and exact results.

📄 Full write-up: Verification case study — what the proxy is, the API + client matrices, and every defect found & fixed.

Prompts and resources are real now — including custom resources. Both MCP surfaces are functional and tested: the summarize_spec / whimsical_blog prompts and the spec_file resource, plus a new ADDITIONAL_RESOURCES env var that serves your own use-case documents (e.g. a NetBox naming policy or an Asana project-layout guide) as MCP resources — see examples/resources/.

Bug fixes (every one live-verified):

  • MCP client discovery: empty capability set + a crash in resource discovery left strict clients seeing zero tools (#23) — fixed, with a full stdio-handshake test harness.
  • IGNORE_SSL_TOOLS was ignored by the low-level dispatcher (#14) — fixed (original patch by @robbycochran, #15).
  • Server crash-loop when a slow spec fetch outran a client’s connect timeout (#28) — handshake now answers immediately, spec loads lazily, closed streams exit cleanly.
  • API_AUTH_TYPE custom schemes (e.g. NetBox Token) sent no auth header at all (#24) — fixed.
  • TOOL_WHITELIST never matched Slack-style dot paths like /users.list (#27) — fixed.
  • TOOL_NAME_MAX_LENGTH was not respected, and name-truncation collisions silently dropped tools (#11) — fixed.
  • Array parameters were emitted without items, which the OpenAI API rejects (#16) — fixed.
  • EXTRA_HEADERS now accepts a JSON array and literal \n separators, not just real newlines (#17).
  • Dead Render spec URL (#26) and incomplete ElevenLabs example (#29) — fixed; the GetZep example is documented for self-hosted Zep CE since the hosted endpoint now 401s (#38).
  • Added a Dockerfile + glama.json for the Glama listing (#13); collapsible README examples + a verified-client/API matrix (#35).

Full environment-variable reference is in Environment Variables.

Table of Contents

Overview

The package offers two operational modes:

  • Low-Level Mode (Default): Dynamically registers tools corresponding to all valid API endpoints specified in an OpenAPI document (e.g. /chat/completions becomes chat_completions()).
  • FastMCP Mode (Simple Mode): Provides a streamlined approach by exposing a predefined set of tools (e.g. list_functions() and call_function()) based on static configurations.

Features

  • Dynamic Tool Generation: Automatically creates MCP tools from OpenAPI endpoint definitions.
  • Simple Mode Option: Offers a static configuration alternative via FastMCP mode.
  • OpenAPI Specification Support: Compatible with OpenAPI v3 with potential support for v2.
  • Flexible Filtering: Allows endpoint filtering through whitelisting by paths or other criteria.
  • Payload Authentication: Supports custom authentication via JMESPath expressions (e.g. for APIs like Slack that expect tokens in the payload not the HTTP header).
  • Header Authentication: Uses Bearer by default for API_KEY in the Authorization header, customizable for APIs like Fly.io requiring Api-Key.
  • MCP Integration: Seamlessly integrates with MCP ecosystems for invoking REST APIs as tools.

Installation

Install the package directly from PyPI using the following command:

uvx mcp-openapi-proxy

MCP Ecosystem Integration

To incorporate mcp-openapi-proxy into your MCP ecosystem configure it within your mcpServers settings. Below is a generic example:

{
    "mcpServers": {
        "mcp-openapi-proxy": {
            "command": "uvx",
            "args": ["mcp-openapi-proxy"],
            "env": {
                "OPENAPI_SPEC_URL": "${OPENAPI_SPEC_URL}",
                "API_KEY": "${API_OPENAPI_KEY}"
            }
        }
    }
}

Refer to the Examples section below for practical configurations tailored to specific APIs.

Modes of Operation

FastMCP Mode (Simple Mode)

  • Enabled by: Setting the environment variable OPENAPI_SIMPLE_MODE=true.
  • Description: Exposes a fixed set of tools derived from specific OpenAPI endpoints as defined in the code.
  • Configuration: Relies on environment variables to specify tool behavior.

Low-Level Mode (Default)

  • Description: Automatically registers all valid API endpoints from the provided OpenAPI specification as individual tools.
  • Tool Naming: Derives tool names from normalized OpenAPI paths and methods.
  • Behavior: Generates tool descriptions from OpenAPI operation summaries and descriptions.

Environment Variables

  • OPENAPI_SPEC_URL: (Required) The URL to the OpenAPI specification JSON file (e.g. https://example.com/spec.json or file:///path/to/local/spec.json).
  • OPENAPI_SIMPLE_MODE: (Optional) Set to true to enable FastMCP mode.
  • TOOL_WHITELIST: (Optional) A comma-separated list of endpoint paths to expose as tools.
  • ADDITIONAL_RESOURCES: (Optional) Comma-separated name=/path/to/file entries served as extra MCP resources (use-case docs such as naming policies or layout conventions; see examples/resources/).
  • TOOL_NAME_PREFIX: (Optional) A prefix to prepend to all tool names.
  • API_KEY: (Optional) Authentication token for the API sent as Bearer in the Authorization header by default.
  • API_AUTH_TYPE: (Optional) Overrides the default Bearer Authorization scheme. api-key sends the key in the header named by API_AUTH_HEADER; any other value is used as a custom scheme prefix (e.g. Token for NetBox → Authorization: Token ).
  • STRIP_PARAM: (Optional) JMESPath expression to strip unwanted parameters (e.g. token for Slack).
  • DEBUG: (Optional) Enables verbose debug logging when set to “true”, “1”, or “yes”.
  • EXTRA_HEADERS: (Optional) One or more outgoing HTTP headers. Accepts a JSON array (["X-A: 1","X-B: 2"]), one Header: Value per line, or literal \n-separated entries (for configs that cannot embed newlines).
  • SERVER_URL_OVERRIDE: (Optional) Overrides the base URL from the OpenAPI specification when set, useful for custom deployments.
  • TOOL_NAME_MAX_LENGTH: (Optional) Truncates tool names to a max length.
  • Additional Variable: OPENAPI_SPEC_URL_ – a variant for unique per-test configurations (falls back to OPENAPI_SPEC_URL).
  • IGNORE_SSL_SPEC: (Optional) Set to true to disable SSL certificate verification when fetching the OpenAPI spec.
  • IGNORE_SSL_TOOLS: (Optional) Set to true to disable SSL certificate verification for API requests made by tools.
  • API_AUTH_HEADER: (Optional) Header name used when API_AUTH_TYPE=api-key (e.g. x-apikey for VirusTotal, xi-api-key for ElevenLabs). Defaults to Authorization.
  • OPENAPI_SPEC_FORMAT: (Optional) Set to yaml to parse file:// specs as YAML (remote specs auto-detect). Default json.
  • OPENAPI_SPEC_CACHE_TTL_SECONDS: (Optional) Live-first disk cache for remote specs: the cached copy is served only when the live fetch fails or stalls (and respawned servers fail fast to it). Default 86400; set 0 to disable.
  • ENABLE_TOOLS / ENABLE_PROMPTS / ENABLE_RESOURCES: (Optional) Feature gates for the three MCP surfaces in low-level mode; each defaults to enabled. Disabling a feature removes its handlers and its capability advertisement.
  • CAPABILITIES_TOOLS / CAPABILITIES_PROMPTS / CAPABILITIES_RESOURCES: (Optional) Advertise listChanged on the corresponding capability (for clients that key on it). Default false.

Verified Clients & Live Results (2026-06-12)

The example configurations below were exercised against the live APIs, and the proxy was attached to a range of agent CLIs over stdio MCP. Results from that verification run:

API example results

API example Tools Sample call proven Extra env needed
glama 6 get_v1_attributes none
apis.guru 7 get_metrics_json none
wolframalpha 2 get_v1_llm_api API_KEY
virustotal 4 IP report API_KEY + API_AUTH_TYPE=api-key + API_AUTH_HEADER=x-apikey
asana 73 (whitelist /workspaces,/projects,/tasks) created project + 11 tasks SERVER_URL_OVERRIDE + API_KEY
render 52 get_services API_KEY (NEW spec URL render-public-api-1.json)
notion 4–5 (whitelist /v1/users,/v1/search or /v1/pages) page create + title read-back SERVER_URL_OVERRIDE + EXTRA_HEADERS (Notion-Version) + API_KEY
elevenlabs 19 TTS mp3 generated SERVER_URL_OVERRIDE + API_AUTH_TYPE=api-key + API_AUTH_HEADER=xi-api-key
flyio 34–35 apps + machine health API_KEY
slack 7 (exact dot-path whitelist until #27 fix) auth.test + postMessage API_KEY
netbox 9 (whitelist /ipam/ip-addresses) IPAM write + read API_KEY + API_AUTH_TYPE=Token
homeassistant 21 get_config (200) + call_service (light.turn_on, 200) SERVER_URL_OVERRIDE + API_KEY (${HA_TOKEN}, sent as Bearer)

Client matrix

Agent CLI Model used (live test) MCP attach mechanism Tool calls Prompts/Resources surfaced to model?
opencode (CLI default) ~/.config/opencode/opencode.json mcp ✅ native prompts: ✅ (slash) · resources: ✅ — most complete ‖
Codex gpt-5-codex (OpenAI API) codex exec -c mcp_servers.* ✅ native prompts: ❌ low-level · ✅ fastmcp (via call_functionget_prompt) · resources: ✅ (read_mcp_resource) ‖
Kilocode kilo-auto/free global settings/mcp_settings.json ✅ native prompts: ❌ (no prompt mechanism) · resources: ✅ (access_mcp_resource) ‖
Qwen agent group via local LiteLLM gateway project .qwen/settings.json ✅ native (live invoke auth-blocked) prompts: ✅ (slash /summarize_spec) · resources: ❌ (no client support) ‖
Gemini Google OAuth free tier (CLI default model) project .gemini/settings.json mcpServers ✅ native prompts: interactive slash only · resources: interactive @ only (neither reaches the model headless) ‖
Vibe mistral-medium-3.5 ~/.vibe/config.toml [[mcp_servers]] ✅ discovery + reads prompts: ❌ · resources: ❌ (tools-only client) ‖
agy ❌ headless cannot enable MCP n/a
letta (cloud / self-hosted) Letta Cloud / PUT /v1/tools/mcp/servers streamable-HTTP / stdio ✅ (per prior sweep) unknown — needs a running Letta server to test ‡

How to read the prompts/resources column. MCP has three surfaces — tools, prompts, resources. mcp-openapi-proxy serves all three, advertised by default since 0.3.0. Whether they reach the model is up to the client, and that varies:

  • ‖ re-verified 2026-06-15 against the published 0.3.3 release with no flags set (validating the default-on advertising), driving each real client binary, in both server modes (low-level and FastMCP simple). Per-client results were the same across modes except where noted.
  • Tools work on every client tested. Prompts→model: opencode & Qwen (slash commands); Gemini interactive-only. Resources→model: opencode, Codex, Kilocode. opencode is the only client that surfaces all three in any mode.
  • FastMCP simple mode exception: a client with no native prompt surface can still reach prompts through the static call_functionget_prompt indirection. Observed with Codex (prompts ❌ in low-level, ✅ in FastMCP simple mode). Vibe stays tools-only regardless of mode.
  • ‡ unknown — Letta can’t be exercised without standing up a Letta server + model; left untested rather than guessed.
  • Every cell on the proxy side was confirmed via a raw stdio handshake (initialize advertises tools+prompts+resources; prompts/get and resources/read return content). The remaining ❌ are client-side gaps, not proxy limitations.

(All pre-0.3.0 prompt/resource findings were voided — they were measured while advertising defaulted off, so they reflected the server default, not the clients.)

Minimal sanitized configs per client (the no-auth Glama spec is used as the smallest working example; substitute your own spec URL and $YOUR_KEY as needed):

agy (headless) and letta cloud could not attach a stdio MCP server at all, so no config snippet applies: agy provides no way to enable MCP in headless mode, and letta cloud only accepts remote MCP servers.

Tips

  • Big specs need TOOL_WHITELIST. Large APIs (Asana, Render, Fly.io, Slack, NetBox) expose dozens of endpoints; whitelist the paths you need to keep the tool count manageable for clients.
  • Dot-style paths need exact whitelist entries for now. Slack-style paths like /chat.postMessage are not matched by prefix whitelisting — list each path exactly (issue #27 / PR #32).
  • Slow remote specs can crash-loop short-timeout clients. If a client kills the server before a large spec finishes downloading, fetch the spec once and point OPENAPI_SPEC_URL at a local file:// copy (issue #28).
  • Custom auth schemes are handled via API_AUTH_TYPE (PR #25), e.g. Token for NetBox, or api-key with API_AUTH_HEADER for Virustotal/ElevenLabs-style header keys.

Examples

For testing you can run the uvx command as demonstrated in the examples then interact with the MCP server via JSON-RPC messages to list tools and resources. See the “JSON-RPC Testing” section below.

Each example below is collapsed — click to expand.

Troubleshooting

JSON-RPC Testing

For alternative testing, you can interact with the MCP server via JSON-RPC. After starting the server, paste the following initialization message:

{"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"claude-ai","version":"0.1.0"}},"jsonrpc":"2.0","id":0}

Expected response:

{"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2024-11-05","capabilities":{"experimental":{},"prompts":{"listChanged":false},"resources":{"subscribe":false,"listChanged":false},"tools":{"listChanged":false}},"serverInfo":{"name":"sqlite","version":"0.1.0"}}}

Then paste these follow-up messages:

{"method":"notifications/initialized","jsonrpc":"2.0"}
{"method":"resources/list","params":{},"jsonrpc":"2.0","id":1}
{"method":"tools/list","params":{},"jsonrpc":"2.0","id":2}
  • Missing OPENAPI_SPEC_URL: Ensure it’s set to a valid OpenAPI JSON URL or local file path.
  • Invalid Specification: Verify the OpenAPI document is standard-compliant.
  • Tool Filtering Issues: Check TOOL_WHITELIST matches desired endpoints.
  • Authentication Errors: Confirm API_KEY and API_AUTH_TYPE are correct.
  • Logging: Set DEBUG=true for detailed output to stderr.
  • Test Server: Run directly:
uvx mcp-openapi-proxy

License

MIT License

View this README on GitHub

설치

uvx mcp-openapi-proxy

설정

{ "mcpServers": { "mcp-openapi-proxy": { "command": "uvx", "args": ["mcp-openapi-proxy"], "env": { "OPENAPI_SPEC_URL": "${OPENAPI_SPEC_URL}", "API_KEY": "${API_OPENAPI_KEY}" } } } }