Skip to main content
Glama

simple-mcp

Turn any API into a curated MCP server from a single config file.

Point it at an API description, and it exposes that API to any MCP client (Claude Desktop, MCP Inspector, IDEs) as a set of tools. Unlike a 1:1 endpoint dump, simple-mcp curates: it filters to the operations you want, writes structured tool descriptions, and — for large APIs — switches to on-demand tool discovery so it doesn't flood the model's context.

Status: MVP. REST (OpenAPI 3.0/3.1) is fully supported. GraphQL and gRPC are architected for but not yet implemented (the adapter seam exists; the adapters throw "not yet implemented"). LLM-generated descriptions are stubbed — see Describe modes.

Why curation matters

Naively turning every API endpoint into an MCP tool breaks down fast: LLM tool-selection degrades once a few dozen tools are in context, and every tool definition costs tokens on every turn. simple-mcp addresses this directly:

  • Filter to an intentional surface (default: nothing is exposed unless you include it).

  • Describe tools with a structured template (Purpose / Guidelines / Limitations / Parameters).

  • Expose them statically for small APIs, or dynamically (a single search_tools meta-tool that loads real tools on demand) for large ones — chosen automatically.

Related MCP server: mcp-api-gateway

Quick start

npm install
npm run build

# Run against the bundled petstore example (no auth needed):
node dist/index.js simple-mcp.example.yaml
# or, once published:  npx simple-mcp simple-mcp.example.yaml

The server speaks MCP over stdio by default. To try it interactively, point the MCP Inspector at that command.

Use it from Claude Desktop

Add to your claude_desktop_config.json:

{
  "mcpServers": {
    "petstore": {
      "command": "node",
      "args": ["/absolute/path/to/simple-mcp/dist/index.js", "/absolute/path/to/simple-mcp.example.yaml"]
    }
  }
}

Configuration

A single YAML file describes the whole server. Full example (simple-mcp.example.yaml):

server:
  name: petstore-mcp
  transport: [stdio]          # stdio and/or http

source:
  protocol: rest              # rest (GraphQL/gRPC not yet implemented)
  spec: https://petstore3.swagger.io/api/v3/openapi.json   # URL or local path
  baseUrl: https://petstore3.swagger.io/api/v3             # overrides the spec's server URL

auth:
  type: none                  # none | bearer | apiKey | basic | oauth2

curation:
  defaultInclude: false       # if false, only `include`d operations are exposed
  include:
    - "getPetById"            # match operationId (glob supported: "get*", "pets.*")
    - "findPetsByStatus"
  exclude: []
  describe:
    mode: deterministic       # deterministic | llm
  exposure: auto              # auto | static | dynamic
  tools: []                   # optional task-oriented consolidation (see below)

server

Key

Meaning

name

Server name advertised to the MCP client.

transport

Array of stdio and/or http. http uses Streamable HTTP; set PORT (default 3000).

source

Key

Meaning

protocol

rest today. graphql / grpc reserved.

spec

OpenAPI document — remote URL or local file path. $refs are bundled/dereferenced automatically.

baseUrl

Base URL for live calls. Recommended — overrides the spec's servers entry. If omitted, a relative server URL in the spec (e.g. /api/v3) is resolved against the spec URL.

auth

Secrets come from environment variables via ${VAR} interpolation — never hardcode them in the file.

type

Fields

Sent as

none

bearer

token

Authorization: Bearer <token>

apiKey

token + (headerName or queryParam)

header or query param

basic

username, password

Authorization: Basic <base64>

oauth2

token

Authorization: Bearer <token>

auth:
  type: bearer
  token: ${ACME_TOKEN}        # read from the environment at startup

Unset ${VAR} in the auth block is a hard error (so a missing secret fails loudly rather than sending unauthenticated requests). Elsewhere, an unresolved ${...} is left as a literal.

curation

Key

Meaning

defaultInclude

false (default): expose only matched include operations. true: expose everything except exclude.

include / exclude

Glob patterns matched against operationId, tags, and path. exclude wins over include.

describe.mode

deterministic (default) or llm (see below).

exposure

auto (default): dynamic when >30 tools, else static. Or force static / dynamic.

tools

Task-oriented consolidation: expose one named tool backed by an ordered sequence of operations.

Exposure strategies

  • static — every curated tool is registered up front. Best for small, focused APIs.

  • dynamic — only a search_tools tool is registered; the client searches by keyword, and matching tools are registered on demand. Keeps context small for large APIs.

  • auto — picks dynamic above 30 tools, static otherwise.

Describe modes

  • deterministic (default) — builds a structured description (Purpose, Guidelines, Limitations, Parameters, …) from the spec's own metadata. No API key needed.

  • llm — *stubbed._ Intended to synthesize richer descriptions via Claude, cached to disk. Currently, if selected without @anthropic-ai/sdk + ANTHROPIC_API_KEY, it prints a warning and falls back to deterministic.

Task-oriented tools

Instead of exposing findAvailability and createEvent separately, expose one intent-shaped tool:

curation:
  tools:
    - name: schedule_event
      steps: [findAvailability, createEvent]

Verified against real APIs

The REST adapter is validated end-to-end against public specs (scripts/validate-realworld.ts):

API

Operations

Exposure (auto)

Introspect

Swagger Petstore v3

19

static

~1.5s

GitHub REST API

1,194

dynamic

~1.5s

Stripe API

587

dynamic

~2.7s

All three introspect cleanly, and a live findPetsByStatus call against the petstore server round-trips end-to-end (the relative servers: [{url: /api/v3}] in its spec is resolved to an absolute URL automatically). Large APIs like GitHub and Stripe cross the 30-tool threshold and switch to dynamic exposure, so the client sees a single search_tools entry instead of ~1,000 tool definitions.

Re-run it yourself: node --import tsx scripts/validate-realworld.ts.

Security

HTTP transport is local-by-default and optional token auth protects networked MCP access. Outbound calls are restricted to public destinations unless you opt in.

Env var

Default

Meaning

MCP_HTTP_HOST

127.0.0.1

Bind address for transport: [http]. Set 0.0.0.0 only if you intentionally expose the port.

MCP_HTTP_TOKEN

(unset)

When set, require Authorization: Bearer <token> or X-MCP-Token: <token> on every HTTP request.

MCP_HTTP_MAX_BODY_BYTES

1048576 (1 MiB)

Max inbound HTTP request body size (over → 413).

MCP_FETCH_TIMEOUT_MS

30000

Upstream fetch timeout.

MCP_MAX_RESPONSE_BYTES

5242880 (5 MiB)

Max upstream response body size.

MCP_OUTBOUND_ALLOW_PRIVATE

(unset)

Set to 1 to allow loopback/private/metadata hosts (for local tests only).

Additional hardening: sensitive client-supplied header parameters are dropped; operator auth is not sent to non-approved origins; OpenAPI x-mcp: { enabled: false } disables operations; secrets from auth are redacted from tool error text.

Development

npm run build         # tsc → dist/
npm test              # node:test suite (unit + integration round-trips)
npx tsc --noEmit      # type-check only

Tests use Node's built-in node:test (no framework). The integration suite drives a real MCP client↔server round trip against a mock upstream, covering static and dynamic exposure, path params, and request bodies.

License

MIT

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Turns any OpenAPI specification into a fully working MCP server with a single command, enabling AI agents to call APIs without writing any glue code.
    9
    MIT
  • F
    license
    A
    quality
    D
    maintenance
    A universal MCP server that integrates any API with Claude Desktop by pointing it at a Swagger/OpenAPI spec, automatically generating tools for interaction.
    3
    44
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Turns any CLI tool or REST API into an MCP server for Claude, enabling Claude to use git, databases, or any API through natural language.
    MIT