Skip to main content

openapi-to-mcp

The openapi-to-mcp plugin enables the gateway to act as a bridge between OpenAPI specifications and MCP (Model Context Protocol) servers. With this plugin, you can expose your existing OpenAPI-based services through an MCP interface, making them accessible to AI models and clients.

The plugin works by converting your OpenAPI specification into the MCP format and serving it through an MCP server interface. Requests from AI clients are then proxied to your upstream services, with support for custom headers and two transport methods for streaming responses: streamable HTTP and Server-Sent Events (SSE), allowing flexible and reliable real-time communication.

The following diagram illustrates the interaction between the MCP client, API7 gateway, and an upstream OpenAPI service. The path and data are example values for demonstration.


Demo

The following example demonstrates how to enable MCP access to Petstore APIs, allowing AI models and clients to interact with the Petstore service. When configured correctly, the AI client should immediately see available Petstore tools; if tools aren't appearing, verify the OpenAPI specification URL is accessible and the gateway address is reachable from your AI client environment.

Examples

The examples below demonstrate how you can configure openapi-to-mcp plugin for different scenarios.

Enable MCP Access to Petstore APIs

The following example demonstrates how to expose the Petstore APIs through the MCP protocol, allowing AI models and clients to interact with the Petstore service.

Create a route with the openapi-to-mcp plugin:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "openapi-to-mcp-route",
"uri": "/mcp",
"methods": ["GET", "POST"],
"plugins": {
"openapi-to-mcp": {
"transport": "streamable_http",
"base_url": "https://petstore3.swagger.io/api/v3",
"headers": {
"Authorization": "special-key"
},
"openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json"
}
}
}'

❶ Configure the route to allow GET and POST methods. The GET method enables the tool discovery and response streaming (SSE), while the POST method enables the execution and action capabilities (messages).

❷ Configure the transport method to be streamable_http (recommended for production).

❸ Configure the Petstore API address.

❹ Configure the Petstore API credential.

❺ Configure the Petstore OpenAPI document URL.

In your AI client, such as Cursor, update the MCP settings with your API7 Gateway address and append the previously created route path. For instance:

mcp.json
{
"mcpServers": {
"api7-petstore-mcp": {
"url": "http://123.123.123.123:9080/mcp"
}
}
}

If the configuration is successful, you should see the available tools (external functions or services exposed to AI clients through MCP).

You can now interact with API7 Enterprise directly from the chat window of your AI client. For example, try asking: “How many pets are there in the petstore?”

AI client interaction with Petstore

Configure Authentication for MCP Routes

The following example demonstrates how to expose Petstore APIs through the MCP protocol when the route is protected by an authentication method such as key-auth.

Create a consumer johndoe:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "johndoe"
}'

Configure the key-auth credential for johndoe:

curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-john-key-auth",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'

Create a route with the openapi-to-mcp and key-auth plugins:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "openapi-to-mcp-route",
"uri": "/mcp",
"methods": ["GET", "POST"],
"plugins": {
"openapi-to-mcp": {
"transport": "streamable_http",
"base_url": "https://petstore3.swagger.io/api/v3",
"headers": {
"Authorization": "special-key"
},
"openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json"
},
"key-auth": {
"header": "apikey"
}
}
}'

When an MCP server requires authentication, you can specify headers in the mcp.json configuration. Refer to the documentation of your AI client to verify whether headers are supported.

If Headers Are Supported

For example, in Cursor you can update the MCP settings with your API7 Gateway address, append the previously created route path, and include the header required for key-auth:

mcp.json
{
"mcpServers": {
"api7-petstore-mcp": {
"url": "http://123.123.123.123:9080/mcp",
"headers": {
"apikey": "john-key"
}
}
}
}

The configured headers will be added to both GET and POST requests.

If the configuration is successful, you should see the available tools (external functions or services exposed to AI clients through MCP). You can then interact with Petstore directly from the chat window of your AI client.

If the authentication header is not configured in mcp.json, the AI client will be unable to load tools from the MCP server.

If Headers Are Not Supported

If your AI client does not support configuring headers in mcp.json, you can include the authentication credential in the MCP URL query, since key-auth supports obtaining credential from the URL query.

Update the key-auth configuration on the route as such:

curl "http://127.0.0.1:9180/apisix/admin/routes/openapi-to-mcp-route" -X PATCH \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"plugins": {
"key-auth": {
"_meta": {
"filter": [
[
"request_method",
"==",
"GET"
]
]
},
"query": "apikey"
}
}
}'

❶ Only apply the key-auth on GET requests. This is because the apikey configured in the query parameter is only sent with the GET request to the SSE endpoint. It is not included in the subsequent POST message requests. As a result, the message requests will be blocked by the key-auth plugin if the filter is not applied.

❷ Configure the plugin to obtain the authentication key from the query.

In your AI client, include the credential in the API7 Gateway address query parameter:

mcp.json
{
"mcpServers": {
"api7-petstore-mcp": {
"url": "http://123.123.123.123:9080/mcp?apikey=john-key"
}
}
}

If the configuration is successful, you should see the available tools (external functions or services exposed to AI clients through MCP). You can then interact with Petstore directly from the chat window of your AI client.

If the authentication credential is not configured in the MCP server URL query, the AI client will be unable to load tools from the MCP server.

Flatten Tool Schema Parameters

The following example demonstrates how flatten_parameters affects the structure of query and path parameters in the generated MCP tool input schema.

Complete the previous example to set up MCP access to the Petstore APIs. Although the configuration does not explicitly set flatten_parameters, the parameter defaults to false.

In your AI client, such as Cursor, inspect the tool input schema. You should see parameters nested under pathParameters and queryParameters:

{
"operations": {
...,
"getPetById": {
"method": "GET",
"path": "/pet/{petId}",
"pathParameters": {
"type": "object",
"required": ["petId"],
"properties": {
"petId": {
"type": "integer",
"description": "ID of pet to return"
}
},
"additionalProperties": false
}
},
"findPetsByStatus": {
"method": "GET",
"path": "/pet/findByStatus",
"queryParameters": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["available", "pending", "sold"],
"description": "Status values that need to be considered for filter",
"default": "available"
}
},
"additionalProperties": false
}
}
}
}

Update the plugin to flatten query and path parameters:

curl "http://127.0.0.1:9180/apisix/admin/routes/openapi-to-mcp-route" -X PATCH \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"plugins": {
"openapi-to-mcp": {
"flatten_parameters": true
}
}
}'

In your AI client, such as Cursor, inspect the tool input schema. You should see that parameters like status are no longer nested under pathParameters or queryParameters:

{
"operations": {
...,
"getPetById": {
"parameters": {
"type": "object",
"required": ["petId"],
"properties": {
"petId": {
"type": "integer",
"description": "ID of pet to return"
}
},
"additionalProperties": false
}
},
"findPetsByStatus": {
"parameters": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["available", "pending", "sold"],
"description": "Status values that need to be considered for filter",
"default": "available"
}
},
"additionalProperties": false
}
}
}
}

Customize MCP Tool Annotations

Availability

MCP tool annotations are available from API7 Enterprise version 3.9.7.

The following example demonstrates how to add MCP tool annotations to OpenAPI operations exposed by the openapi-to-mcp plugin.

Without these annotations, AI clients only receive the generated tool name, description, and input schema. They cannot reliably tell whether a tool is read-only, destructive, or idempotent, which makes it harder to rank tools correctly and use them safely.

This is implemented in the bundled OpenAPI-to-MCP converter in two ways:

  1. It infers default tool behavior from the HTTP method.
  2. It reads explicit operation-level configuration from the OpenAPI vendor extension x-mcp-annotations.

When both are present, explicit x-mcp-annotations values override the inferred defaults.

Complete the previous example to expose an OpenAPI document through the openapi-to-mcp plugin, then add annotations to the OpenAPI operations:

The previous Petstore example uses a public OpenAPI document that you cannot edit directly. To apply x-mcp-annotations, host your own OpenAPI document and update the openapi_url field in the openapi-to-mcp plugin configuration to point to that hosted document.

openapi.yaml
paths:
/users/{id}:
get:
operationId: getUser
summary: Get user information
x-mcp-annotations:
title: Get User
readOnlyHint: true
openWorldHint: false
delete:
operationId: deleteUser
summary: Delete a user
x-mcp-annotations:
title: Delete User
destructiveHint: true

Supported annotation fields:

  • title
  • readOnlyHint
  • destructiveHint
  • idempotentHint
  • openWorldHint

If x-mcp-annotations is not configured, the converter still applies default inference rules:

  • GET, HEAD, and OPTIONS map to readOnlyHint: true
  • DELETE maps to destructiveHint: true and idempotentHint: true
  • PUT maps to idempotentHint: true

After updating the hosted OpenAPI document, ask your MCP client to list tools. The following snippet shows the result.tools portion of the tools/list response:

{
"tools": [
{
"name": "getUser",
"annotations": {
"title": "Get User",
"readOnlyHint": true,
"openWorldHint": false
}
},
{
"name": "deleteUser",
"annotations": {
"title": "Delete User",
"destructiveHint": true,
"idempotentHint": true
}
}
]
}

Notes:

  • Only operation-level x-mcp-annotations is supported.
  • Invalid values and unsupported fields are ignored.
  • summary and description still control the generated tool description.
  • title is only read from x-mcp-annotations.title.

Troubleshooting

To diagnose issues, check the openapi-to-mcp error log at /usr/local/openapi2mcp/error.log in your gateway container or pod. Note that this log is separate from the gateway’s error log.

Known Issues

  1. The error Cannot use 'in' operator to search for '$ref' in undefined typically occurs when an OpenAPI v2 document is used in openapi_url. The plugin only supports OpenAPI v3 document in openapi_url.

  2. The plugin has a known parsing issue when handling oneOf schemas in OpenAPI v3 document retrieved from openapi_url. In this case, the MCP client will be stuck at tool loading.

API7.ai Logo

The digital world is connected by APIs,
API7.ai exists to make APIs more efficient, reliable, and secure.

Sign up for API7 newsletter

Product

API7 Gateway

SOC2 Type IIISO 27001HIPAAGDPRRed Herring

Copyright © APISEVEN PTE. LTD 2019 – 2026. Apache, Apache APISIX, APISIX, and associated open source project names are trademarks of the Apache Software Foundation