Crates.io | rmcp-openapi |
lib.rs | rmcp-openapi |
version | 0.16.1 |
created_at | 2025-07-09 14:45:26.671931+00 |
updated_at | 2025-09-25 16:31:42.867972+00 |
description | Library for converting OpenAPI specifications to MCP tools |
homepage | https://gitlab.com/lx-industries/rmcp-openapi |
repository | https://gitlab.com/lx-industries/rmcp-openapi |
max_upload_size | |
id | 1744990 |
size | 1,109,660 |
A Rust workspace providing OpenAPI to MCP (Model Context Protocol) conversion tools.
This workspace contains two crates that work together to bridge OpenAPI specifications and the Model Context Protocol (MCP):
rmcp-openapi
(library): Core functionality for converting OpenAPI specifications to MCP toolsrmcp-openapi-server
(binary): MCP server executable that exposes OpenAPI endpoints as toolsThis enables AI assistants to interact with REST APIs through a standardized interface.
rmcp-openapi
acts as a proxy between MCP clients and OpenAPI services, which creates unique security considerations regarding authorization header handling.
Important: Please read the SECURITY.md file for detailed information about:
By default, the server operates in MCP-compliant mode and does not forward authorization headers. Non-compliant modes require explicit opt-in via compile-time features and runtime configuration.
We welcome contributions to rmcp-openapi
! Please follow these guidelines:
main
: git checkout -b feature/my-new-feature
cargo test
# Clone your fork
git clone https://gitlab.com/your-username/rmcp-openapi.git
cd rmcp-openapi
# Build the project
cargo build --workspace
# Run tests
cargo test
cargo fmt
to format codecargo clippy --all-targets
to catch common mistakesFound a bug or have a feature request? Please report it on our GitLab issue tracker.
cargo install rmcp-openapi-server
# Build entire workspace
cargo build --workspace --release
# Build specific crates
cargo build --package rmcp-openapi --release # Library only
cargo build --package rmcp-openapi-server --release # Server only
Add to your Cargo.toml
:
[dependencies]
rmcp-openapi = "0.8.2"
rustls-tls
(default): Use rustls for TLS supportnative-tls
: Use native TLS implementationtransport-sse
: Enable deprecated SSE (Server-Sent Events) transport for backward compatibilityauthorization-token-passthrough
: Enable non-compliant authorization header forwarding (see SECURITY.md)# Default configuration (StreamableHttp transport only)
[dependencies]
rmcp-openapi = "0.13.0"
# Enable deprecated SSE transport for backward compatibility
[dependencies]
rmcp-openapi = { version = "0.13.0", features = ["transport-sse"] }
# Server with SSE transport
[dependencies]
rmcp-openapi-server = { version = "0.13.0", features = ["transport-sse"] }
use rmcp_openapi::Server;
use serde_json::Value;
use url::Url;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load OpenAPI specification JSON (from URL, file, or embedded)
let openapi_json: Value = {
// Example: Load from embedded JSON string
let spec_content = r#"{
"openapi": "3.0.3",
"info": {"title": "Pet Store", "version": "1.0.0"},
"paths": {
"/pets": {
"get": {
"operationId": "listPets",
"responses": {"200": {"description": "List of pets"}}
}
}
}
}"#;
serde_json::from_str(spec_content)?
// In practice, you'd load from file or URL using your preferred method
};
// Create server with OpenAPI specification and base URL
let mut server = Server::builder()
.openapi_spec(openapi_json)
.base_url(Url::parse("https://api.example.com")?)
.build();
// Parse the OpenAPI specification and generate tools
server.load_openapi_spec()?;
// Get information about generated tools
println!("Generated {} tools", server.tool_count());
println!("Available tools: {}", server.get_tool_names().join(", "));
Ok(())
}
use rmcp_openapi::Server;
use reqwest::header::HeaderMap;
use serde_json::Value;
use url::Url;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load OpenAPI specification from file (async I/O handled by your code)
let openapi_json: Value = {
let content = tokio::fs::read_to_string("./api-spec.json").await?;
serde_json::from_str(&content)?
};
let base_url = Url::parse("https://api.example.com")?;
// Create headers
let mut headers = HeaderMap::new();
headers.insert("Authorization", "Bearer token123".parse()?);
// Create server with custom configuration using builder pattern
let mut server = Server::builder()
.openapi_spec(openapi_json)
.base_url(base_url)
.default_headers(headers)
.tag_filter(Some(vec!["user".to_string(), "pets".to_string()]))
.build();
// Parse specification and generate tools
server.load_openapi_spec()?;
// Get tool information
println!("Generated {} tools", server.tool_count());
println!("Tool stats: {}", server.get_tool_stats());
Ok(())
}
# Basic usage with Petstore API
rmcp-openapi-server https://petstore.swagger.io/v2/swagger.json
# See all available options
rmcp-openapi-server --help
The server exposes a StreamableHttp endpoint for MCP clients by default.
If you enable the deprecated transport-sse
feature, an SSE endpoint is also available:
http://localhost:8080/sse
Add to your Claude Desktop MCP configuration:
{
"servers": {
"petstore-api": {
"command": "rmcp-openapi-server",
"args": ["https://petstore.swagger.io/v2/swagger.json", "--port", "8080"]
}
}
}
Note: This example uses the deprecated SSE transport. Enable the transport-sse
feature to use this.
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { SseClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
const client = new Client(
{
name: "my-client",
version: "1.0.0"
},
{
capabilities: {}
}
);
const transport = new SseClientTransport(
new URL("http://localhost:8080/sse")
);
await client.connect(transport);
// List available tools
const tools = await client.listTools();
console.log("Available tools:", tools.tools.map(t => t.name));
// Call a tool
const result = await client.callTool({
name: "getPetById",
arguments: { petId: 123 }
});
The server automatically generates MCP tools for each OpenAPI operation:
operationId
or generates from HTTP method + pathsummary
and description
fieldsExample generated tools for Petstore API:
addPet
: Add a new pet to the storefindPetsByStatus
: Find pets by statusgetPetById
: Find pet by IDupdatePet
: Update an existing petdeletePet
: Delete a petThe server now generates output schemas for all tools based on OpenAPI response definitions. This enables:
structured_content
{
"status": 200, // HTTP status code
"body": { // Actual response data
"id": 123,
"name": "Fluffy",
"status": "available"
}
}
This wrapper ensures:
Example output schema for getPetById
:
{
"type": "object",
"properties": {
"status": {
"type": "integer",
"description": "HTTP status code"
},
"body": {
"type": "object",
"properties": {
"id": { "type": "integer", "format": "int64" },
"name": { "type": "string" },
"status": { "type": "string", "enum": ["available", "pending", "sold"] }
}
}
},
"required": ["status", "body"]
}
The library distinguishes between two types of errors:
These occur before tool execution and are returned as MCP protocol errors:
These occur during tool execution and are returned as structured content in the tool response:
For tools with output schemas, execution errors are wrapped in the standard response structure:
{
"status": 404,
"body": {
"error": {
"type": "http-error",
"status": 404,
"message": "Pet not found"
}
}
}
Validation errors are returned as MCP protocol errors:
{
"code": -32602,
"message": "Validation failed with 1 error",
"data": {
"type": "validation-errors",
"violations": [
{
"type": "invalid-parameter",
"parameter": "pet_id",
"suggestions": ["petId"],
"valid_parameters": ["petId", "status"]
}
]
}
}
The server uses structured logging with the tracing
crate for comprehensive observability and debugging.
Set the log level using the RMCP_OPENAPI_LOG
environment variable:
# Info level (default for normal operation)
RMCP_OPENAPI_LOG=info rmcp-openapi-server https://petstore.swagger.io/v2/swagger.json
# Debug level (detailed operation info)
RMCP_OPENAPI_LOG=debug rmcp-openapi-server https://petstore.swagger.io/v2/swagger.json
# Trace level (very detailed debugging)
RMCP_OPENAPI_LOG=trace rmcp-openapi-server https://petstore.swagger.io/v2/swagger.json
# Or use the --verbose flag for debug level
rmcp-openapi-server --verbose https://petstore.swagger.io/v2/swagger.json
error
: Critical errors that need attentionwarn
: Potential issues or warningsinfo
: Important operational events (server startup, tool registration, HTTP request completion)debug
: General debugging information (parameter extraction, tool lookup)trace
: Very detailed debugging (detailed parameter parsing)Note: Request and response bodies are never logged for security reasons.
Logs include structured fields for easy parsing and filtering:
2025-08-19T10:30:45.123Z INFO rmcp_openapi_server::main: OpenAPI MCP Server starting bind_address="127.0.0.1:8080"
2025-08-19T10:30:45.125Z INFO rmcp_openapi::server: Loaded tools from OpenAPI spec tool_count=12
2025-08-19T10:30:45.130Z INFO http_request{tool_name="getPetById" method="GET" path="/pet/{petId}"}: rmcp_openapi::http_client: HTTP request completed status=200 elapsed_ms=45
You can control logging for specific modules:
# Only HTTP client debug logs
RMCP_OPENAPI_LOG=rmcp_openapi::http_client=debug rmcp-openapi-server spec.json
# Only server info logs, everything else warn
RMCP_OPENAPI_LOG=warn,rmcp_openapi::server=info rmcp-openapi-server spec.json
# Debug parameter extraction and tool generation
RMCP_OPENAPI_LOG=info,rmcp_openapi::tool_generator=debug rmcp-openapi-server spec.json
See the examples/
directory for usage examples:
petstore.sh
: Demonstrates server usage with the Swagger Petstore API# Run all tests
cargo test
# Run with live API testing
RMCP_TEST_LIVE_API=true cargo test
# Run specific integration tests
cargo test test_http_integration
MIT License - see LICENSE file for details.