Turn any OpenAPI specification into a smaller, LLM-friendly MCP server.
- Input: any OpenAPI 3.x spec
- Shaping layer: optional MCP profile to reduce tools, rename parameters, compose workflows, and trim responses
- Output: MCP tools exposed over
stdioor HTTP
| Step | What happens | Why it matters |
|---|---|---|
| 1. Load API | mcp4openapi reads your OpenAPI spec |
Raw REST operations become available for tool generation |
| 2. Shape tools | A profile can group, filter, and simplify operations | The LLM sees fewer, more useful tools |
| 3. Connect client | Your MCP client connects over stdio or HTTP |
You use the API through MCP without custom server code |
Typical outcomes:
- Fewer tools and smaller responses, so the LLM keeps more relevant context
- One server with multiple profiles for dev, staging, prod, or role-specific access
- Reusable higher-level workflows with composite tools and prompt definitions
Start with an existing profile in profiles/, then adapt only what you need.
- I want to try it fast: jump to Quick Start and use an existing bundled profile.
- I need remote access or OAuth: use HTTP transport and OAuth setup.
- I want custom tool design: start with the Profile Guide.
- I want the autonomous-agent machine contracts: see Agent Output Schemas and Autonomous Agents.
- Any OpenAPI API: works with OpenAPI 3.x specifications
- Profiles: transform raw APIs into LLM-friendly MCP tools in MCP profiles
- Tool aggregation: reduce tool clutter by grouping related operations
- Composite actions: chain API calls into reusable workflows
- Prompt definitions: add reusable MCP prompts directly in profiles
- MCP Apps resources: expose static or fetch-backed
resources/list,resources/templates/list,resources/read, and template-variable completion from profiles - Upstream MCP provider config: profiles can declare remote HTTP streamable MCP upstreams (schema and validation first; transport execution follows in later roadmap issues)
- OAuth 2.0: browser-based auth flow for HTTP transport (see docs/OAUTH.md)
- Enterprise managed authorization: inbound JWT bearer grant for HTTP transport with profile-driven issuer/JWKS policy and opaque MCP access tokens (see docs/OAUTH.md)
- Multi-auth: combine multiple auth methods with priority fallback (see docs/MULTI-AUTH.md)
- Multipart uploads:
HttpClienthandlesmultipart/form-data - Observability: structured logging with secrets redaction and Prometheus metrics
- DNS rebinding protection: when binding to localhost (
127.0.0.1/::1), the HTTP transport enforces Host header validation and returns403 { "error": "Forbidden" }on mismatch. This mitigates browser-based DNS rebinding attacks against local development servers. - For remote deployments, bind to an explicit interface or place the server behind a reverse proxy that enforces strict Host checks and origin allowlists.
Check example profiles in profiles/.
Profiles declare a single upstream_mcp object for a remote MCP provider, or resolve it from an env-backed JSON object via upstream_mcp_from_env.
- Supported transport in the first iteration:
transport.type: "http-streamable" - Supported upstream auth subset:
bearer,query,custom-header - Secrets must be referenced with
value_from_env; inline credentials are rejected - If
upstream_mcp_from_envis set and resolves to non-empty JSON, it overrides the staticupstream_mcpobject stdioupstream providers are intentionally deferred to a later, explicitly gated iteration
Example:
{
"upstream_mcp_from_env": "MCP4_UPSTREAM_MCP_JSON",
"upstream_mcp": {
"name": "remote-mcp",
"transport": {
"type": "http-streamable",
"url": "https://remote-mcp.example/mcp"
},
"auth": {
"type": "bearer",
"value_from_env": "REMOTE_MCP_TOKEN"
},
"tool_prefix": "remote",
"tools": {
"allow": ["github_*"],
"deny": ["admin_*"]
},
"timeout_ms": 30000
}
}Use the env-backed path when deployment-specific upstreams differ between environments and you do not want to edit the checked-in profile file.
Profiles can now declare top-level resources[] for MCP Apps UIs and read-only data surfaces:
- fixed resources with
uriand preloadedfile_pathor boundedinline_text - template resources with
uri_template, optional variable completion, and optional fetch-backed rendering through declared read-only OpenAPI/composite bindings - tool-level
appsmetadata to attach output templates and widget metadata without changing the core tool schema generator
See docs/PROFILE-GUIDE.md for the profile shape and validation rules.
For most users, the simplest path is:
- Pick a bundled profile such as
gitlab,codecov, orn8n. - Start
mcp4openapiwithnpx. - Paste one matching MCP client config below.
Minimal local example:
export MCP4_API_TOKEN=your_token
npx mcp4openapi --profile gitlab --api-base-url https://gitlab.example.com/api/v4If you already know your MCP client, go straight to its config example. If not, use the file-location section first.
Cursor:
- Project-Specific:
.cursor/mcp.jsonin your project root - Global: user profile configuration (for example Linux
~/.config/Cursor/User/mcp.json; use⚙→Tools & MCP→New MCP Server)
VS Code + Copilot:
- Project-Specific:
.vscode/mcp.jsonin your project root - Global:
~/.config/Code/User/mcp.jsonin your home directory (platform-dependent; useCtrl+Shift+P→MCP: Open User Configuration)
JetBrains IDEs + Copilot:
- Project-Specific:
.idea/mcp.jsonin your project root - Global:
~/.config/github-copilot/intellij/mcp.json(platform-dependent; use GitHub Copilot icon bottom right →Edit Setting...→Model Context Protocol (MCP)→Configure)
Claude Code:
- Project-Specific:
.claude/mcp.jsonin your project root - Global:
~/.claude.jsonin your home directory (platform-dependent)
No installation required.
Use VS Code dialog to enter access token (recommended for security):
Access Token (Bearer) example:
{
"servers": {
"mcp4openapi": {
"command": "npx",
"args": [
"-y", "mcp4openapi",
"--profile", "<profile-name>",
"--api-base-url", "https://api.example.com"
],
"env": {
"MCP4_API_TOKEN": "${input:api-token}",
}
},
"inputs": [
{
"type": "promptString",
"id": "api-token",
"description": "API Authorization Token",
"password": true
}
]
}
}inputs section prompts you for the token when the server starts, so environment variables are not needed.
Cursor stdio example (non-OAuth, token-based auth only):
{
"mcpServers": {
"mcp4openapi": {
"command": "npx",
"args": [
"-y", "mcp4openapi",
"--profile", "<profile-name>",
"--api-base-url", "https://api.example.com"
],
"env": {
"MCP4_API_TOKEN": "${env:MCP4_API_TOKEN}",
}
}
}
}Cursor OAuth example (HTTP transport, URL-based MCP server):
{
"mcpServers": {
"mcp4openapi-oauth": {
"url": "http://127.0.0.1:3003/profile/<profile-name>/mcp"
}
}
}If profile defines profile_id (or profile_name or profile_alias), you can start with:
npx mcp4openapi --profile (profile-id/name/alias)List available profiles with:
npx mcp4openapi --list-profiles
npx mcp4openapi -lShow standard CLI info with:
npx mcp4openapi --help
npx mcp4openapi -h
npx mcp4openapi --version
npx mcp4openapi -vPredefined profiles in the profiles/ directory contains names for easy reference:
- GitLab profile:
gitlab - YouTrack profile:
youtrack - Codecov profile:
codecov - GitHub security profile:
github-security - SemGrep profile:
semgrep - Grafana profile:
grafana - n8n profile:
n8n - n8n simple node listing profile:
n8n-nodes
Profiles are resolved from ./profiles path by default. If that directory is missing, the bundled npm package profiles are used. Override with --profiles-dir or MCP4_PROFILES_DIR.
MCP4_API_TOKEN(or equivalent environment variable name defined in your profile) with access token (Bearer) must be set for stdio transport with authenticated APIs. OAuth authorization flow is supported for HTTP transport only.
claude mcp add --transport stdio mcp4openapi \
-- npx mcp4openapi --profile <profile-name> --api-base-url https://api.example.comMCP4_API_TOKENwith access token (Bearer) must be set.
{
"servers": {
"mcp4openapi": {
"command": "npx",
"args": [
"mcp4openapi",
"--profile",
"<profile-name>",
"--api-base-url",
"https://api.example.com"
],
"env": {
"MCP4_API_TOKEN": "${input:api-token}",
}
}
}
}- JetBrains IDEs show
⚠️ right next to${input:api-token}to indicate that you need to enter the token manually in the IDE dialog.
See docs/DOCKER.md for build, run, authentication modes, production deployment, and security.
1. Clone & Install:
git clone https://github.com/davidruzicka/mcp4openapi.git
cd mcp4openapi
npm install2. Build:
npm run build3. Configure:
cp env.example .env
# Edit .env with your settings4. Run:
# uses .env for configuration
npm start- alternatively, run with CLI flags:
export MCP4_API_TOKEN=glpat-xxxxxxxxxxxx
npm start --profile mcp-profileSee docs/HTTP-TRANSPORT.md for transport options (stdio vs HTTP) and authentication modes.
Node.js has a fixed list of certificate authorities. If your MCP server uses self-signed certificates, you need to configure Node.js to trust them.
Option 1: Disable certificate validation (test only)
export NODE_TLS_REJECT_UNAUTHORIZED=0
# Persist for current user
echo 'export NODE_TLS_REJECT_UNAUTHORIZED=0' >> $HOME/.profileOption 2: Add custom CA to Node.js
export NODE_EXTRA_CA_CERTS=$HOME/ca-bundle.pem
# Persist for current user
echo 'export NODE_EXTRA_CA_CERTS="$HOME/ca-bundle.pem"' >> $HOME/.profileOption 1: Disable certificate validation (test only)
# Session only
$env:NODE_TLS_REJECT_UNAUTHORIZED = "0"
# Persist for current user
setx NODE_TLS_REJECT_UNAUTHORIZED 0Option 2: Add custom CA to Node.js
# Session only
$env:NODE_EXTRA_CA_CERTS = "$env:USERPROFILE\ca-bundle.pem"
# Persist for current user
setx NODE_EXTRA_CA_CERTS "%USERPROFILE%\ca-bundle.pem"Option 1: Disable certificate validation (test only)
# Session only
export NODE_TLS_REJECT_UNAUTHORIZED=0
# Persist for current user (zsh)
echo 'export NODE_TLS_REJECT_UNAUTHORIZED=0' >> $HOME/.zshrc
# or for bash
echo 'export NODE_TLS_REJECT_UNAUTHORIZED=0' >> $HOME/.bash_profileOption 2: Add custom CA to Node.js
# Session only
export NODE_EXTRA_CA_CERTS="$HOME/ca-bundle.pem"
# Persist for current user (zsh)
echo 'export NODE_EXTRA_CA_CERTS="$HOME/ca-bundle.pem"' >> $HOME/.zshrc
# or for bash
echo 'export NODE_EXTRA_CA_CERTS="$HOME/ca-bundle.pem"' >> $HOME/.bash_profileMCP4_API_TOKEN: API token (default env var name; customizable viaMCP4_AUTH_ENV_VARor profilevalue_from_envfor auth parameters)- Required for stdio mode with authenticated APIs
- Optional for HTTP mode with per-session tokens sent in HTTP headers
- When using no profile mode, auth type is auto-detected from OpenAPI
securityschemes if present
MCP4_PROFILE: Profile ID for resolving profiles from a directory (used by--profile)MCP4_PROFILES_DIR: Profiles root directory for profile ID resolution (default:./profiles)MCP4_PROFILE_PATH: Profile JSON path (default: auto-generate tools from OpenAPI spec; warning logged if tool exceeds 60 parameters)MCP4_OPENAPI_SPEC_PATH: Path or URL to OpenAPI spec (YAML/JSON, supports local files and HTTP/HTTPS URLs). Required when profile does not provideopenapi_spec_path. In HTTP profile routing, this acts as a global fallback for profiles withoutopenapi_spec_path.MCP4_TRANSPORT:stdio(default) orhttpMCP4_API_BASE_URL: Override OpenAPI server URLMCP4_TRUST_BOOTSTRAP_URLS: Set totrueto skip SSRF checks for bootstrap URL fetches (remote OpenAPI spec loading and OAuth metadata discovery). Default is secure mode (false).MCP4_SSRF_ALLOW_PRIVATE_NETWORK: Set totrueto allow private/loopback/link-local targets in SSRF validation paths, including bootstrap URL checks.
Profile auth env vars: Use profile-specific names for value_from_env (for example, GITLAB_TOKEN, YOUTRACK_TOKEN) instead of the generic MCP4_API_TOKEN.
Enterprise authorization env vars: enterprise_authorization also supports selective *_from_env references for issuer, audience, mode, scopes, tool categories, and claim mappings so HTTP enterprise auth can be deployed without editing the profile file. See docs/OAUTH.md for the supported fields and formats.
CLI mapping rule: Documented MCP4_* env vars can be passed as a CLI flag by dropping the MCP4_ prefix and using kebab-case. Example: MCP4_PROFILE_PATH -> --profile-path, MCP4_OPENAPI_SPEC_PATH -> --openapi-spec-path. Unknown flags cause startup to fail.
Global tool filtering removes tools during profile load for every session.
MCP4_TOOL_FILTER_ALLOW_NAMES: Comma-separated tool names to keep (exact match, case-sensitive)MCP4_TOOL_FILTER_ALLOW_NAME_REGEX: Comma-separated regex patterns to allow (auto-anchored unless already wrapped with^and$)MCP4_TOOL_FILTER_DENY_NAMES: Comma-separated tool names to excludeMCP4_TOOL_FILTER_DENY_NAME_REGEX: Comma-separated regex patterns to exclude (auto-anchored)MCP4_TOOL_FILTER_ALLOW_CATEGORIES: Comma-separated operation categories to allow (listand/orread). Composite tools are allowed only if all steps are within the allowed categories.MCP4_TOOL_FILTER_WARN_THRESHOLD_PCT: Warn when filtered percentage exceeds this threshold (default:90)MCP4_TOOL_FILTER_SESSION_MAX_TOOLS: Max entries inX-Mcp4-Toolsheader (default:100)
Regex patterns are validated for length, nested quantifiers, and alternations with quantifiers to reduce ReDoS risk.
- If startup fails with "Tool filter configuration has no effect", ensure allow or deny patterns actually change the tool set.
- If startup fails with "All tools filtered out", relax allow or deny settings to leave at least one tool.
- If session initialization fails with "X-Mcp4-Tools filter has no effect", remove empty headers or adjust entries to restrict tools.
- If session initialization fails with "X-Mcp4-Tools filtered out all tools", verify tool names or regex patterns match available tools.
- If regex validation fails, shorten patterns and avoid nested quantifiers or alternations with quantifiers.
Global parameter filtering constrains tool-call arguments process-wide in both stdio and http.
MCP4_PARAM_FILTER: Baseline parameter filter using the same format asX-Mcp4-Params
CLI mapping:
MCP4_PARAM_FILTER->--param-filter
Rules:
- In
stdio,MCP4_PARAM_FILTERapplies for the lifetime of the local process. - In
http,MCP4_PARAM_FILTERis the baseline for every session. - If a client also sends
X-Mcp4-Paramsduring HTTP initialization, the session header may only narrow the global baseline. - Conflicting overlaps fail with a validation error.
Example:
npx mcp4openapi \
--transport stdio \
--tool-filter-allow-names manage_merge_requests \
--param-filter "project_id=123,_allow_read"When running without a profile (OpenAPI spec only), authentication is automatically configured from OpenAPI spec's security schemes:
MCP4_AUTH_ENV_VAR: Environment variable name for auth token (default:MCP4_API_TOKEN)
Supported OpenAPI Security Types:
- Bearer Token (
httpwithscheme: bearer): UsesAuthorization: Bearer <token>header - API Key in Header (
apiKeywithin: header): Uses custom header (e.g.,X-API-Key: <token>) - API Key in Query (
apiKeywithin: query): Adds token to query string (e.g.,?api_key=<token>) - OAuth2/OpenID Connect: Mapped to bearer token authentication (profile mode only)
- Public APIs: No authentication if OpenAPI spec has no
securitydefined
Example: Use custom env var for GitLab own instance token:
export MCP4_API_TOKEN=xxxxxxxxxxxx
npm start \
--api-base-url https://gitlab.example.com/api/v4 \
--openapi-spec-path https://gitlab.example.com/api/v4/openapi.yamlFor APIs with incomplete OpenAPI specs (missing security definition but requiring authentication):
MCP4_AUTH_FORCE: Enable force auth override (true|false, default:false)MCP4_AUTH_TYPE: Authentication type:bearer|query|custom-header(default:bearer)MCP4_AUTH_HEADER_NAME: Custom header name (required whenMCP4_AUTH_TYPE=custom-header)MCP4_AUTH_QUERY_PARAM: Query parameter name (required whenMCP4_AUTH_TYPE=query)
Example: Force bearer authentication for incomplete spec:
export MCP4_AUTH_FORCE=true
export MCP4_AUTH_TYPE=bearer
export MCP4_API_TOKEN=your_token_here
export MCP4_OPENAPI_SPEC_PATH=./incomplete-spec.yaml
npm startCLI alternative:
export MCP4_API_TOKEN=your_token_here
npm start \
--auth-force true \
--auth-type bearer \
--openapi-spec-path ./incomplete-spec.yamlNote: If OpenAPI spec has security defined, it takes precedence over force auth settings.
MCP4_PROXY_MAX_BYTES: Global override for proxy download size limit (bytes). Must be a positive integer.- Profile-specific env vars can take precedence when defined by the profile via
max_size_bytes_from_envon aproxy_downloadoperation.
Precedence: profile-specific env override → MCP4_PROXY_MAX_BYTES → profile max_size_bytes → built-in default (10MB).
Example: Cap proxy downloads to 2MB globally
export MCP4_PROXY_MAX_BYTES=2097152When generating tools from OpenAPI without a profile, long operation IDs may exceed limits. Configure automatic shortening:
MCP4_TOOLNAME_MAX: Maximum tool name length (default:45)MCP4_TOOLNAME_STRATEGY: Shortening strategy:none|balanced|iterative|hash|auto(default:none)none: No shortening, only warningsbalanced: Add parts by importance until unique & meaningful (recommended)iterative: Progressively remove noise until under limit (conservative)hash: Use verb + resource + hash for guaranteed uniquenessauto: Try strategies in order: balanced → iterative → hash
MCP4_TOOLNAME_WARN_ONLY: Only warn, don't shorten:true|false(default:true)MCP4_TOOLNAME_SIMILAR_TOP: How many similar operationId pairs to show in warnings (default:3)MCP4_TOOLNAME_SIMILARITY_THRESHOLD: Similarity threshold for warning examples (default:0.75)MCP4_TOOLNAME_MIN_PARTS: Minimum parts for balanced strategy (default:3)MCP4_TOOLNAME_MIN_LENGTH: Minimum length in chars for balanced strategy (default:20)
Example: Apply balanced shortening (recommended):
export MCP4_TOOLNAME_STRATEGY=balanced
export MCP4_TOOLNAME_WARN_ONLY=falseResult for balanced strategy:
putApiV4ProjectsIdAlertManagementAlertsAlertIidMetricImagesMetricImageId
→ put_alert_management_image (26 chars)
deleteApiV4ProjectsIdAlertManagementAlertsAlertIidMetricImagesMetricImageId
→ delete_alert_management_image (26 chars)
Example 2: Apply iterative shortening with 30 char limit:
export MCP4_TOOLNAME_STRATEGY=iterative
export MCP4_TOOLNAME_WARN_ONLY=false
export MCP4_TOOLNAME_MAX=30MCP4_HOST: Bind address (default:127.0.0.1)MCP4_PORT: Port (default:3003)MCP4_ALLOWED_ORIGINS: Comma-separated origins (supports exact, wildcard*.domain.com, CIDR192.168.1.0/24)MCP4_SESSION_TIMEOUT_MS: Session timeout (default:1800000= 30min)MCP4_OAUTH_SESSION_TIMEOUT_MS: OAuth session timeout for sessions with refresh tokens (default:86400000= 24h,0= unlimited)MCP4_OAUTH_REFRESH_THRESHOLD_MS: Refresh access tokens this many ms before expiry (default:60000= 60s)MCP4_HEARTBEAT_ENABLED,MCP4_HEARTBEAT_INTERVAL_MS: SSE heartbeat settingsMCP4_TOKEN_MAX_LENGTH: Maximum token length in characters (default:4096, raised from1000in Phase 03.4 to accommodate encrypted token envelopes)MCP4_TOKEN_KEY: Optional symmetric key for AES-256-GCM encrypted token envelopes. When set, the gateway issuesmcp4.v1.*tokens to OAuth clients on/oauth/tokenand rehydrates sessions from them on restart, eliminating the re-authentication round-trip in k8s restart scenarios. Accepts any passphrase (SHA-256-derived) or a 64-char hex string (32 raw bytes). Default unset (plain-token mode, backward-compatible). Seedocs/HTTP-TRANSPORT.md-> Encrypted Token Envelopes for details.MCP4_FILTER_MAX_VALUES: Max values per filtering key (default:10)MCP4_HTTP_PROFILE_ROUTING: Enable profile routing (/profile/:id/mcp). If enabled without a default profile,/mcpis not registered.MCP4_HTTP_PROFILE_INDEX: Enable profile index onGET /for routed profiles.MCP4_PROFILES_DESCRIPTION: Optional JSON object mapping profile id/name/alias to an admin-supplied HTML snippet shown in the HTML profile detail card before the profile description. Parsed once at startup, ignored for JSON index responses, and rejected on invalid JSON, non-string values, duplicate resolution conflicts, or values longer than10000characters.MCP4_ALLOW_PROFILES: Comma-separated profile ids/names/aliases allowed for routed profiles.MCP4_ALLOW_PROFILES_REGEX: Regex for allowed profile ids/names/aliases (applies only when routing is enabled).MCP4_HIDDEN_PROFILES: Comma-separated profile ids/names/aliases to hide from the index page (profiles remain fully functional).MCP4_HTTP_TENANTS_FILE: Path to tenant selector config JSON.MCP4_HTTP_TENANTS_JSON: Inline tenant selector config JSON.MCP4_HTTP_TENANTS_ALLOW_HTTP: Allowhttptenant selectors (default ishttpsonly).
Profile routing example:
export MCP4_TRANSPORT=http
export MCP4_HTTP_PROFILE_ROUTING=true
export MCP4_HTTP_PROFILE_INDEX=true
export MCP4_ALLOW_PROFILES=gitlab-optimized,youtrack-optimized
export MCP4_PROFILES_DIR=./profiles
npx mcp4openapiCLI alternative:
npx mcp4openapi --transport http \
--http-profile-routing true \
--http-profile-index true \
--allow-profiles gitlab,github \
--profiles-dir ./profilesTest with curl:
curl -X POST http://localhost:3003/profile/mcp-profile-name/mcp -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'Profile index admin descriptions:
export MCP4_HTTP_PROFILE_ROUTING=true
export MCP4_HTTP_PROFILE_INDEX=true
export MCP4_PROFILES_DESCRIPTION='{"gitlab":"<p><strong>Internal:</strong> Use SSO token.</p>","youtrack":"<p>Use permanent token from Hub.</p>"}'Notes:
- Keys are matched against
profileId,profileName, and aliases. - The HTML is rendered only in the HTML profile index detail card on
GET /, not in the JSON payload. - The value is rendered as raw HTML, so only trusted administrator-supplied content should be used.
If MCP4_PROFILE_PATH (or --profile-path) is set, /mcp remains available alongside /profile/:id/mcp.
Tenant selection is configured via MCP4_HTTP_TENANTS_FILE or MCP4_HTTP_TENANTS_JSON and supports both:
- exact selectors:
https://team-a.example.com/api - mask selectors:
mask:https://grafana.*.security.*.ops.iszn.cz/api - mask path wildcards:
mask:https://monitoring.ops.iszn.cz/*/api(*matches exactly one path segment)
Selection headers (initialize request):
X-Mcp4-Tenant-Id: selects tenant bytenant_idX-Mcp4-Api-Base-Url: selects concrete tenant endpoint by exact ormask:selector
Required tenant scoping:
profile_ids: required non-empty array of profile ids where the tenant is active
Resolution order:
X-Mcp4-Tenant-Id- exact
X-Mcp4-Api-Base-Url mask:X-Mcp4-Api-Base-Url
Rules:
- For
mask:tenant selection, concreteX-Mcp4-Api-Base-Urlis required. - If both tenant headers are provided, they must resolve to the same tenant.
- On existing session requests, provided tenant headers must match stored tenant context.
- Startup rejects selector collisions (exact/exact with incompatible auth, exact/mask overlap, mask/mask overlap) and runtime rejects ambiguous mask matches.
- If no tenant headers are sent, no tenant override is applied and profile-level config is used.
When MCP4_HTTP_PROFILE_INDEX=true, the HTML profile index shows tenant availability per profile and provides interactive tenant picker for supported remote snippet formats that inject X-Mcp4-Tenant-Id into copied snippet output. Picker always includes a "no tenant" option that keeps snippets without tenant headers. For mask: tenants, copied snippets also include example X-Mcp4-Api-Base-Url with wildcard parts replaced by <your-part>. In Local stdio mode, tenant selection updates API base URL in snippets that support local env injection (using profile API endpoint env var). The same page also exposes a per-profile tool catalog with interactive builders for X-Mcp4-Tools and X-Mcp4-Params: in remote mode, unsupported custom-header snippet variants are hidden while filtering is active; in local mode, the same filter state is translated into --tool-filter-allow-names, --tool-filter-allow-categories, and --param-filter inside generated stdio snippets. Profiles that use auth.type: "session-cookie" are intentionally shown only in Local stdio snippets because remote HTTP initialization does not accept upstream login/password via request headers.
X-Mcp4-Params is a per-session header for constraining tool call parameters (not tool selection). It is parsed on session initialization and then enforced for the lifetime of the session: subsequent requests may omit the header, but if provided it must match the session value or the server returns a 400 validation error. If MCP4_PARAM_FILTER is also set, the session header may only narrow that process-wide baseline.
Format: comma-separated key=value pairs. Repeat keys to allow multiple values.
Example for GitLab profile:
X-Mcp4-Params: project_id=123, project_id=mcp/mcp-gitlab, _allow_list, _allow_read
What this means:
- The session is constrained to the GitLab project identified by either
123ormcp/mcp-gitlab(both refer to the same project) for tools that acceptproject_id(or an alias mapped to it). If a tool call provides a differentproject_id, the server rejects it. - This is useful for agent-style workflows (e.g., "code review only within project 123/456") because the client can enforce the scope at session init instead of relying on the agent to always remember to pass the correct project parameter.
_allow_listand_allow_readrelax filter enforcement for list and read operations; use them if you want list/read calls to be allowed even when they omit the filtered key, or when they pass a different value.
Notes:
- Keys are validated against the currently available tool parameters (including parameter aliases).
- Max values per key are limited by
MCP4_FILTER_MAX_VALUES. - Control keys (no value):
_allow_list: allows list operations to omit the filtered key (only affects presence enforcement)._allow_read: allows read operations to omit the filtered key (only affects presence enforcement).- If the filtered key is present in arguments, its value is not constrained for list/read operations.
- Control keys do not relax modify operations.
- Control keys are only meaningful when at least one
key=valuefilter is present (otherwise there is nothing to enforce).
See docs/HTTP-TRANSPORT.md for detailed HTTP transport configuration.
MCP4_SSL_CERT_FILE,MCP4_SSL_KEY_FILE: SSL certificate and key (PEM format)
When both are set, server automatically starts in HTTPS mode.
See docs/OAUTH.md for SSL configuration with OAuth.
OAuth requires HTTP transport. Stdio (command/args) client configuration does not support OAuth browser flow.
Cursor OAuth setup (global user config) example:
{
"mcpServers": {
"gitlab-oauth": {
"url": "http://127.0.0.1:3003/mcp"
}
}
}Autodiscovery - Just provide DCR (Dynamic Client Registration) credentials, API base URL and OAuth callback:
export MCP4_TRANSPORT=http
export MCP4_HOST=127.0.0.1
export MCP4_PORT=3003
export MCP4_API_BASE_URL=https://www.gitlab.com/api/v4
export MCP4_OAUTH_CLIENT_ID=your_dcr_client_id
export MCP4_OAUTH_CLIENT_SECRET=your_dcr_client_secret
export MCP4_OAUTH_REDIRECT_URI=http://127.0.0.1:3003/oauth/callback
# OAuth endpoints are automatically discovered from API base URLNote: DCR and OAuth callback must be registered with the OAuth provider.
Configuration priority:
- Explicit URLs:
MCP4_OAUTH_AUTHORIZATION_URL,MCP4_OAUTH_TOKEN_URL(highest priority) - Explicit issuer:
MCP4_OAUTH_ISSUER(auto-derives standard OAuth paths) - Autodiscovery: From
MCP4_API_BASE_URL(fetches RFC 8414 metadata or uses standard paths)
Environment variables:
MCP4_OAUTH_CLIENT_ID,MCP4_OAUTH_CLIENT_SECRET: OAuth client credentials (required)MCP4_OAUTH_REDIRECT_URI: OAuth redirect URI (required, must match registered URI)MCP4_ALLOW_UNREGISTERED_CLIENTS: Allow authorize requests for unregistered OAuth clients when redirect URIs match the approved allowlist (optional, default:false)MCP4_ALLOWED_UNREGISTERED_REDIRECT_URIS: Comma-separated approved redirect URI rules for unregistered OAuth clients, e.g.http://localhost,cursor://(optional)MCP4_OAUTH_ISSUER: OAuth provider issuer URL (optional, auto-derives endpoints)MCP4_OAUTH_AUTHORIZATION_URL,MCP4_OAUTH_TOKEN_URL: OAuth endpoints (optional, for non-standard paths)MCP4_OAUTH_CLIENT_STORE_MAX_CLIENTS: Max dynamic OAuth clients stored in memory (default:1000)MCP4_OAUTH_CLIENT_STORE_MAX_REDIRECT_URIS: Maxredirect_urisper dynamic client (default:10)MCP4_OAUTH_CLIENT_STORE_MAX_REDIRECT_URI_LENGTH: Max length of one redirect URI (default:256)MCP4_OAUTH_CLIENT_STORE_IDLE_GRACE_MS: Minimum age (ms) before an idle OAuth client is evictable (default:0)
CLI equivalents:
--allow-unregistered-clients true--allowed-unregistered-redirect-uris http://localhost,cursor://
Dynamic client store eviction behavior:
- Eviction prefers idle dynamic clients (
mcp-client-*) and does not evict clients that are currently active in session/state/code flows. - If store is full and no idle candidate is safely evictable,
/oauth/registerreturns429withtemporarily_unavailable.
See docs/OAUTH.md for complete setup guide including OAuth application registration, SSL configuration, and troubleshooting.
MCP4_HTTP_RATE_LIMIT_ENABLED: Enable rate limiting (default:true)MCP4_HTTP_RATE_LIMIT_WINDOW_MS: Rate limit window (default:60000= 1 minute)MCP4_HTTP_RATE_LIMIT_MAX_REQUESTS: Max requests for MCP endpoints (default:100)MCP4_HTTP_RATE_LIMIT_METRICS_MAX: Max requests for/metrics(default:10)
OAuth Rate Limiting (stricter limits for OAuth endpoints):
MCP4_OAUTH_RATE_LIMIT_MAX: Max OAuth requests per window (default:10)MCP4_OAUTH_RATE_LIMIT_WINDOW_MS: OAuth rate limit window (default:60000= 1 minute)
Configuration Priority: Profile > Environment variables > Defaults
Defaults:
- 100 requests/minute for MCP endpoints, 10 requests/minute for metrics
- 10 requests/1 minute for OAuth endpoints (
/oauth/authorize,/oauth/token,/oauth/callback)
Returns 429 Too Many Requests when exceeded.
MCP4_LOG_LEVEL:debug,info(default),warn,errorMCP4_LOG_FORMAT:console(default) orjsonMCP4_METRICS_ENABLED: Enable Prometheus metrics (default:false)MCP4_METRICS_PATH: Metrics endpoint (default:/metrics)- HTTP/session/tool/API metrics include
profile_idandtenant_idlabels; when unresolved they useprofile_id="unknown"andtenant_id="none".
Security Note:
- Sensitive auth tokens are automatically redacted from logs based on your profile's auth configuration (bearer, query, custom-header, or session-cookie)
- All errors returned to clients are sanitized to generic messages (
Internal error) while full details are logged server-side
Profile defines which MCP tools from OpenAPI spec are exposed and how to aggregate them.
Start with existing profiles from profiles/ (e.g., GitLab).
Features:
- Tool aggregation (group related operations)
- Response field filtering (reduce LLM context)
- Composite actions (chain API calls)
- Rate limiting & retry logic
Create your own profiles: See docs/PROFILE-GUIDE.md
npm run validate
# Checks: JSON syntax, schema, logic, OpenAPI operationsnpm run validate:schema
# Validates profile-schema.json itselfnpm test
npm run test:e2eCursor:
- Open "Output" panel (Ctrl+Shift+U / Cmd+Shift+U)
- Select "MCP Logs" from dropdown
- Check for connection errors or authentication issues
VS Code:
- Open "Output" from View menu
- Select problematic MCP server from dropdown
- Review MCP tool logs for errors
JetBrains IDEs:
- Open "Help" → "Show Log in <your_explorer>" → "mcp" directory to access MCP log files
- Check
<your_mcp_server>.logfor MCP-related errors
Common Issues:
- Connection refused: Check if MCP server is running and accessible
- Authentication failed: Verify token is correct and has required permissions
- Certificate errors: Configure Node.js to trust custom CA certificates (see Custom CA Certificates)
- Tool not found: Verify OpenAPI spec path and profile configuration
- Cursor: Cursor MCP Guide
- VS Code + Copilot: VS Code MCP Servers, GitHub Copilot MCP Guide
- JetBrains IDEs + Copilot: JetBrains+Copilot MCP Guide
- docs/EXAMPLE-GITLAB.md - Complete GitLab API example with curl commands
- docs/PROFILE-GUIDE.md - Guide for creating custom profiles
- docs/HTTP-TRANSPORT.md - HTTP transport setup and usage
- docs/OAUTH.md - OAuth 2.0 authentication setup guide
- docs/MULTI-AUTH.md - Multi-auth support: OAuth + Bearer tokens
- docs/DOCKER.md - Docker deployment guide (includes Kubernetes example)
- docs/RELEASING.md - Release process and CI/CD automation (for maintainers)
profiles/- Example profiles for OpenAPI specsprofiles/youtrack/- YouTrack profile + bundled OpenAPI spec (ready-to-use MCP tools)profiles/codecov/- Codecov CRUD-style profile + bundled OpenAPI specprofile-schema.json- JSON Schema for IDE autocomplete
- Core MCP server with tool generation
- stdio transport (MCP SDK)
- HTTP Streamable transport (MCP Spec 2025-03-26)
- Session management & SSE resumability
- Profile system with validation
- Prometheus metrics (HTTP, sessions, tools, API calls)
See CONTRIBUTING.md for development guidelines.
