api2ai
Generate production-ready MCP servers from any OpenAPI specification using the highly-used and convenient mcp-use framework

🤖 Agent skill — npx skills@latest add https://github.com/OpenSourceAGI/dev-tools-starter-agent --skill api2ai (what it covers)
🌐 Live Site | 🎯 Example MCP Server
Generate production-ready MCP servers from any OpenAPI specification using the highly-used and convenient mcp-use framework (8k+ GitHub stars).
OpenAPI specs are easy to write and organize your code and have 100s of tools available such as the OpenAPI Builder web UI.
Try it in the browser at api-2-ai.vercel.app — the hosted site lets you design and validate OpenAPI specs visually, browse the docs, and see generated-server examples without installing anything.
Features
- 🚀 Modern Framework - Uses mcp-use for clean, maintainable code
- 🔍 Built-in Inspector - Test tools immediately at
/inspector - 📡 Multiple Transports - HTTP, SSE, and Streamable HTTP support
- 🎨 UI Widgets - Compatible with ChatGPT Apps SDK and MCP-UI
- 🔐 Auth Support - Bearer tokens, API keys, custom headers
- ✨ Zod Schemas - Type-safe parameter validation
- 🛡️ Security Hardening - Risk classification, policy enforcement, HTTP guardrails
- 🐳 Production Ready - Docker, PM2, and Kubernetes ready
Quick Start
# Generate a server from the Petstore API
npx api2ai \
https://petstore3.swagger.io/api/v3/openapi.json \
./petstore-mcp \
--name petstore-api
# Install and run
cd petstore-mcp
npm install
npm startOpen http://localhost:3000/inspector to test your tools!
Usage
CLI
node generate-mcp-use-server.js <openapi-spec> [output-folder] [options]
Options:
--name <name> Server name (default: api-mcp-server)
--base-url <url> Override API base URL
--port <port> Server port (default: 3000)
--allow-mutations Enable POST/PUT/PATCH/DELETE tools by default
--include-tags <tags> Only include tools with these tags (comma-separated)
--exclude-tags <tags> Exclude tools with these tags (comma-separated)
--approve-writes Disable approval requirement for restricted tools
--help Show helpExamples
# From remote URL
node generate-mcp-use-server.js \
https://api.example.com/openapi.json \
./my-server \
--name my-api
# From local file
node generate-mcp-use-server.js \
./specs/my-api.yaml \
./my-mcp-server \
--port 8080
# With custom base URL
node generate-mcp-use-server.js \
./petstore.json \
./petstore \
--base-url https://petstore.example.com/v3
# Include only read-only tools tagged "public"
node generate-mcp-use-server.js \
./api.json \
./readonly-server \
--include-tags public \
--exclude-tags admin,internal
# Enable writes (mutations) explicitly
node generate-mcp-use-server.js \
./api.json \
./full-server \
--allow-mutations \
--approve-writesProgrammatic Usage
import { generateMcpServer, extractTools, loadOpenApiSpec } from './generate-mcp-use-server.js';
// Generate complete server
const result = await generateMcpServer(
'https://api.example.com/openapi.json',
'./output-folder',
{
serverName: 'my-api',
baseUrl: 'https://api.example.com/v1',
port: 3000,
allowMutations: false, // block POST/PUT/PATCH/DELETE by default
includeTags: ['public'], // only include tools tagged "public"
excludeTags: ['admin'], // exclude tools tagged "admin"
}
);
console.log(`Generated ${result.toolCount} tools`);
// Or just extract tools for custom processing
const spec = await loadOpenApiSpec('./my-spec.json');
const tools = extractTools(spec, {
filterFn: (tool) => tool.riskLevel === 'low', // only safe read-only tools
excludeOperationIds: ['deleteUser'],
});Security
The generator enforces a three-layer security model in every generated server.
Layer 1 — Generation-time risk classification
Every tool is classified during generation and the result is baked into src/tools-config.js:
| Risk level | When assigned | Default behavior |
|---|---|---|
low | GET, HEAD, OPTIONS with no dangerous keywords | Enabled, no approval required |
medium | Any mutating method (POST, PUT, PATCH, DELETE) | Blocked unless ALLOW_RESTRICTED_TOOLS=true |
high | Any operation matching admin, auth, billing, payments, tokens, secrets, user management patterns | Blocked, approval required |
Use --allow-mutations at generation time to promote medium-risk tools to enabled-by-default, or override at runtime with env vars.
Layer 2 — Runtime policy enforcement
checkToolPolicy() runs before every outbound API call, reading env vars at call-time so you can change policy without regenerating:
ALLOW_RESTRICTED_TOOLS=true # unlock medium/high-risk tools
REQUIRE_APPROVALS=false # bypass per-call approval gateLayer 3 — HTTP hardening
The generated HTTP client enforces these on every request:
- Timeouts — configurable via
REQUEST_TIMEOUT_MS(default 30 s) - Response size cap — configurable via
MAX_RESPONSE_BYTES(default 10 MB) - No redirects —
redirect: 'error'prevents host-pivot attacks - Credential header protection — tool arguments cannot override
Authorization,Cookie,X-API-Key, or other credential headers; env-configured auth always wins - Host allowlist —
ALLOWED_API_HOSTSrestricts outbound calls to specific hostnames
Inspector note: The built-in inspector at /inspector exposes all registered tools. In production, restrict access using a reverse proxy or firewall rule.
Generated Output
my-mcp-server/
├── .env # Environment config (gitignored)
├── .env.example # Example environment file
├── .gitignore
├── package.json
├── README.md # Generated documentation
└── src/
├── index.js # Main server with tool registrations
├── http-client.js # Hardened HTTP client
├── tools-config.js # Tool configurations with risk metadata
└── policy.js # Runtime security policyGenerated Server Features
Built-in Endpoints
| Endpoint | Description |
|---|---|
GET /inspector | Interactive tool testing UI |
POST /mcp | MCP protocol endpoint |
GET /sse | Server-Sent Events endpoint |
GET /health | Health check |
Environment Variables
| Variable | Description | Default |
|---|---|---|
PORT | Server port | 3000 |
NODE_ENV | development / production | development |
API_BASE_URL | Base URL for API calls | From spec |
API_KEY | Bearer token auth | — |
API_AUTH_HEADER | Custom header (Name:value) | — |
MCP_URL | Public URL for widgets | — |
ALLOWED_ORIGINS | CORS origins (production) | — |
ALLOW_RESTRICTED_TOOLS | Allow medium/high-risk tools | false |
REQUIRE_APPROVALS | Require approval for restricted tools | true |
ALLOWED_API_HOSTS | Comma-separated allowed API hostnames | (spec's host) |
REQUEST_TIMEOUT_MS | Outbound request timeout in ms | 30000 |
MAX_RESPONSE_BYTES | Maximum response body size in bytes | 10485760 |
Connect to Claude Desktop
{
"mcpServers": {
"my-api": {
"url": "http://localhost:3000/mcp"
}
}
}Connect to ChatGPT
The generated server supports the OpenAI Apps SDK out of the box.
Advanced Options
Filter by risk level
const result = await generateMcpServer(specUrl, outputDir, {
filterFn: (tool) => tool.riskLevel === 'low',
});Filter Tools by Method
const result = await generateMcpServer(specUrl, outputDir, {
filterFn: (tool) => ['get', 'post'].includes(tool.method),
});Exclude Dangerous Operations
const result = await generateMcpServer(specUrl, outputDir, {
excludeOperationIds: [
'deleteUser',
'deleteAllData',
'adminReset',
],
});Filter by Path Pattern
const result = await generateMcpServer(specUrl, outputDir, {
filterFn: (tool) => tool.pathTemplate.startsWith('/api/v2/'),
});Combine Filters
const result = await generateMcpServer(specUrl, outputDir, {
excludeOperationIds: ['deleteUser'],
allowMutations: false,
filterFn: (tool) =>
tool.riskLevel === 'low' &&
tool.pathTemplate.includes('/public/'),
});Comparison with Raw MCP SDK
| Feature | This Generator | Raw SDK |
|---|---|---|
| Code needed | ~50 lines | ~200+ lines |
| Inspector | ✅ Built-in | ❌ Manual |
| UI Widgets | ✅ Supported | ❌ Manual |
| Zod validation | ✅ Generated | ❌ Manual |
| Authentication | ✅ Configured | ❌ Manual |
| Risk classification | ✅ Automatic | ❌ Manual |
| Runtime policy | ✅ Generated | ❌ Manual |
| HTTP hardening | ✅ Built-in | ❌ Manual |
| Production ready | ✅ Yes | ⚠️ Requires work |
Please star this repo for updates! 🌟
Last updated on