apimcp

package module
v0.12.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 10, 2026 License: MIT Imports: 6 Imported by: 0

README

apimcp

CI Go Reference

Convert an OpenAPI document into an MCP server.

What it does

apimcp adapts an OpenAPI-described HTTP API into an MCP server. MCP clients can discover the API operations as tools and call the existing service without requiring a second hand-written MCP implementation.

Status

This is an MVP. It supports OpenAPI JSON/YAML, common HTTP methods, path and query/header parameters, JSON request bodies, Bearer tokens, API keys, OAuth2 client credentials, stdio and Streamable HTTP transports, and allow/deny tool filters. Path-level parameters are merged with operation parameters, and generated tool names are deterministic. Local and file-based external $ref references are resolved through kin-openapi. By default, external files must remain under the OpenAPI file's directory; remote references require an explicit host allowlist. Reusable schemas are emitted as MCP tool $defs, including recursive schemas. Tool calls also perform server-side checks for required parameters and common JSON types before contacting the upstream API. OpenAPI response descriptions and successful response schemas are exposed in MCP tool metadata as Description and OutputSchema. JSON, empty, and binary success responses are represented, and binary output uses the same Base64 {contentType, filename, data} shape documented below. API key names and locations can be inferred from OpenAPI securitySchemes when they are not supplied explicitly. Basic Auth credentials can be provided with --basic-username and --basic-password-env. Upstream requests have a 30 second timeout and responses are limited to 10 MiB by default. Operation-level security overrides the document-level requirement, and an explicit security: [] keeps a public operation from receiving global credentials. Common OpenAPI parameter styles (form, simple, spaceDelimited, pipeDelimited, and deepObject) are supported for path/query/header/cookie parameters. Multipart file uploads accept Base64-encoded file values, and binary downloads are returned as Base64 data with their content type and filename when present.

Run

go run ./cmd/apimcp --spec openapi.yaml --base-url https://api.example.com

The project uses the official Go MCP SDK and adapts OpenAPI operations into MCP tools. It does not expose every operation automatically when --allow is set:

go run ./cmd/apimcp --spec openapi.yaml --allow getUser,listUsers --stdio

To load local references from a shared directory:

go run ./cmd/apimcp `
  --spec C:\apis\openapi.yaml `
  --external-ref-root C:\apis

Remote references are disabled unless their host is explicitly allowed:

go run ./cmd/apimcp `
  --spec openapi.yaml `
  --remote-ref-hosts schemas.example.com

For an API key:

go run ./cmd/apimcp --spec openapi.yaml `
  --api-key-name X-API-Key `
  --api-key-value "$env:API_KEY" `
  --api-key-in header

For credentials stored in environment variables:

go run ./cmd/apimcp --spec openapi.yaml `
  --bearer-token-env API_TOKEN

go run ./cmd/apimcp --spec openapi.yaml `
  --api-key-value-env API_KEY `
  --api-key-name X-API-Key

When the OpenAPI document defines an apiKey security scheme, the name and location flags can be omitted:

go run ./cmd/apimcp --spec openapi.yaml `
  --api-key-value-env API_KEY

For an OAuth2 clientCredentials security scheme, keep credentials in environment variables:

components:
  securitySchemes:
    serviceOAuth:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://auth.example.com/oauth/token
          scopes:
            users.read: Read users
security:
  - serviceOAuth:
      - users.read
$env:API_CLIENT_ID = "my-client"
$env:API_CLIENT_SECRET = "my-secret"

go run ./cmd/apimcp --spec openapi.yaml `
  --oauth2-client-id-env API_CLIENT_ID `
  --oauth2-client-secret-env API_CLIENT_SECRET `
  --oauth2-scopes users.read,users.write

The token URL is inferred from the OpenAPI flows.clientCredentials.tokenUrl. Use --oauth2-token-url to override it. Access tokens are cached and refreshed automatically when they expire. Only the client credentials flow is currently supported; OAuth2 authorization code and device flows are not implemented.

Reliability options:

go run ./cmd/apimcp --spec openapi.yaml `
  --timeout 15s `
  --max-response-bytes 5242880 `
  --max-retries 2 `
  --retry-base-delay 250ms

Retries apply to idempotent methods (GET, HEAD, OPTIONS, PUT, and DELETE) and transient statuses such as 408, 429, 502, 503, and 504. POST and PATCH are not retried unless explicitly enabled through the Go API.

The --stdio flag is accepted for compatibility with MCP client configurations; stdio is the default transport. To run an HTTP MCP server:

go run ./cmd/apimcp `
  --transport http `
  --listen 127.0.0.1:8080 `
  --spec openapi.yaml `
  --base-url https://api.example.com

The Streamable HTTP MCP endpoint is http://127.0.0.1:8080/mcp. The HTTP server is stateless and returns JSON MCP responses, which is convenient for local development and simple reverse-proxy deployments.

For a multipart/form-data operation with a binary field, pass the field as:

{
  "file": {
    "data": "SGVsbG8=",
    "filename": "hello.txt",
    "contentType": "text/plain"
  }
}

For application/octet-stream request bodies, use the same object under the body argument. Binary responses are exposed in this form:

{
  "contentType": "application/pdf",
  "filename": "report.pdf",
  "data": "<Base64 data>"
}

Library usage

spec, err := apimcp.LoadFile("openapi.yaml")
if err != nil {
    return err
}

return apimcp.RunStdio(ctx, spec, apimcp.Options{
    BaseURL:            "https://api.example.com",
    OAuth2ClientID:     clientID,
    OAuth2ClientSecret: clientSecret,
})

To embed the HTTP transport in another Go service:

handler, err := apimcp.NewHTTPHandler(spec, apimcp.Options{
    BaseURL:     "https://api.example.com",
    BearerToken: token,
})
if err != nil {
    return err
}
http.Handle("/mcp", handler)
return http.ListenAndServe(":8080", nil)

Development

go test ./...
go test -race ./...
go vet ./...

The test suite includes an in-memory MCP client and an httptest upstream server to verify tool discovery, argument validation, request conversion, and error results end to end.

Roadmap

  • OAuth2 authorization code and device flows
  • broader OpenAPI Schema keyword coverage
  • expose response headers and status metadata in tool results

Contributing

See CONTRIBUTING.md for the development workflow and commit conventions.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewHTTPHandler added in v0.8.0

func NewHTTPHandler(document *Document, options Options) (http.Handler, error)

NewHTTPHandler creates an MCP Streamable HTTP handler for document. The handler is intended to be mounted at the /mcp endpoint.

func NewServer

func NewServer(document *Document, options Options) (*mcp.Server, error)

func RunHTTP added in v0.8.0

func RunHTTP(ctx context.Context, document *Document, options Options, addr string) error

RunHTTP starts an MCP Streamable HTTP server on addr. The MCP endpoint is available at /mcp.

func RunStdio

func RunStdio(ctx context.Context, document *Document, options Options) error

Types

type Document

type Document = openapi.Document

func LoadFile

func LoadFile(path string) (*Document, error)

func LoadFileWithOptions added in v0.11.0

func LoadFileWithOptions(path string, options LoadOptions) (*Document, error)

LoadFileWithOptions loads an OpenAPI document with an explicit reference policy.

type LoadOptions added in v0.11.0

type LoadOptions = openapi.LoadOptions

type Options

type Options = adapter.Options

Directories

Path Synopsis
cmd
apimcp command
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL