Install
$ agentstack add mcp-bahri-hirfanoglu-mcpify ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
mcpify
OpenAPI to MCP in seconds
Generate an MCP server from any OpenAPI specification. Let AI assistants interact with your REST APIs instantly.
Install
npm install -g @bahridev/mcpify
Quick Start
# Start an MCP server from a local spec
mcpify ./openapi.yaml
# From a URL
mcpify https://petstore3.swagger.io/api/v3/openapi.json
# With authentication
mcpify ./api.yaml --bearer-token $API_TOKEN
# HTTP transport (remote access)
mcpify ./api.yaml --transport http --port 3100
# Preview tools without starting server
mcpify ./api.yaml --dry-run
# Watch for spec changes
mcpify ./api.yaml --watch
# Interactive config setup
mcpify init
# Validate a spec for MCP compatibility
mcpify validate ./api.yaml
# Inspect a single tool
mcpify inspect ./api.yaml listPets
# Add to Claude Desktop config automatically
mcpify install ./api.yaml --name my-api --bearer-token $API_TOKEN
# Retry on 429/5xx, cache GETs, auto-paginate, pluck fields
mcpify ./api.yaml --retry 3 --cache-ttl 60 --auto-paginate \
--response-fields "data[].id,data[].name"
# Compare two specs for breaking changes
mcpify diff ./old.yaml ./new.yaml --fail-on-breaking
# Smoke-test safe operations against a live API
mcpify test ./api.yaml --bearer-token $TOKEN
Usage
mcpify [options]
Arguments:
spec OpenAPI spec file path or URL
Options:
--spec Spec source (alternative to positional arg)
--transport stdio (default) | http
--port HTTP port (default: 3100)
--base-url API base URL override
--bearer-token Bearer token
--api-key-header API key header name
--api-key-value API key value
--oauth-flow OAuth2 flow (client_credentials | refresh_token)
--oauth-token-url OAuth2 token endpoint
--oauth-client-id OAuth2 client ID
--oauth-client-secret OAuth2 client secret
--oauth-refresh-token OAuth2 refresh token
--oauth-scopes OAuth2 scopes (comma-separated)
--include Include operations (glob, comma-separated)
--exclude Exclude operations (glob, comma-separated)
--tags Only include these tags (comma-separated)
--naming Tool naming: camelCase | snake_case | original
--prefix Prefix for all tool names
--header Custom headers (repeatable)
--max-response-size Max response size in KB (default: 50)
--retry Retry attempts on 429/5xx (default: 0)
--retry-delay Base delay for retry backoff (default: 500)
--retry-max-delay Max delay for retry backoff (default: 10000)
--cache-ttl Cache TTL for GET responses (default: 0)
--cache-max Max cached entries (default: 100)
--auto-paginate Follow pagination links and merge pages
--max-pages Max pages when paginating (default: 10)
--response-fields Dotted paths to select (e.g. "data[].id")
--dry-run List tools without starting server
--watch Watch spec file and reload on changes
--verbose Verbose HTTP logging to stderr
-V, --version Output version
-h, --help Show help
Commands:
init Interactively create a .mcpifyrc.json
validate Report MCP compatibility of a spec
inspect Show full schema and example call for a tool
install Add entry to claude_desktop_config.json
diff Compare two specs, report changes
test Smoke-test safe operations against a live API
Retry, Cache, Pagination, Field Selection
For resilient and token-efficient runtime behavior:
# Retry on 429/5xx with exponential backoff, honoring Retry-After
mcpify ./api.yaml --retry 3 --retry-delay 500 --retry-max-delay 10000
# Cache GET responses for 60 seconds (per-auth keyed)
mcpify ./api.yaml --cache-ttl 60 --cache-max 200
# Follow Link/next/cursor pagination and merge pages into one response
mcpify ./api.yaml --auto-paginate --max-pages 20
# Pluck only the fields the LLM needs from large responses
mcpify ./api.yaml --response-fields "data[].id,data[].name"
All four can be combined and are also configurable via .mcpifyrc.json (retry, retryDelay, retryMaxDelay, cacheTtl, cacheMax, autoPaginate, maxPages, responseFields).
mcpify diff
Compare two spec versions and report added, removed, and changed operations:
$ mcpify diff ./v1.yaml ./v2.yaml
Minimal API v0.1.0 → Minimal API v0.2.0
Added: 1
Removed: 1
Changed: 1
Unchanged: 1
Added operations:
+ getStatus GET /status
Removed operations:
- legacy GET /legacy
Changed operations:
~ getItem GET /items/{id}
+ param query:verbose
Use --fail-on-breaking in CI to guard against removed operations, newly-required parameters, or method/path changes.
mcpify test
Smoke-test safe GET / HEAD operations against a live API:
$ mcpify test ./api.yaml --bearer-token $TOKEN
Base URL: https://api.example.com
Operations: 5 (ok: 3, fail: 0, skipped: 2)
✓ healthCheck GET /health 200 45ms
✓ listPets GET /pets 200 112ms
∘ getPet GET /pets/{petId} (requires parameters)
Exits 1 when any probe fails. Operations requiring path/query/header parameters or using unsafe methods are skipped automatically.
Supported Specs
- OpenAPI 3.0.x and 3.1.x
- Swagger 2.0
- YAML and JSON formats
- Local files and remote URLs
Version is auto-detected — just point mcpify at any spec.
Claude Desktop Configuration
The fastest way: let mcpify edit the config for you.
mcpify install ./path/to/openapi.yaml --name my-api --bearer-token $API_TOKEN
This writes (or updates) an mcpServers.my-api entry in the platform-specific config file:
| Platform | Path | |----------|------| | Windows | %APPDATA%\Claude\claude_desktop_config.json | | macOS | ~/Library/Application Support/Claude/claude_desktop_config.json | | Linux | $XDG_CONFIG_HOME/Claude/claude_desktop_config.json or ~/.config/Claude/claude_desktop_config.json |
Bearer tokens are written to entry.env (not to the CLI args) so they don't show up in process listings. Pass --force to overwrite an existing entry, --config to target a different file, and --transport http --port 3100 to wire up the HTTP transport.
Or edit the file manually:
{
"mcpServers": {
"my-api": {
"command": "mcpify",
"args": ["./path/to/openapi.yaml"],
"env": {
"MCPIFY_BEARER_TOKEN": "your-token"
}
}
}
}
HTTP Transport
Run as a remote MCP server accessible over HTTP:
mcpify ./api.yaml --transport http --port 3100
This exposes:
POST /mcp— MCP JSON-RPC endpoint (Streamable HTTP)GET /mcp— SSE stream for server-initiated messagesDELETE /mcp— End an MCP sessionGET /health— Health check endpoint
Each client gets an isolated session with its own MCP server instance. Sessions are tracked via the mcp-session-id header.
OAuth2
mcpify supports OAuth2 client credentials and refresh token flows. When either the oauth2 security scheme in your spec exposes a clientCredentials.tokenUrl / authorizationCode.refreshUrl and the corresponding credentials are present in the environment, mcpify will automatically fetch tokens and refresh them before expiry.
Client credentials (machine-to-machine)
mcpify ./api.yaml \
--oauth-flow client_credentials \
--oauth-token-url https://auth.example.com/token \
--oauth-client-id $CLIENT_ID \
--oauth-client-secret $CLIENT_SECRET \
--oauth-scopes "read,write"
Or equivalently, let mcpify discover tokenUrl from the spec and only supply the credentials via env vars:
export MCPIFY_OAUTH_CLIENT_ID=...
export MCPIFY_OAUTH_CLIENT_SECRET=...
mcpify ./api.yaml
Refresh token
mcpify ./api.yaml \
--oauth-flow refresh_token \
--oauth-token-url https://auth.example.com/token \
--oauth-client-id $CLIENT_ID \
--oauth-refresh-token $REFRESH_TOKEN
The refresh token is rotated automatically when the server returns a new one in the token response.
.mcpifyrc.json
{
"spec": "./api.yaml",
"oauth": {
"flow": "client_credentials",
"tokenUrl": "https://auth.example.com/token",
"clientId": "my-client",
"clientSecret": "shhh",
"scopes": ["read", "write"]
}
}
Authorization code / OpenID Connect
Full interactive browser-based authorization is out of scope for now. Use your IdP's tooling (or a one-time curl exchange) to obtain a refresh token, then pass it with --oauth-refresh-token. If your spec uses an openIdConnect scheme, provide --oauth-token-url explicitly because mcpify does not auto-discover OIDC configuration.
mcpify init
Generates a .mcpifyrc.json interactively:
$ mcpify init
OpenAPI spec source (file path or URL): ./openapi.yaml
Transport (stdio | http) (stdio): http
HTTP port (3100):
Override base URL (empty to skip):
Auth type (none | bearer | api-key | oauth2) (none): oauth2
OAuth2 flow (client_credentials | refresh_token) (client_credentials):
...
✓ Wrote /path/to/.mcpifyrc.json
Pass --force to overwrite an existing config without confirmation.
mcpify validate
Reports which parts of a spec mcpify can handle, with issues grouped by severity:
$ mcpify validate ./api.yaml
OAuth API v1.0.0
Base URL: https://api.example.com
Operations: 12
Tools: 12
Security schemes:
✓ oauth (oauth2 (clientCredentials))
⚠ oidc (openIdConnect)
Issues:
⚠ security scheme "oidc" is OpenID Connect — mcpify does not
auto-discover the tokenUrl. Provide --oauth-token-url manually
⚠ PASS with warnings — 1 warning(s)
Exits with code 1 when errors are present. Use this in CI to guard against spec regressions.
mcpify inspect
Shows the full tool metadata, a placeholder example argument object, and an equivalent cURL invocation:
$ mcpify inspect ./api.yaml getPet
getPet
──────
GET /pets/{petId}
Base URL: https://petstore.example.com/v1
Tags: pets
Hints: read-only
Description:
Get a pet by ID
Returns: {id, name, tag}
Input schema:
{ ... }
Example arguments:
{ "petId": "" }
cURL:
curl -X GET 'https://petstore.example.com/v1/pets/%3Cstring%3E' \
-H 'Accept: application/json'
Respects --naming, --prefix, --include, --exclude, --tags, and --base-url, so tool name resolution matches the configuration you use at runtime.
Docker
# Build
docker build -t mcpify .
# Run over HTTP
docker run --rm -p 3100:3100 \
-v "$PWD/openapi.yaml:/spec/openapi.yaml:ro" \
mcpify /spec/openapi.yaml --transport http --port 3100
Published images are available at ghcr.io/bahri-hirfanoglu/mcpify:.
GitHub Action
Use the composite action to validate specs or spin up an MCP server in a workflow:
- uses: bahri-hirfanoglu/mcpify@v1
with:
spec: ./openapi.yaml
command: validate
Supported commands: validate, dry-run, inspect, serve. Pass additional flags via extra-args.
Config File
Create a .mcpifyrc.json in your project root to avoid repeating CLI flags:
{
"spec": "./openapi.yaml",
"transport": "stdio",
"bearerToken": "sk-...",
"include": ["get*", "list*"],
"exclude": ["delete*"],
"naming": "snake_case",
"prefix": "myapi_",
"headers": {
"X-Custom-Header": "value",
"X-Api-Version": "2024-01"
},
"verbose": true
}
Supported file names: .mcpifyrc.json, .mcpifyrc, mcpify.config.json
CLI flags always override config file values.
Custom Tool Naming
# Convert operationIds to snake_case
mcpify api.yaml --naming snake_case
# Add a prefix to all tool names
mcpify api.yaml --prefix myapi_
# Combine both
mcpify api.yaml --naming snake_case --prefix myapi_
# listAllPets → myapi_list_all_pets
Custom Headers
Send custom HTTP headers with every API request:
# Single header
mcpify api.yaml --header "Authorization: Bearer sk-..."
# Multiple headers
mcpify api.yaml --header "Authorization: Bearer sk-..." --header "X-Api-Version: 2024-01"
Also configurable via .mcpifyrc.json (headers field).
Filtering Operations
# Only include specific operations
mcpify api.yaml --include "get*,list*"
# Exclude destructive operations
mcpify api.yaml --exclude "delete*,remove*"
# Filter by tags
mcpify api.yaml --tags "users,pets"
Response Schema Hints
Tool descriptions automatically include response structure information extracted from the spec:
listPets — List all pets
Returns: array of {id, name, tag}
This helps AI assistants understand what the API returns before calling a tool.
Key Sanitization
mcpify automatically sanitizes JSON Schema property keys that contain special characters (dots, brackets, hyphens, etc.) to ensure compatibility with all MCP clients. Original keys are restored when making API requests, so the target API always receives the correct parameter names.
X-Request-ID → x_request_id (in tool schema)
filter[name] → filter_name_ (in tool schema)
This is fully transparent — no configuration needed.
Verbose Logging
mcpify api.yaml --verbose
Logs HTTP requests and responses to stderr:
→ GET https://api.example.com/pets?limit=10
← ✓ 200 45ms 1.2KB
→ POST https://api.example.com/pets
← ✗ 401 12ms 156B
Environment Variables
| Variable | Description | |----------|-------------| | MCPIFY_BEARER_TOKEN | Bearer token for authentication | | MCPIFY_API_KEY_HEADER | API key header name | | MCPIFY_API_KEY_VALUE | API key value | | MCPIFY_OAUTH_CLIENT_ID | OAuth2 client ID | | MCPIFY_OAUTH_CLIENT_SECRET | OAuth2 client secret | | MCPIFY_OAUTH_REFRESH_TOKEN | OAuth2 refresh token |
Programmatic API
import { parseSpec, generateTools, startServer } from '@bahridev/mcpify';
const spec = await parseSpec('./openapi.yaml');
const tools = generateTools(spec.operations);
await startServer({
spec,
tools,
operations: spec.operations,
baseUrl: spec.defaultServerUrl,
auth: { type: 'none' },
transport: 'stdio',
port: 3100,
maxResponseSize: 50 * 1024,
});
How It Works
- Parses and dereferences the OpenAPI/Swagger spec
- Converts each operation to an MCP tool with JSON Schema input
- Adds response schema hints to tool descriptions
- Starts an MCP server (stdio or HTTP transport)
- When a tool is called, builds and executes the corresponding HTTP request
- Returns the API response as MCP tool output
License
MIT
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: bahri-hirfanoglu
- Source: bahri-hirfanoglu/mcpify
- License: MIT
- Homepage: https://bahri-hirfanoglu.github.io/mcpify
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.