Skip to main content

specmcp

Convert any OpenAPI spec into a working MCP server — no code required.

specmcp runs a load → normalize → simplify → expose pipeline at startup and then answers MCP tools/list and tools/call requests by proxying the real upstream API. Give it a spec URL or file and a config file, and your LLM can call the API immediately.

specmcp serve --spec https://api.example.com/openapi.json

Install

pip install mcp-from-spec

Requires Python 3.10+.


Quickstart

1. Scaffold a config file

specmcp init --spec https://petstore3.swagger.io/api/v3/openapi.json

This writes mcp.config.yaml and .env.example to the current directory.

2. Start the server

specmcp serve --config mcp.config.yaml

The server runs over stdio by default, which is what Claude Desktop and most MCP clients expect. You should see something like:

specmcp serving 19 tools from https://petstore3.swagger.io/api/v3/openapi.json [transport=stdio]

3. Point your MCP client at it

In Claude Desktop's claude_desktop_config.json:

{
  "mcpServers": {
    "petstore": {
      "command": "specmcp",
      "args": ["serve", "--config", "/path/to/mcp.config.yaml"]
    }
  }
}

Config file reference

mcp.config.yaml controls everything: which spec to load, which operations to expose, auth credentials, timeouts, and more.

version: "1"

spec:
  source: ./openapi.json          # path or URL

auth:
  myKey:
    type: apiKey
    in: header                    # header | query | cookie
    name: X-API-Key
    value_from: env(MY_API_KEY)   # env(VAR) or literal(value)

server:
  base_url_override: https://api.example.com   # override spec's servers[]
  include_operations:            # allowlist by operationId
    - listPets
    - createPet
  exclude_tags:
    - admin

dispatch:
  default_timeout_seconds: 30
  response_size_limit_bytes: 1048576   # 1 MiB
  text_truncate_bytes: 65536           # 64 KiB

simplify:
  truncate_description_chars: 400
  drop_spec_metadata: true

Auth types

API key

auth:
  myKey:
    type: apiKey
    in: header          # header | query | cookie
    name: X-API-Key
    value_from: env(MY_API_KEY)

Bearer token

auth:
  myToken:
    type: bearer
    value_from: env(MY_BEARER_TOKEN)

OAuth 2.0 — Client Credentials

specmcp fetches a short-lived access token at the token_url and refreshes it automatically before expiry. No user interaction required.

auth:
  myApi:
    type: oauth2_client_credentials
    token_url: https://auth.example.com/oauth/token
    client_id_from: env(MY_CLIENT_ID)
    client_secret_from: env(MY_CLIENT_SECRET)
    scopes:
      - read
      - write

OAuth 2.0 — Authorization Code + PKCE

For APIs that require user-delegated OAuth (GitHub, Google, Salesforce, etc.). Requires --transport http so specmcp can receive the IdP callback.

auth:
  myOAuth:
    type: oauth2_authorization_code
    authorization_url: https://auth.example.com/oauth/authorize
    token_url: https://auth.example.com/oauth/token
    redirect_uri: http://localhost:8765/auth/callback
    client_id_from: env(MY_CLIENT_ID)
    client_secret_from: env(MY_CLIENT_SECRET)
    scopes:
      - read
      - write

See OAuth 2.0 Authorization Code flow below for the full walkthrough.


CLI reference

specmcp serve [OPTIONS]
Flag Default Description
--spec / -s (from config) Path or URL to the OpenAPI spec
--config / -c mcp.config.yaml Config file path
--transport / -t stdio stdio or http
--watch / -w false Hot-reload spec/config on file change
--verbose / -v false DEBUG-level logging
--management-port 8766 Port for the management listener (HTTP transport only)
--management-bind loopback loopback or all
--token-store memory memory or sqlite (encrypted at rest)
--token-store-path ~/.specmcp/tokens.db SQLite database path
--token-store-key-env SPECMCP_TOKEN_KEY Env var holding the encryption key

Other commands:

specmcp init      # scaffold mcp.config.yaml + .env.example
specmcp inspect   # list all exposed tools without starting the server
specmcp validate  # lint the spec and config and exit with a status code

HTTP transport

Start the server over HTTP/SSE instead of stdio:

specmcp serve --config mcp.config.yaml --transport http

The MCP server listens on http://127.0.0.1:8765 by default.

transport:
  http:
    host: "127.0.0.1"
    port: 8765

Use HTTP transport when you need:

  • Multiple simultaneous MCP clients (one SSE connection each)
  • OAuth 2.0 Authorization Code flows (requires an HTTP callback endpoint)
  • Per-session auth tokens

OAuth 2.0 Authorization Code flow

When oauth2_authorization_code is configured and the server is running with --transport http, the flow works like this:

  1. LLM calls a tool — specmcp checks whether the session has a valid token.
  2. No token — specmcp returns an AuthRequired error containing a login_url.
  3. Client presents the URL — the user opens the URL in a browser.
  4. User authenticates — the IdP redirects to specmcp's /auth/callback.
  5. Token stored — specmcp exchanges the code for tokens and stores them.
  6. LLM retries — the tool call proceeds with the access token in the Authorization header.

Subsequent calls use the stored token (silently refreshed before expiry).

Start the HTTP server

specmcp serve \
  --config mcp.config.yaml \
  --transport http \
  --token-store sqlite \
  --token-store-key-env SPECMCP_TOKEN_KEY

Set the encryption key for the SQLite token store:

export SPECMCP_TOKEN_KEY="$(openssl rand -hex 32)"

OAuth endpoints

Route Purpose
GET /auth/login?nonce=<token> Redirect to the IdP authorization page
GET /auth/callback?code=&state= Exchange the authorization code for tokens
GET /auth/status?session=<id> Poll {"authenticated": true|false}
DELETE /auth/session/<id> Revoke a session's tokens (management endpoint)

The management endpoint (DELETE /auth/session/<id>) runs on a dedicated port (default 8766) bound to loopback only. Set --management-bind all and management.management_token_from in config to expose it externally with Bearer auth.


Hot-reload (--watch)

specmcp serve --config mcp.config.yaml --watch

Watches the spec and config files for changes and atomically reloads the ToolRegistry without dropping the stdio connection. Useful when iterating on a spec. Requires watchfiles:

pip install watchfiles

Note: changes to the auth: section of mcp.config.yaml are not picked up on hot-reload. A full restart is required for auth changes.


Examples

The examples/ directory contains ready-to-run configs:

Example Description
examples/petstore/ Swagger Petstore — basic quickstart
examples/github/ GitHub REST API (bearer token)
examples/stripe/ Stripe API (API key)
examples/oauth2-example/ OAuth 2.0 Authorization Code + PKCE

Run any example:

export GITHUB_TOKEN=ghp_...
specmcp serve --config examples/github/mcp.config.yaml

How it works

Point specmcp at any OpenAPI spec and it instantly becomes an MCP server. Every operation in the spec becomes a callable tool — with a name, description, and typed arguments that the LLM can use directly.

specmcp handles all the translation automatically: it reads the spec, builds the tools, injects your credentials, and proxies calls to the real upstream API. No code generation, no wrappers to maintain. When the spec changes, restart specmcp (or use --watch) and the tools update automatically.


License

Apache 2.0

Metadata

Release files for mcp-from-spec 1.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mcp-from-spec 1.4.1
File Size Uploaded
mcp_from_spec-1.4.1.tar.gz 150.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mcp-from-spec 1.4.1
File Interpreter ABI Platform
mcp_from_spec-1.4.1-py3-none-any.whl Python 3 none any Details

Total release size: 240.8 kB

Release files / mcp_from_spec-1.4.1.tar.gz

Download URL mcp_from_spec-1.4.1.tar.gz
Size 150.6 kB
Tags Source
SHA-256 checksum
How to use checksums
a117c0644ff158b05fce35977efcf123389635f6abb2f3a6295f524b92f3e2d6
BLAKE2b-256 checksum
How to use checksums
d390d7a50492656ee80901573eefbc3fdc452e49f8a9053620494d9c26dfbdfe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 3, 2026.

Transparency log

Release files / mcp_from_spec-1.4.1-py3-none-any.whl

Download URL mcp_from_spec-1.4.1-py3-none-any.whl
Size 90.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
11fa033b2ff57c56d9f7d2ff7bc75bbcd6b20f5c6b4c8d62b031238da47fb7e9
BLAKE2b-256 checksum
How to use checksums
48e59b1ae3e8c6e8a8062f20ac8e2db76acc82bd6bda952b96cc4e436d00c28a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 3, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.4.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page