A practical tool is here to convert existing OpenAPIs into MCP Servers in batches

Higress's latest open source capabilities help build MCP Server efficiently.
Core content:
1. OpenAPI-related concepts and application scenarios
2. Conventional practices for converting existing OpenAPIs to MCP Servers
3. Use and configuration debugging of Higress batch conversion tools
Converting existing OpenAPIs into MCP Servers in batches is Higress's latest open source capability, helping developers build MCP Servers efficiently. [1]
Table of contents
01. OpenAPI related concepts
02. Common practices for converting existing OpenAPI to MCP Server
03. Batch conversion of OpenAPI to MCP Server
04. Debug the MCP Server configuration
05. Conclusion
01.
OpenAPI related concepts
OpenAPI is written in YAML or JSON, and defines a language-independent HTTP API interface, providing a unified way of information transmission for each stage of the API life cycle. API allows developers to discover and use corresponding services without accessing the source code.
If a social APP wants to obtain the geographic location information of both parties, it does not need to build an Amap by itself, nor does it need to obtain the Amap source code. Instead, it can obtain the geographic location information through the Amap API interface.
Classic Internet applications, such as Amap and Alipay, all provide API services to the outside world in the form of open platforms; public cloud services, such as Alibaba Cloud, provide API services to users through OpenAPI Explorer, allowing developers to manage cloud resources, data, and services through these application programming interfaces. Another example is artificial intelligence big models. Tongyi, DeepSeek, and OpenAI all provide big model call services to the outside world in the form of APIs. These APIs all follow the OpenAPI specification. With specifications, collaboration will be efficient.
02.
Common practices for converting existing OpenAPI to MCP Server
MCP allows LLM to access external resources, data, and services in a standardized way. Converting existing OpenAPI to MCP Server is a reuse strategy. As a path to ensure economic benefits, the purpose is to enable its own services to be called by external AI applications, thereby increasing the value of existing services. Still taking Amap as an example, Amap provides the ability to convert existing OpenAPI services, such as IP positioning and geocoding, into MCP Server, which allows external applications to call Amap, thereby increasing the activity of the service.
Although MCP has greatly reduced the complexity of large model applications accessing and calling external resources, data, and services, if you use the reuse of existing infrastructure as an MCP development strategy, you will face a new problem, that is, converting existing OpenAPIs into MCP Servers is a "repetitive manual labor" and requires daily maintenance, including interface updates and server stability assurance.
MCP provides SDK toolkits such as TypeScript and Java for developing MCP Server, exposing the existing Open API as a common HTTP service through the MCP protocol. This process includes: [2]
- Read and parse the existing OpenAPI documents and extract key information, such as API path, request method, request parameters, response format, etc.
- According to the MCP protocol specification, it is converted into a new description, including the tool's function description and tool parameter description, and returned to the client as tool/list result.
- When the MCP Client wants to call the MCP Server , it parses the Json RPC request of tool/call, generates the HTTP call request of the backend through the configured parameter mapping information, Path, backend address and other information, and makes the call. After the call is completed, the backend call result is packaged for the standard tool/call interface to return the result.
03.
Batch conversion of OpenAPI to MCP Server
3.1 Installation
go install github.com/higress-group/openapi-to-mcpserver/cmd/openapi-to-mcp@latest
3.2 Use
openapi-to-mcp --input path/to/openapi.json --output path/to/mcp-config.yaml
illustrate
--input
: The path to the OpenAPI specification file (JSON or YAML format), required.--output
: The path to the output MCP configuration file (in YAML format), required.--server-name
: The name of the MCP server. The default value is "openapi-server".--tool-prefix
: The prefix of the tool name, the default value is empty.--format
: Output format (yaml or json), the default value is "yaml".--validate
: Whether to validate the OpenAPI specification, the default value is false.--template
: Path to template file used to patch output, default value is empty.
3.3 Examples
openapi-to-mcp --input petstore.json --output petstore-mcp.yaml --server-name petstore
This example will petstore.json
Convert files to petstore-mcp.yaml
file and set the name of the MCP server to petstore
.
Here is the complete example.
a. Start with an OpenAPI specification (petstore.json):
{ "openapi": "3.0.0", "info": { "version": "1.0.0", "title": "Swagger Petstore", "description": "A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification" }, "servers": [ { "url": "http://petstore.swagger.io/v1" } ], "paths": { "/pets": { "get": { "summary": "List all pets", "operationId": "listPets", "parameters": [ { "name": "limit", "in": "query", "description": "How many items to return at one time (max 100)", "required": false, "schema": { "type": "integer", "format": "int32" } } ], "responses": { "200": { "description": "A paged array of pets", "content": { "application/json": { "schema": { "type": "object", "properties": { "pets": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer", "description": "Unique identifier for the pet" }, "name": { "type": "string", "description": "Name of the pet" }, "tag": { "type": "string", "description": "Tag of the pet" } } }, "nextPage": { "type": "string", "description": "URL to get the next page of pets" } } } } } } }, "post": { "summary": "Create a pet", "operationId": "createPets", "requestBody": { "description": "Pet to add to the store", "required": true, "content":{ "application/json": { "schema": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string", "description": "Name of the pet" }, "tag": { "type": "string", "description": "Tag of the pet" } } } } } }, "responses": { "201": { "description": "Null response" } } } }, "/pets/{petId}": { "get": { "summary": "Info for a specific pet", "operationId": "showPetById", "parameters": [ { "name": "petId", "in": "path", "required": true, "description": "The id of the pet to retrieve", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Expected response to a valid request", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "integer", "description": "Unique identifier for the pet" }, "name": { "type": "string", "description": "Name of the pet" }, "tag": { "type": "string", "description": "Tag of the pet" } } } } } } } } } }}"Tag of the pet" } } } } } }, "responses": { "201": { "description": "Null response" } } } }, "/pets/{petId}": { "get": { "summary": "Info for a specific pet", "operationId": "showPetById", "parameters": [ { "name": "petId", "in": "path", "required": true, "description": "The id of the pet to retrieve", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Expected response to a valid request", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "integer", "description": "Unique identifier for the pet" }, "name": { "type": "string", "description": "Name of the pet" }, "tag": { "type": "string", "description": "Tag of the pet" } } } } } } } } } }}"Tag of the pet" } } } } } }, "responses": { "201": { "description": "Null response" } } } }, "/pets/{petId}": { "get": { "summary": "Info for a specific pet", "operationId": "showPetById", "parameters": [ { "name": "petId", "in": "path", "required": true, "description": "The id of the pet to retrieve", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Expected response to a valid request", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "integer", "description": "Unique identifier for the pet" }, "name": { "type": "string", "description": "Name of the pet" }, "tag": { "type": "string", "description": "Tag of the pet" } } } } } } } } } }}{ "id": { "type": "integer", "description": "Unique identifier for the pet" }, "name": { "type": "string", "description": "Name of the pet" }, "tag": { "type": "string", "description": "Tag of the pet" } } } } } } } } } }}{ "id": { "type": "integer", "description": "Unique identifier for the pet" }, "name": { "type": "string", "description": "Name of the pet" }, "tag": { "type": "string", "description": "Tag of the pet" } } } } } } } } } }}
b. Convert it to Higress REST-to-MCP configuration:
openapi-to-mcp --input petstore.json --output petstore-mcp.yaml --server-name petstore
c. Generate petstore-mcp.yaml file:
server:
name: petstore
tools:
- name: showPetById
description: Info for a specific pet
args:
- name: petId
description: The id of the pet to retrieve
type: string
required: true
position: path
requestTemplate:
url: /pets/{petId}
method: GET
responseTemplate:
prependBody: |
# API Response Information
Below is the response from an API call. To help you understand the data, I 've provided:
1. A detailed description of all fields in the response structure
2. The complete API response
## Response Structure
> Content-Type: application/json
- **id**: Unique identifier for the pet (Type: integer)
- **name**: Name of the pet (Type: string)
- **tag**: Tag of the pet (Type: string)
## Original Response
- name: createPets
description: Create a pet
args:
- name: name
description: Name of the pet
type: string
required: true
position: body
- name: tag
description: Tag of the pet
type: string
position: body
requestTemplate:
url: /pets
method: POST
headers:
- key: Content-Type
value: application/json
responseTemplate: {}
- name: listPets
description: List all pets
args:
- name: limit
description: How many items to return at one time (max 100)
type: integer
position: query
requestTemplate:
url: /pets
method: GET
responseTemplate:
prependBody: |
# API Response Information
Below is the response from an API call. To help you understand the data, I've provided:
1. A detailed description of all fields in the response structure
2. The complete API response
## Response Structure
> Content-Type: application/json
- **pets**: (Type: array )
- **pets[].id**: Unique identifier for the pet ( Type : integer )
- **pets[].name**: Name of the pet ( Type : string )
- **pets[].tag**: Tag of the pet ( Type : string )
- **nextPage**: URL to get the next page of pets ( Type : string )
## Original Response
Note that the tool automatically sets the position field for each parameter based on its position in the OpenAPI spec:
petId
The parameters are set toposition: path
(location: path), because in the OpenAPI specification it is defined asin: path
(located in the path).limit
The parameters are set toposition: query
(Location: Query Parameters), because in the OpenAPI specification it is defined asin: query
(in the query parameters).- Request body attributes (
name
andtag
) is set toposition: body
(Location: request body).
The MCP server automatically handles these parameters in the correct place when making API requests. For more information on how to use this configuration with Higress REST-to-MCP, refer to the Higress REST-to-MCP documentation. [2]
3.4 Functionality
- Convert OpenAPI paths to MCP tools.
- Supports OpenAPI specifications in JSON and YAML formats.
- Generates an MCP configuration containing server and tool definitions.
- Preserve parameter descriptions and types.
- Automatically set parameter locations (path, query, header, cookie, request body) based on OpenAPI parameter locations.
- Handles path, query, header, cookie, and body parameters.
- Generate response templates with field descriptions and improved formatting for Large Language Model (LLM) to understand.
- Optional OpenAPI specification validation (disabled by default).
3.5 Configuring the MCP Server Plug-in
Next, we import the generated files into the Higress console, add the MCP Server plugin and configure it so that it can be used with Higress.
Plugin configuration example:
server: name: "random-user-server" tools:- description: "Get random user information" name: "get-user" requestTemplate: method: "GET" url: "https://randomuser.me/api/" responseTemplate: body: |- # User Information {{- with (index .results 0) }} - **Name**: {{.name.first}} {{.name.last}} - **Email**: {{.email}} - **Location**: {{.location.city}}, {{.location.country}} - **Phone**: {{.phone}} {{- end }}
Note: For the 2025-03-26 MCP streamable HTTP protocol, this plugin can be used directly without the need for a global ConfigMap configuration.
3.6 Calling MCP Server
Configure the SSE connection of MCP Server in AI Agent, taking Cursor as an example:
- MCP Server of database type: Use the path + sse_path_suffix configured in ConfigMap
- MCP Server of REST API type: Use the route path + sse_path_suffix configured in the console
"mcpServers": { "postgres": { "url": "http://your-higress-address/postgres/sse" }, "rest-api": { "url": "http://your-higress-address/user/sse" }
Configuration is completed in Cursor :
With MCP Server, you can quickly add support for various data sources for AI Agents to improve development efficiency. Any REST API can be converted to MCP Server through simple configuration without writing additional code.
04.
Tuning the MCP Server configuration
In the previous chapters, we have learned how the OpenAPI to MCP tool can help us quickly convert existing APIs into tools that can be called by AI assistants. This automated conversion greatly improves development efficiency, allowing us to complete work that would have taken hours or even days in just a few minutes.
However, although the automatically generated configuration is functionally complete, it is often not sophisticated enough. Especially when the API returns complex data structures, if the configuration is not manually tuned, it may cause the large language model (LLM) to understand the data inaccurately, thus affecting the user experience.
4.1 Why do we need to tune the MCP configuration?
The automatically generated MCP configuration will usually contain all the fields returned by the API, presented in a flat manner. This may be sufficient when dealing with simple APIs, but for complex APIs that return a lot of nested data, it will bring several problems:
? Information overload : LLM has a limited context window, and too much irrelevant information will dilute the important content.
? Unclear structure : Complex nested relationships are easily lost in flat descriptions.
? Lack of semantics : Technical codes and professional terms are not converted and difficult to be correctly understood by LLM.
? Hallucination risk : LLM may make incorrect inferences when faced with unfamiliar data structures.
By manually tuning the MCP configuration, we can significantly improve LLM's ability to understand the data returned by the API, reduce misinterpretations and hallucinations, and thus provide users with more accurate and valuable answers.
4.2 Tuning Case: E-commerce Product Search API
Let's use a specific example to illustrate the importance of MCP configuration tuning. Suppose we have a product search API for an e-commerce platform that returns complex product information containing a lot of technical details.
4.2.1 Automatically generated basic configuration
The configuration automatically generated using the OpenAPI to MCP tool might look like this:
server:
name: ecommerce-api
tools:
- name: searchProducts
description: "Search for products in the e-commerce platform"
args:
- name: query
description: "Search query string"
type: string
required: true
- name: category
description: "Product category"
type: string
required: false
- name: limit
description: "Maximum number of results to return"
type: integer
default: 10
requestTemplate:
url: "https://api.example.com/products/search"
method: GET
argsToUrlParam: true
responseTemplate:
prependBody: |
# Search Results
Below is the API response with these fields:
- **success** : Boolean indicating if the request was successful
- **total** : Total number of matching products
- **page** : Current page number
- **pageSize** : Number of items per page
- **products** : Array of product objects with the following fields:
- **id** : Product unique identifier
- **name** : Product name
- **description** : Product description
- **price** : Product price
- **compareAtPrice** : Original price before discount
- **currency** : Currency code (eg, USD, EUR)
- **availability** : Product availability status
- **metadata** : Technical metadata
- **attributes** : Product attributes
- **variants** : Product variations
- **images** : Product images
- **categories** : Categories the product belongs to
- **tags** : Product tags
- **brand** : Product brand information
- **shipping** : Shipping information
- **ratings** : Product ratings and reviews
Original response:
When LLM receives an API response in this configuration, it faces the following challenges:
? Data structure confusion : Unable to clearly understand the internal structure of nested objects (such as metadata, attributes).
? Field meaning is unknown : The possible values of the "availability" field and their meaning are unknown.
? Unclear information priority : It is difficult to determine which information is most important to users.
Context window occupancy : A large amount of raw JSON occupies the context window of LLM, squeezing out other important information.
These issues may lead to the following misunderstandings of LLM:
? Confusing the main product with variant information: "This watch is available in black, silver, and rose gold, and the prices are 899 yuan, 899 yuan, and 949 yuan respectively." (mistaking variant information for the main information)
? Incorrectly associated technical details: "The warranty period for this TechFit Pro smartwatch is TF-SW-P10." (Confusing SKU with warranty period)
? Generating hallucinations based on incomplete information: "This watch is available in all electronics stores." (based on incorrect inference of shipping.locations)
4.2.2 Manually tuned configuration
Higress supports combining Go template and Gjson expressions to perform fine-grained processing on request and response templates (for detailed capabilities, please refer to the document: https://higress.cn/en/ai/mcp-server ). Through careful tuning, we can optimize the configuration as follows:
server:
name: ecommerce -api
tools:
- name: searchProducts
description: "Search for products on the e-commerce platform and return a list of products that match the search criteria, including basic product information, price, inventory status, ratings, etc."
args:
- name: query
description: "Search keywords, which can be product names, brands, models or keywords in descriptions"
type : string
required: true
- name: category
description: "Product category, such as 'electronics', 'clothing', 'home', etc."
type : string
required: false
- name: limit
description: "The number of results returned, range 1-50"
type : integer
minimum: 1
maximum: 50
default: 10
requestTemplate:
url: "https://api.example.com/products/search"
method: GET
argsToUrlParam: true
responseTemplate:
body: |
# Product Search Results
Found {{.total}} products matching "{{.query}}" . Here are the most relevant {{len .products}} results:
{{range $index , $product := .products}}
## {{add $index 1}}. {{$product.name}}
**Price**: {{ if $product .onSale}}~~{{ $product .compareAtPrice}} {{ $product .currency}}~~ **{{ $product .price}} {{ $product .currency}}** (Save {{percentage $product .compareAtPrice $product .price}}%){{ else }}{{ $product .price}} {{ $product .currency}}{{ end }}
**Brand**: {{ $product .brand.name}}
**Stock status**: {{ if eq $product .availability "in_stock" }}In stock{{ else if eq $product .availability "low_stock" }}Low stock{{ else }}Out of stock{{ end }}
{{ if gt (len $product .ratings.reviews) 0 }}**Rating**: {{ $product .ratings.averageRating}} / 5 ({{ $product .ratings.reviewCount}} reviews){{ end }}
{{ $product .description | truncate 200 "..." }}
{{ if gt (len $product .highlights) 0 }}**Product Features**:
{{range $highlight := $product .highlights}}
- {{ $highlight }}
{{ end }}{{ end }}
{{ end }}
{{ if gt .total (len .products)}}
There are more results not shown. You can get more accurate matches by adjusting the search conditions.
{{ end }}
Here’s an actual response example from a smartwatch product, showing how the fine-tuned template handles raw data:
# Product Search Results
Found 128 products matching "smart watch", here are the most relevant 10 results:
## 1. TechFit Pro Smartwatch
**Price** : ~~1299 CNY~~ **899 CNY** (save 30.8%)
**Brand** : TechFit
**Stock Status** : In stock
**Rating** : 4.7/5 (342 reviews)
The TechFit Pro smartwatch is equipped with a high-definition color touch screen, supports heart rate monitoring, blood oxygen detection, multiple sports mode tracking and sleep analysis. It is waterproof and has a battery life of up to 7 days.
**Features** :
-HD AMOLED touch screen
- 7 days of long battery life
-Heart rate and blood oxygen monitoring
- 30 sports modes
- 5ATM waterproof
2. FitBit Versa 3
**Price** : 1499 CNY
**Brand** : FitBit
**Stock Status** : In stock
**Rating** : 4.5/5 (287 reviews)
The FitBit Versa 3 smartwatch has integrated GPS positioning, supports 24/7 heart rate monitoring, has a built-in voice assistant, can answer calls, and has a battery life of up to 6 days.
**Features** :
-Built -in GPS
- Voice assistant function
-Answering calls
- 20+ sports modes
-Waterproof 50 meters
## 3. Apple Watch Series 7
**Price** : 2999 CNY
**Brand** : Apple
**Stock Status** : Limited stock
**Rating** : 4.9/5 (1243 reviews)
The Apple Watch Series 7 has a larger display, faster charging, IP6X dust resistance, swimming-grade waterproofing, and 24/7 blood oxygen monitoring and electrocardiogram functions.
**Features** :
- Retina-grade OLED display
- Fast charging
-ECG and blood oxygen monitoring
- Fall detection and emergency SOS
-Support Apple Pay
There are more results not shown. You can get more accurate matches by adjusting the search conditions.
With this structured response format, LLM can clearly understand the key information of each product without being bogged down by a lot of technical details and raw JSON structure.
4.3 How Tuning Improves LLM Understanding
A well-tuned configuration can significantly improve LLM’s understanding of the data:
4.3.1 Understanding of LLM before tuning
? Structural confusion : Failure to distinguish between the main product and variants, and the possibility of incorrectly describing variant attributes as main product features.
? Focusing on the wrong things : You may focus too much on details (such as SKUs, barcodes) rather than product features that users care about.
? Misunderstanding of field meaning : Failure to correctly understand professional terms and coded values.
? Hallucinations : Being influenced by irrelevant content such as product details, leading to hallucinations
4.3.2 Improved Understanding of LLM after Tuning
? Clear structure : Accurately understand the basic information, price, brand, inventory status and ratings of each product.
? Focus : Able to identify key information such as price discounts, product descriptions and features.
? Clear semantics : The meaning of inventory status is correctly understood without ambiguity.
? Contextual completeness : Get the full picture of the search results ("Found 128 matches, showing 10")
4.4 Tuning Strategy Summary
Based on the above cases, we can extract the following MCP configuration tuning strategies:
? Identify and extract core fields : Analyze the information that users really need and remove technical details and internal data.
? Convert technical codes and technical terms into descriptions that are easy for LLM to understand.
? Add contextual information : Help LLM understand the completeness and scope of the data.
? Structure key information : Use a hierarchical structure to make the importance and relationship of information clear at a glance
05.
Conclusion
The OpenAPI to MCP tool provides us with the ability to quickly convert APIs into AI tools, and manual tuning is a key step in improving AI understanding and user experience. Through carefully designed response templates, we can guide LLM to more accurately understand the data returned by the API, reduce misinterpretations and illusions, and provide users with more valuable services.
In actual applications, it is recommended to use the OpenAPI to MCP tool to generate basic configurations first, and then perform targeted tuning based on the complexity of the API and user needs. For simple APIs, the automatically generated configuration may be sufficient; for complex APIs, especially those that return a large amount of nested data, manual tuning will significantly improve the experience.
It should be emphasized that high-quality MCP configuration tuning often relies on data feedback and iterative optimization. A single configuration is difficult to meet all user scenarios at one time, so it is necessary to build a closed loop of evaluation feedback and continuous optimization based on grayscale testing of multiple configuration versions. Higress will combine the powerful capabilities of the Nacos Configuration Center to provide MCP server maintainers with more sophisticated configuration management functions, including version control, grayscale release, configuration rollback, and effect analysis, so that configuration tuning is no longer a one-time job, but a data-driven continuous optimization process.
Through the complete link of "automatic conversion + manual tuning + data feedback", we can not only enjoy the efficiency improvement brought by automation, but also ensure that the AI assistant provides a high-quality user experience. At the same time, we can continuously optimize the configuration based on actual usage data, so that the capabilities of the AI assistant continue to evolve with use.
Preview: Higress will launch the MCP Marketplace based on API Gateway next week, including 50 commonly used API services to quickly call MCP Server.