api2ai
v0.2.9
Published
Generate production-ready MCP servers from any OpenAPI specification using the highly-used and convenient [mcp-use](https://mcp-use.com) framework
Downloads
134
Readme
API2AI: OpenAPI to MCP-Use 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.
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
/inspectorexposes 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 |
