mcpfather:从 OpenAPI 规范生成企业级 MCP 服务器的生成器
flowgent-labs/mcpfather
flowgent-labs 发布 mcpfather,一款可从 OpenAPI 2.x/3.x(JSON 或 YAML)规范一键生成生产级 MCP 服务器的生成器,每个 API 操作都会变成带类型化输入输出 schema 的 MCP 工具。
An Enhanced enterprise-grade MCP generator / builder — generates production-ready MCP servers from OpenAPI specs, Each API operation becomes an AI-callable tool with typed schemas and customized aggregate virtual tools(Reduce tokens consumption), auth forwarding, and helm chart deployment and OTEL observability, and even use as regular CLI in development.
Features
- OAS 2.x / 3.x support — JSON or YAML, one-command generation. Every OpenAPI operation becomes a typed MCP tool with structured input/output schemas.
- Virtual Tools — Declaratively compose native tools into pipelines (e.g
call → jq → foreach → emit → return). Drastically reduces LLM token consumption for multi-step API workflows. - Enterprise Auth — Frontend OIDC JWT bearer validation (RFC 9728 Resource Server), plus backend OIDC (client credentials + password grants), and static web/cookie tokens for upstream APIs. Frontend and backend credentials are fully decoupled per the MCP Token Passthrough Prohibition.
- Prometheus Metrics — Standard
mcp_tool_call_duration_secondshistogram exported for every native and virtual tool invocation, with configurable boundaries and static labels. - OTel Distributed Tracing — Optional OpenTelemetry tracing via OTLP gRPC (
-tags otel). W3C trace context is propagated to upstream APIs for end-to-end visibility across agent teams. - Deployment Artifacts — Generated projects ship with Dockerfile, Helm chart, Makefile targets, and K8s manifests (ConfigMap, Secret, HPA, Ingress/Gateway, SecretProviderClass for GCP).
- TFS Data Plane Server — Built-in REST endpoints (
/_/tfs/*) for binary file upload and download, cleanly separated from the JSON-RPC 2.0 control plane at/mcp. OpenAPI file transfer operations become MCP tools that route binary payloads through the data plane, not the control channel.
Quick Start
Build Generator
make
Generate MCP server (e.g: Confluence)
./bin/mcpfather -v \
-i use-cases/swaggers/confluence-server-v10.2.14.oas.v3.0.1.json \
-o use-cases/confluence-mcp \
--includes "listSpaces,createPage,updatePage,deletePage"Start in HTTP mode (example)
- The server defaults to httpbin.org which echoes requests — great for quick verification:
export MCP__UPSTREAM__DEFAULT__ENDPOINT=https://api.example.com # Optional 1: setup token from env export MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN=your-token use-cases/confluence-mcp/bin/confluence-mcp -v 10 --transport http --port 8080 # Optional 2: setup token from file (e.g: echo -n "YOUR_TOKEN" > /path/to/.credentials) export MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN_FILE=/path/to/.credentials use-cases/confluence-mcp/bin/confluence-mcp -v 10 --transport http --port 8080
- Test with
mcpclient.sh(forHTTPtransport only)
./mcpclient.sh list-tools
./mcpclient.sh call GetPage '{"id": "123456"}'- Inspection MCP frontend authentication (OAuth2.1).
# Start the MCP server with HTTP mode. export MCP__SERVER__AUTH__OIDC__ENABLED=true export MCP__SERVER__AUTH__OIDC__ISSUER="https://keycloak.example.com/realms/master" export MCP__SERVER__AUTH__OIDC__AUDIENCE="confluence-mcp" ./bin/confluence-mcp -v 10 --transport http --port 8080 # Obtain the OAuth2.1 metadata. curl -s https://iam.example.com/realms/master/.well-known/openid-configuration curl -s localhost:8080/.well-known/oauth-protected-resource #{"resource":"confluence-mcp","authorization_servers":["https://keycloak.example.com/realms/master"],"bearer_methods_supported":["header"]}
Run in CLI Mode (example)
Invoke tools directly from the command line — no MCP agent needed. Useful for debugging, scripting, and manual API exploration. The CLI reuses the same mcptools handlers as the MCP server, so every call makes a real HTTP request upstream.
# Set your upstream endpoint (required for real API calls) export MCP__UPSTREAM__DEFAULT__ENDPOINT=https://api.example.com export MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN=your-token # First call: list available tools use-cases/confluence-mcp/bin/confluence-mcp -t cli list # First tool call: fetch a page by ID use-cases/confluence-mcp/bin/confluence-mcp -t cli Getpage --id 123456 # Show tool-specific help (GNU-style usage) use-cases/confluence-mcp/bin/confluence-mcp -t cli Getpage --help # Call a tool with GNU-style --flag arguments use-cases/confluence-mcp/bin/confluence-mcp -t cli ListSpaces --limit=5 --type global use-cases/confluence-mcp/bin/confluence-mcp -t cli SearchContent --cql 'type=page AND text~"API"' --limit 10 # Call a tool without arguments (for tools that have no required params) use-cases/confluence-mcp/bin/confluence-mcp -t cli ListSpaces
Generator Self Configuration
./bin/mcpfather -i spec.yaml -o output-dir [--includes op1,op2] [--excludes op3] [-v]
| Flag | Description | Example |
|---|---|---|
-i, --input |
Path to the OpenAPI specification file (JSON or YAML) | spec.yaml |
-o, --output |
Path to the output MCP server directory | ./my-mcp |
--includes |
Comma-separated operationId values to generate (omit for all) |
listSpaces,createPage |
--excludes |
Comma-separated operationId values to skip |
healthCheck,status |
-v, --verbose |
Print step-by-step generation details | |
--validation |
Enable OpenAPI schema validation |
Values are matched against the operationId field in the OpenAPI spec (exact string match). An operationId appearing in both --includes and --excludes triggers an error.
Filtering
Use --includes and --excludes to control which operations generate MCP tools. Values are the operationId strings from your OpenAPI spec.
- for example - Generate the Atlassian Confluence MCP server
# Only generate tools for specific operations ./bin/mcpfather -i use-cases/swaggers/confluence-server-v10.2.14.oas.v3.0.1.json \ -o use-cases/confluence-mcp --includes "listSpaces,createPage,getSpaceContent" # Generate all tools except health checks ./bin/mcpfather -i use-cases/swaggers/confluence-server-v10.2.14.oas.v3.0.1.json \ -o use-cases/confluence-mcp --excludes "healthCheck,status" # Generate all tools except a few ./bin/mcpfather -i use-cases/swaggers/confluence-server-v10.2.14.oas.v3.0.1.json \ -o use-cases/confluence-mcp --excludes "uploadAttachment,removeLabel" # Preview what gets included/excluded ./bin/mcpfather -i use-cases/swaggers/confluence-server-v10.2.14.oas.v3.0.1.json \ -o use-cases/confluence-mcp --includes "listSpaces" -v
Tool name truncation
Long operationId values are automatically truncated to 125 characters with a hash suffix to preserve uniqueness, ensuring compatibility with MCP tool name limits.
Generated MCP Server - Configuration
| Flag | Description | Default |
|---|---|---|
--transport <stdio|http|cli> |
Transport mode | stdio |
-p, --port <number> |
HTTP server port | 8080 |
-v, --verbose <0-10> |
Request logging verbosity | 0 |
--print-default-config |
Print default config.yaml to stdout and exit |
Logging levels
| Level | Output |
|---|---|
0 |
Silent |
1 |
HTTP access log: [http] sid=- 200 POST /mcp (1ms) |
2 |
MCP request log: [mcp] tool=SearchContent args={...}, upstream method + URL |
3 |
+ upstream query params |
5 |
+ request/response headers |
7 |
+ request/response body |
9 |
+ pretty-printed JSON body |
10 |
Same as 9 (full debug) |
TFS — Temporary File System (Data Plane)
MCP speaks JSON-RPC 2.0 at /mcp — a control plane that carries structured tool invocations. But OpenAPI specs often include file download/upload operations that transfer raw binary payloads. Pushing multi-megabyte blobs through JSON-RPC is inefficient and breaks streaming semantics.
MCPFather solves this with a dual-plane architecture:
| Plane | Protocol | Endpoint | Purpose |
|---|---|---|---|
| Control | JSON-RPC 2.0 | /mcp |
Tool discovery, typed arguments, structured results |
| Data | REST | /_/tfs/* |
Binary file upload/download with UUID collision avoidance |
How it works:
-
Generator stage — MCPFather detects OpenAPI operations that produce/consume binary content (e.g.
produces: application/octet-stream, multipart form upload). These become MCP tools that return a FileRef (file://URI) instead of inline base64 data. -
At runtime — When an AI agent calls a download tool, the MCP server fetches the binary from the upstream API, stores it to
~/.{app}/tfs/download/{yyyyMMdd}/{uuid}.{suffix}, and returns a JSON result containing the TFS download URL:{"fileRef": "http://localhost:8080/_/tfs/download/20260808/a1b2c3d4-....pdf"} -
Upload reverse — The MCP client uploads a file via
POST /_/tfs/upload/{yyyyMMdd}/{uuid}.{suffix}, the tool invocation receives the file path, and the server forwards the binary upstream.
UUID-based naming prevents collisions when the same file is downloaded or uploaded multiple times. Files are organized by date under ~/.{app}/tfs/download/{yyyyMMdd}/.
Configuration (config.yaml):
server: tfs: enabled: true # set false to disable the data plane (pure JSON-RPC mode)
The TFS REST API is part of the same HTTP server (same port) as
/mcp. No additional ports or services needed.
Environment variables
Auth Layers at a Glance — frontend validates inbound, backend authenticates outbound:
| Layer | Config YAML path | Env var prefix | Role |
|---|---|---|---|
| Server | server.auth.oidc |
MCP__SERVER__AUTH__OIDC__* |
Validates AI agent bearer tokens (inbound) |
| Upstream OIDC | upstream.default.auth.oidc |
MCP__UPSTREAM__DEFAULT__AUTH__OIDC__* |
Server's own OIDC client_credentials for upstream APIs |
| Upstream Static | upstream.default.auth.static |
MCP__UPSTREAM__DEFAULT__AUTH__STATIC__* |
Server's own static token/cookie for upstream APIs |
The AI agent's inbound token is never forwarded upstream (MCP spec: Token Passthrough Prohibition).
Frontend (inbound) env vars:
| Variable | Description |
|---|---|
MCP__SERVER__AUTH__OIDC__ENABLED |
Enable JWT bearer validation for inbound requests |
MCP__SERVER__AUTH__OIDC__ISSUER |
OIDC issuer for agent tokens (used for JWKS discovery) |
MCP__SERVER__AUTH__OIDC__JWKS_URI |
JWKS endpoint (auto-discovered from issuer if empty) |
MCP__SERVER__AUTH__OIDC__AUDIENCE |
Expected aud claim; also the RFC 9728 resource identifier |
Backend (outbound) env vars:
| Variable | Description |
|---|---|
MCP__UPSTREAM__DEFAULT__ENDPOINT |
Base URL of the upstream API (default: https://httpbin.org/anything) |
MCP__UPSTREAM__DEFAULT__AUTH__OIDC__CLIENT_ID |
OIDC client ID for upstream authentication |
MCP__UPSTREAM__DEFAULT__AUTH__OIDC__CLIENT_SECRET |
OIDC client secret for upstream authentication |
MCP__UPSTREAM__DEFAULT__AUTH__OIDC__ISSUER |
OIDC issuer for upstream token acquisition |
MCP__UPSTREAM__DEFAULT__AUTH__OIDC__SCOPES |
OIDC scopes (default: openid) |
MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN |
Static web token for upstream auth |
MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN_FILE |
Path to a file containing the web token |
MCP__UPSTREAM__DEFAULT__AUTH__STATIC__COOKIE_TOKEN |
Cookie token for upstream session auth |
MCP__UPSTREAM__DEFAULT__AUTH__STATIC__COOKIE_TOKEN_FILE |
Path to a file containing the cookie token |
| ... | ... |
Token retrieval priority (backend / outbound)
The server tries to obtain an upstream Bearer token in this order:
- OIDC client_credentials grant (
upstream.default.auth.oidc.*) - Static web token (
upstream.default.auth.static.web_tokenorweb_token_file)
The AI agent's own Authorization header is deliberately excluded from upstream forwarding (MCP spec: Token Passthrough Prohibition).
Token format
- The token value is inspected for a recognized prefix. If the value already starts with
BearerorBasic(case-insensitive), it is used as-is in theAuthorizationheader. Otherwise,Beareris automatically prepended.
Tool filtering
- For specs with many operations, limit which tools AI agents can discover via an optional config file:
# Print the default config template use-cases/confluence-mcp/bin/confluence-mcp --print-default-config # Edit: ~/.confluence-mcp/config.yaml and list only the tools you want
$HOME/.{serviceName}/config.yaml:
# ---- Native MCP Tools ---- native_tools: expose: # When true, all native tools are registered by default # (individual tools can be hidden via excludes). # When false (the default), only tools listed in includes # are exposed. register_all_tools_by_default: false # Explicitly expose these tools (operationId values). # Takes precedence: tools listed here are always exposed, # even if register_all_tools_by_default is false. includes: - ListSpaces - SearchContent # Explicitly hide these tools from external agents (operationId values). # Takes precedence over register_all_tools_by_default. # A tool listed in BOTH includes and excludes will cause # the server to fail at startup. excludes: []
- When
tools.expose.includeis non-empty, only those tools are registered with the MCP server and shown in-t cli list. When absent or empty, all tools are available.
Virtual Tools (Composition)
-
Compose multiple native tools into a single AI-callable tool via a declarative 5-step pipeline DSL. Add a
virtualToolslist to your config file: -
Real Enterprise Virtual Tools definitions:
~/.test-verify-v2/config.yaml:
# ---- Virtual Tools ---- # Compose multiple native tools into a single virtual tool via a declarative # e.g: 5-step pipeline (call → jq → foreach → emit → return). # Schema: https://github.com/flowgent-labs/mcpfather/blob/main/.agents/skills/virtual-tool-creator/resources/dsl-schema.json virtual_tools: - id: getData kind: call spec: tool: GetData parse: json args: id: $input.dataId - id: enrich kind: foreach spec: in: $getData.items as: item concurrency: 8 preserveOrder: true pipeline: - id: getDetail kind: call spec: tool: GetItemDetail args: id: $item.id - id: emitEnriched kind: emit spec: from: $item vars: detail: $getDetail expr: '. + {detail: $detail}' - id: done kind: return spec: from: $enrich
- Pipeline step kinds:
call(invoke an MCP tool),http(direct HTTP API call on a named upstream),jq(jq expression transform),foreach(concurrent iteration over arrays),emit(output within foreach), andreturn(final result). Full documentation in .agents/skills/virtual-tool-creator/. - HTTP step outputs use
{body, headers}; reference payloads as$stepId.bodyand response headers as$stepId.headers.<Header-Name>.
HTTP node connection pool, timeout, and retry
Define reusable policies once and select them from an HTTP node. dial_timeout
limits TCP connection establishment; request_timeout limits one complete
attempt, including reading the response body. Retry has its own total budget.
middleware: http_client_pool: large: max_idle_conns: 128 # reusable idle connections across all upstream hosts max_idle_conns_per_host: 32 # reusable idle connections retained per upstream host max_conns_per_host: 64 # hard cap: active + dialing + idle connections per host dial_timeout: 10s # TCP connection establishment timeout request_timeout: 60s # complete attempt, including response-body reads medium: max_idle_conns: 64 max_idle_conns_per_host: 16 max_conns_per_host: 32 dial_timeout: 5s request_timeout: 30s small: max_idle_conns: 16 max_idle_conns_per_host: 4 max_conns_per_host: 8 dial_timeout: 3s request_timeout: 15s retry: reliable: max_retries: 4 # extra attempts after the first request max_elapsed_time: 30s # hard budget for all attempts and backoff standard: max_retries: 2 max_elapsed_time: 15s besteffort: max_retries: 0 # Select one policy from each group in an HTTP pipeline step: virtual_tools: - name: fetch_issues input_schema: {type: object} pipeline: - id: request kind: http spec: upstream: default pool: medium retry: standard method: GET path: /api/issues - id: done kind: return spec: from: $request.body
The QoS-style names communicate retry intent without promising application-level
success. Omitted references use process-wide built-ins: pool limits 32/32/32,
disabled request timeout, and max_retries: 0.
Generated MCP Server - Agent Integration
OpenCode
~/.config/opencode/opencode.json:
{
"mcp": {
"confluence-mcp": {
"type": "local",
"command": ["bash", "-c", "/path/to/confluence-mcp"],
"args": ["--transport", "stdio"],
"env": {
"MCP__UPSTREAM__DEFAULT__ENDPOINT": "https://api.example.com",
"MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN": "your-token",
"MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN_FILE": "/path/to/fallback/.credentials"
},
"enabled": true
}
}
}Claude Code
~/.claude.json:
{
"mcpServers": {
"confluence-mcp": {
"command": "/path/to/confluence-mcp",
"args": ["--transport", "stdio"],
"env": {
"MCP__UPSTREAM__DEFAULT__ENDPOINT": "https://api.example.com",
"MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN": "your-token",
"MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN_FILE": "/path/to/fallback/.credentials"
}
}
}
}Codex CLI
~/.codex/config.toml:
[mcp_servers.confluence-mcp] url = "http://localhost:8080/mcp" web_token_env_var = "MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN"
Cursor
~/.cursor/mcp.json:
{
"mcpServers": {
"confluence-mcp": {
"command": "/path/to/confluence-mcp",
"args": ["--transport", "stdio"],
"env": {
"MCP__UPSTREAM__DEFAULT__ENDPOINT": "https://api.example.com",
"MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN": "your-token",
"MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN_FILE": "/path/to/fallback/.credentials"
}
}
}
}OpenCode (Remote)
~/.config/opencode/opencode.json:
{
"mcp": {
"confluence-mcp": {
"type": "remote",
"env": {
"MCP__UPSTREAM__DEFAULT__ENDPOINT": "https://api.example.com",
"MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN": "your-token",
"MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN_FILE": "/path/to/fallback/.credentials"
}
}
}
}Claude Code (Remote)
~/.claude.json(User MCPs):
{
"mcpServers": {
"confluence-mcp": {
"url": "http://localhost:8080/mcp",
"env": {
"MCP__UPSTREAM__DEFAULT__ENDPOINT": "https://api.example.com",
"MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN": "your-token",
"MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN_FILE": "/path/to/fallback/.credentials"
}
}
}
}Codex CLI (Remote)
~/.codex/config.toml:
[mcp_servers.confluence-mcp] url = "http://localhost:8080/mcp" web_token_env_var = "MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN"
Cursor (Remote)
~/.cursor/mcp.json:
{
"mcpServers": {
"confluence-mcp": {
"url": "http://localhost:8080/mcp",
"env": {
"MCP__UPSTREAM__DEFAULT__ENDPOINT": "https://api.example.com",
"MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN": "your-token",
"MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN_FILE": "/path/to/fallback/.credentials"
}
}
}
}Docker Deployment
The generated Docker image is a static binary on scratch — no shell, no tools.
Configure via environment variables and a volume-mounted config file.
# 1. Prepare config mkdir -p ~/.my-mcp-server cp config.yaml ~/.my-mcp-server/config.yaml # 2. Run (HOME is required — the server resolves $HOME/.<serviceName>/config.yaml) docker run -d --name my-mcp-server \ --restart unless-stopped \ -e HOME=/home/mcp \ -e MCP__UPSTREAM__DEFAULT__ENDPOINT="https://api.example.com" \ -e MCP__UPSTREAM__DEFAULT__AUTH__STATIC__WEB_TOKEN="your-token" \ -v ~/.my-mcp-server:/home/mcp/.my-mcp-server \ -p 8080:8080 -p 9991:9991 \ ghcr.io/<YOUR_ORG>/my-mcp-server:v1.0.0
Note:
-e HOME=/home/mcpis mandatory. Thescratchimage has no environment variables; withoutHOME,os.UserHomeDir()fails and the server exits immediately.
Helm Deployment
Generated MCP servers ship with an embedded Helm chart under deploy/helm/.
The official Docker image is published to GitHub Container Registry on every release.
# Install a generated MCP server from the ghcr.io image helm upgrade --install --create-namespace \ my-mcp-server ./deploy/helm \ --set image.repository=ghcr.io/<YOUR_ORG>/my-mcp-server \ --set image.tag=v1.0.0 \ --set config.upstream.default.endpoint=https://api.example.com \ --set config.upstream.default.auth.static.create=true \ --set config.upstream.default.auth.static.webToken=<YOUR_TOKEN>
The Helm chart sets ENV HOME=/home/mcp via the Docker image and mounts the config
at /home/mcp/.<serviceName>/config.yaml automatically.
Images are automatically built and pushed to e.g: ghcr.io/<YOUR_ORG>/my-mcp-server
on every tagged release (feat:, fix:, refactor: commits to main).
References swaggers
Atlassian - Jira
-
Server edition (more: developer.atlassian.com/server)
- jira_software_dc_10007_swagger.v3.json (v10.7.4)
- jira_software_dc_11002_swagger.v3.json (v11.2.1)
- Other MCP refer: context7 OpenAPI
- Older specs refer: jira-rest-plugin.wadl
-
Cloud edition (More: developer.atlassian.com/cloud)
Atlassian - Confluence
-
Server edition (More: developer.atlassian.com/server)
-
Cloud edition (More: developer.atlassian.com/cloud)
Sonatype - IQ
Sonatype - Nexus Repository
Sonarqube
- SonarQube APIs official schema - (No Native Swagger format)
- You can use this tool convert (sonarqube-convert-to-oas.py) to OAS format from Sonarqube official schema.
SonarQube API (Page) - @Deprecated (Many commonly used APIs are missing)SonarQube API (custom schema) - @Deprecated (Many commonly used APIs are missing)sonarqube-mcp-server - @Deprecated (official java edition)go-sonarqube-mcp-server - @Deprecated (enhanced go edition based on official above)
Github
- Github RESTful APIs OAS schemas
- ghes-3.21.json
- Or you can also deploy the Local official Github MCP server
Telegram
- Telegram APIs official schema - (No Native Swagger format)
- You can use this tool convert (telegram-convert-to-oas.py) to OAS format from Telegram official schema.
Binance
License
This project is licensed under the AGPL License, but the Generated MCP servers exception, It will use a permissive standard Apache License 2.0. — see the LICENSE file for details.
Contact
For questions, suggestions, or support:
- GitHub Issues: Create an issue
- Discussions: Start a discussion
- Email: jameswong1376@gmail.com
Acknowledgments
This MCP server was generated by MCPFather, an enterprise-grade OpenAPI-to-MCP code generator.
Built with these excellent open-source projects:
- mcp-go — Go SDK for the Model Context Protocol
- OpenTelemetry — observability framework for metrics and tracing
- Prometheus — metrics collection and alerting
- Viper — Go configuration management
- go-jq — Pure Go implementation of jq
- Keycloak — Open Source Identity and Access Management
来源:GitHub · github.com