The landscape of AI integration is rapidly evolving. While OpenAPI has long been the gold standard for documenting REST APIs, the Model Context Protocol (MCP) is emerging as the de facto standard for enabling AI agents to interact with tools and data sources. However, many organizations face a challenge: they have extensive OpenAPI specifications but need to expose those capabilities to LLMs via MCP. This post explores how these two specifications compare and how to effectively bridge them for cross-protocol interoperability.
Understanding the Core Differences
At their core, both MCP and OpenAPI are JSON Schema-based definitions, but their design philosophies differ significantly. OpenAPI is designed for human-readable API documentation and strict request/response contracts. It focuses on HTTP methods, paths, and security schemes. MCP, on the other hand, is designed for machine-to-machine communication, specifically for LLMs to discover and invoke tools. It abstracts away the HTTP details and focuses on semantic descriptions that help models understand intent and usage.
Key differences include:
- Transport Layer: OpenAPI implies HTTP/HTTPS. MCP is transport-agnostic, often using stdio or Streamable HTTP.
- Schema Granularity: OpenAPI requires strict typing for all request bodies. MCP often accepts flexible inputs, relying on the model to parse natural language arguments into structured data.
- Description Purpose: OpenAPI descriptions help developers implement clients. MCP descriptions help LLMs decide when and how to use a tool.
Comparing Tool Definitions
An OpenAPI "operation" is mapped to an MCP "tool." Let's look at a practical example. Suppose we have a simple function to search a database.
OpenAPI 3.0 Definition:
openapi: 3.0.0
info:
title: Search API
version: 1.0.0
paths:
/search:
post:
operationId: searchItems
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
query:
type: string
description: The search term
required:
- query
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: array
items:
type: object
MCP Tool Definition:
{
"name": "search_items",
"description": "Searches the product database for items matching the provided query. Returns a list of products with name and price.",
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The keyword or phrase to search for in product names or descriptions."
}
},
"required": ["query"]
}
}
Notice how the MCP definition includes a more descriptive "description" field. This is critical because LLMs rely on this text to understand the tool's utility. The OpenAPI spec relies on the `operationId` and path structure, which are less intuitive for a model trying to reason about actions.
Strategies for Interoperability
When converting OpenAPI to MCP, or vice versa, you should not rely on a simple 1:1 JSON transformation. Instead, consider the following strategies:
- Semantic Enrichment: Use an LLM to generate enhanced descriptions for MCP tools based on the OpenAPI spec. The original doc might say "Get user ID," but the MCP tool description should say "Retrieves the unique identifier for the currently authenticated user." This context helps the model use the tool correctly.
- Flattening Parameters: OpenAPI often uses nested objects in request bodies. MCP works best with flat, simple input schemas. Flatten nested JSON structures into individual parameters where possible to reduce ambiguity for the LLM.
- Error Handling Abstraction: OpenAPI defines HTTP status codes. MCP tools typically return a single result object. Your MCP server implementation should catch HTTP errors from the underlying OpenAPI API and convert them into meaningful error messages within the MCP response, rather than exposing raw 404s to the model.
Implementation Best Practices
To build a robust bridge, wrap your OpenAPI client inside your MCP server. The MCP server acts as an adapter. It receives the tool call from the LLM, constructs the HTTP request defined in the OpenAPI spec, executes it, and formats the response back into an MCP-compatible result.
// Pseudo-code for an MCP Server handler
async function handleSearchTool(args) {
// 1. Validate args against MCP inputSchema
if (!args.query) throw new McpError("Missing query");
// 2. Construct HTTP request based on OpenAPI logic
const response = await fetch("https://api.example.com/search", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: args.query })
});
// 3. Handle errors
if (!response.ok) {
return { content: [{ type: "text", text: `Search failed: ${response.statusText}` }] };
}
// 4. Format success response for MCP
const data = await response.json();
return {
content: [{
type: "text",
text: `Found ${data.length} items: ${data.map(i => i.name).join(", ")}`
}]
};
}
Conclusion
OpenAPI and MCP are not competitors but complementary standards. OpenAPI defines the contract for your API's behavior, while MCP defines the interface for how AI agents perceive and interact with that behavior. By understanding the differences in schema granularity and descriptive intent, you can build effective adapters that expose your existing REST APIs to the world of AI agents. As MCP adoption grows, maintaining a clear mapping between your OpenAPI specs and MCP tool definitions will be essential for anyone building scalable AI-powered applications.