yamcp

yamcp

Convert any OpenAPI spec into a secure MCP server with scoped auth, per-tool allow/deny policies, rate limiting, and a redacted audit trail.

Category
Visit Server

README

yamcp

Serve any OpenAPI spec as a secure MCP server — scoped auth, per-tool allow/deny policies, rate limiting, and a redacted audit trail. One command.

npx yamcp serve --config yamcp.config.json

The problem

Your customers' AI agents (Claude, ChatGPT, coding assistants) want to call your API — but exposing an API to an autonomous agent is not the same as exposing it to a developer:

  • Every MCP server you find on GitHub skips security. No caller auth, no audit trail, no way to say "agents may read, never delete."
  • Enterprises block agent access outright because there is no scoped access, no logging, and no rate control between the model and the API.
  • Building it yourself means learning the MCP protocol, mapping your OpenAPI operations to tools by hand, and maintaining it as both evolve.

yamcp closes that gap: point it at the OpenAPI spec you already have, and it serves a policy-enforced MCP server in front of your API.

How it works

Every tool call flows through a fixed pipeline — there is no way around it:

MCP client ──▶ inbound auth ──▶ allow/deny policy ──▶ rate limit ──▶ schema validation ──▶ upstream API
                                                                                              │
                                              audit log (JSONL, secrets redacted) ◀──────────┘
  • Operations → tools, automatically. Each OpenAPI operation becomes an MCP tool with a JSON Schema derived from its parameters and request body. Arguments are validated before anything touches your API.
  • Credentials never reach the model. Upstream API keys are referenced by environment-variable name and injected server-side. Config files contain no secrets, and Authorization inputs are stripped from tool schemas.
  • Deny means invisible. Tools removed by policy or scope are not listed to the client at all — an agent cannot ask for what it cannot see.
  • Everything is on the record. Every call — allowed, denied, rate-limited, or failed — is one JSONL line with caller, decision, latency, and redacted arguments.

Quickstart (30 seconds)

# 1. Generate a config from your spec (lists every derived tool in an allowlist)
npx yamcp init --spec ./openapi.yaml

# 2. Trim the allowlist, set your upstream base URL, then check the result
npx yamcp list --config yamcp.config.json

# 3. Serve
export UPSTREAM_TOKEN=...   # if your API needs auth
npx yamcp serve --config yamcp.config.json

Use it from Claude Code / Claude Desktop

claude mcp add my-api -- npx yamcp serve --config /path/to/yamcp.config.json

or in claude_desktop_config.json:

{
  "mcpServers": {
    "my-api": {
      "command": "npx",
      "args": ["yamcp", "serve", "--config", "/path/to/yamcp.config.json"],
      "env": { "UPSTREAM_TOKEN": "..." }
    }
  }
}

Configuration

{
  "spec": "./openapi.yaml",
  "upstream": {
    "baseUrl": "https://api.example.com",
    // Secrets are env-var references — never literals in this file.
    "auth": { "type": "bearer", "tokenEnv": "UPSTREAM_TOKEN" },
  },
  "policy": {
    "mode": "allowlist", // or "denylist"
    "allow": ["get*", "list*"], // "*" wildcards
    "deny": ["deleteUser"], // deny always wins
    "readOnly": false, // true = GET/HEAD operations only
  },
  "rateLimit": {
    "global": { "rps": 10 },
    "perTool": { "createOrder": { "rps": 1, "burst": 2 } },
  },
  "auth": {
    // Inbound auth for --http mode (stdio inherits the host process's trust).
    "http": {
      "tokens": [
        { "tokenEnv": "YAMCP_READ_TOKEN", "scopes": ["read"] },
        { "tokenEnv": "YAMCP_ADMIN_TOKEN", "scopes": ["read", "write"] },
      ],
      "scopeMap": {
        "read": ["get*", "list*"],
        "write": ["create*", "update*"],
      },
    },
  },
  "audit": {
    "destination": "./audit.jsonl", // or "stderr"
    "redactFields": ["ssn", "card_number"], // merged with built-in defaults
  },
}

Remote mode (Streamable HTTP)

npx yamcp serve --config yamcp.config.json --http --port 3000
  • Callers authenticate with bearer tokens; each token's scopes control which tools it can see and call. Two callers get two different tool lists.
  • --http refuses to start without auth.http configured — secure by default.
  • Token comparison is constant-time; tokens themselves live in environment variables.

CLI

Command What it does
yamcp init --spec <path> Generate a config scaffold with every derived tool in an allowlist
yamcp validate --config <path> Validate config + spec without starting a server
yamcp list --config <path> Show every tool and its effective policy decision
yamcp serve --config <path> [--http] [--port N] Start the MCP server (stdio by default)

Example

A runnable petstore example lives in examples/petstore/ — the audit log below is what one session against it looks like:

{"ts":"2026-07-15T07:25:27.680Z","tool":"getPet","caller":"stdio","decision":"ok","args":{"petId":"42"},"upstreamStatus":200,"latencyMs":99}
{"ts":"2026-07-15T07:25:27.697Z","tool":"deletePet","caller":"stdio","decision":"denied"}

Current limitations

  • Request bodies must be application/json (operations with form/multipart bodies are skipped with a warning at startup).
  • Rate limits are in-memory and per-process — the right shape for MCP's process-per-client model, not for a fleet behind a load balancer.
  • Upstream auth is static bearer/API-key via env vars; OAuth flows to the upstream are on the roadmap.

Security model

See SECURITY.md for the threat model and design decisions.

Development

npm install
npm run build
npm test        # 55 tests: unit + end-to-end over in-memory and HTTP transports

MIT © yamcp contributors

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured