Expose REST APIs as MCP Tools for AI Agents
This guide explains how to use the openapi-to-mcp plugin to expose existing REST APIs as MCP tools. The plugin forwards MCP traffic to the OpenAPI-to-MCP service deployed alongside the gateway. The service reads your OpenAPI definition, exposes each operation as a tool, and sends tool invocations to the upstream REST API.
Overview
MCP (Model Context Protocol) is an open protocol for connecting AI agents to external tools. Without MCP, agent integrations with REST APIs are usually custom and fragile. The openapi-to-mcp plugin and its companion service convert OpenAPI 3.x operations into MCP tool definitions.
With this approach:
- Existing REST APIs stay unchanged.
- AI agents discover tools dynamically through MCP.
- The OpenAPI-to-MCP service (MCP sidecar) translates tool invocations into upstream HTTP requests.
How MCP Gateway Works
The request path is:
AI Agent -> MCP Client -> API7 Gateway -> OpenAPI-to-MCP Service -> Upstream REST APIs
The plugin does not start an MCP server. It proxies requests to the separately deployed OpenAPI-to-MCP service at 127.0.0.1:3000 by default. The service must share the gateway's network namespace and exposes two transport modes:
sse(default):GET /.api7_mcp/ssefor the event streamPOSTmessages on the MCP message endpoint
streamable_http:- Stateless
POST /.api7_mcp/mcp_stateless
- Stateless
For the SSE connection request and for Streamable HTTP requests, the plugin automatically injects x-openapi2mcp-base-url and x-openapi2mcp-openapi-spec headers from the plugin configuration before forwarding the request to the MCP sidecar. You do not need to set these headers manually.
Prerequisites
Before you begin, make sure you have:
-
API7 Enterprise Gateway running (
openapi-to-mcpis Enterprise-only). -
The OpenAPI-to-MCP service deployed in the same network namespace as the gateway. For Helm deployments, set
openapiToMcp.enabled: true. For Docker or bare-metal deployments, follow the deployment and compatibility guidance. -
Create a token from the Dashboard and save it to an environment variable:
export API_KEY=your-dashboard-token # replace with your Dashboard token -
Replace
{gateway_group_id}with your gateway group ID. Usedefaultif you are following the quickstart. -
If you are following the Admin API examples, create or reuse a service in API7 Gateway. If you do not have one yet, follow Create or Reuse a Service, then save its ID to an environment variable:
export SERVICE_ID=your-service-id # replace with your service ID -
An upstream service that exposes a valid OpenAPI 3.x specification.
-
An MCP client (for example, Claude Desktop or another MCP-compatible client) for validation.
Configure the MCP Gateway
Configure a route with the openapi-to-mcp plugin. The following example uses the public Petstore service:
{
"openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json",
"base_url": "https://petstore3.swagger.io/api/v3",
"transport": "sse",
"headers": {},
"flatten_parameters": false
}
- Admin API
- ADC
curl -k "https://localhost:7443/apisix/admin/routes?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
--data-binary @- <<EOF
{
"id": "openapi-to-mcp-route",
"service_id": "$SERVICE_ID",
"paths": ["/.api7_mcp/*"],
"plugins": {
"openapi-to-mcp": {
"openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json",
"base_url": "https://petstore3.swagger.io/api/v3",
"transport": "sse",
"headers": {},
"flatten_parameters": false
}
}
}
EOF
❶ openapi_url points to your OpenAPI 3.x document. The OpenAPI-to-MCP service parses this spec and builds MCP tools from its operations.
❷ base_url is the upstream REST API base address used when a tool is invoked.
❸ transport selects the MCP transport. Use sse (default) or streamable_http.
❹ flatten_parameters controls whether nested parameters are flattened when generating tool input schemas.
services:
- name: MCP Gateway
routes:
- uris:
- /.api7_mcp/*
name: openapi-to-mcp-route
plugins:
openapi-to-mcp:
openapi_url: https://petstore3.swagger.io/api/v3/openapi.json
base_url: https://petstore3.swagger.io/api/v3
transport: sse
headers: {}
flatten_parameters: false
❶ openapi_url points to your OpenAPI 3.x document. The OpenAPI-to-MCP service parses this spec and builds MCP tools from its operations.
❷ base_url is the upstream REST API base address used when a tool is invoked.
❸ transport selects the MCP transport. Use sse (default) or streamable_http.
❹ flatten_parameters controls whether nested parameters are flattened when generating tool input schemas.
Synchronize the configuration to API7 Gateway:
adc sync -f adc.yaml
Validate with an MCP Client
Step 1 — Connect and Discover Tools
SSE Mode
Connect the MCP client to the SSE endpoint:
curl -N "http://127.0.0.1:9080/.api7_mcp/sse"
A successful connection returns an event stream with a session-specific endpoint:
event: endpoint
data: /.api7_mcp/sse?sessionId=abc123xyz
The sessionId value identifies the SSE session created by the MCP sidecar. Use the session-specific endpoint returned by the event stream instead of the route pattern configured on the gateway.
Streamable HTTP Mode
The two transports are mutually exclusive for a route. Before using the Streamable HTTP examples, change transport from sse to streamable_http in the route configuration shown earlier, then reapply that configuration with the Admin API or adc sync.
Send a tools/list request to discover available tools:
curl -s "http://127.0.0.1:9080/.api7_mcp/mcp_stateless" \
-X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'
Response (HTTP 200) — 19 tools discovered:
event: message
data: {
"result": {
"tools": [
{"name": "updatePet", "description": "Update an existing pet by Id"},
{"name": "addPet", "description": "Add a new pet to the store"},
{"name": "findPetsByStatus", "description": "Multiple status values can be provided with comma separated strings"},
{"name": "findPetsByTags", "description": "Multiple tags can be provided with comma separated strings"},
{"name": "getPetById", "description": "Returns a single pet"},
{"name": "updatePetWithForm", "description": "Updates a pet in the store with form data"},
{"name": "deletePet", "description": "Deletes a pet"},
{"name": "uploadFile", "description": "Uploads a file"},
{"name": "getInventory", "description": "Returns a map of status codes to quantities"},
{"name": "placeOrder", "description": "Place a new order in the store"},
{"name": "getOrderById", "description": "For valid response try integer IDs with value <= 5 or > 10"},
{"name": "deleteOrder", "description": "For valid response try integer IDs with positive integer value"},
{"name": "createUser", "description": "This can only be done by the logged in user"},
{"name": "createUsersWithListInput", "description": "Creates list of users with given input array"},
{"name": "loginUser", "description": "Logs user into the system"},
{"name": "logoutUser", "description": "Logs out current logged in user session"},
{"name": "getUserByName", "description": "Get user by user name"},
{"name": "updateUser", "description": "This can only be done by the logged in user"},
{"name": "deleteUser", "description": "This can only be done by the logged in user"}
]
},
"jsonrpc": "2.0",
"id": 2
}
Step 2 — Invoke a Tool
With the route configured for streamable_http, call a tool to verify end-to-end REST forwarding. The following example calls getPetById, which requires a path parameter petId. Because flatten_parameters is false, provide the parameter under pathParameters.
curl -s "http://127.0.0.1:9080/.api7_mcp/mcp_stateless" \
-X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "getPetById",
"arguments": {
"pathParameters": {
"petId": 1
}
}
}
}'
A successful call returns HTTP 200 and an MCP result containing the Petstore resource with ID 1. The other resource fields can vary because the public Petstore data is mutable. Depending on the deployed OpenAPI-to-MCP service version, the resource can appear in a JSON-encoded upstream response envelope or directly in the result, including as structuredContent.
Security Considerations
When exposing APIs as MCP tools, apply the same controls as production API traffic:
- Authentication: enforce gateway auth (API key, JWT, mTLS) before MCP tool calls reach the OpenAPI-to-MCP service.
- Authorization: restrict which routes and operations an agent identity can access.
- Rate limiting: apply request or token-based limits to prevent abusive or runaway agent traffic.
- Sidecar egress: restrict network egress from the OpenAPI-to-MCP service because it fetches the OpenAPI document and sends upstream requests directly. Configure
allowed_hostswhenbase_urlcontains variables.
Next Steps
- Token-Based Rate Limiting and Quota Management — Control agent traffic and cost.
- AI Observability and Cost Tracking — Monitor tool usage and latency.
- For the full configuration reference, see
openapi-to-mcp.