rmcp-openapi 0.5.1

Expose OpenAPI definition endpoints as MCP tools
Documentation

rmcp-openapi

Expose OpenAPI definition endpoints as MCP tools using the official Rust SDK for the Model Context Protocol.

Overview

This project provides a bridge between OpenAPI specifications and the Model Context Protocol (MCP), allowing you to automatically generate MCP tools from OpenAPI definitions. This enables AI assistants to interact with REST APIs through a standardized interface.

Features

  • Automatic Tool Generation: Parse OpenAPI specifications and automatically generate MCP tools for all operations
  • Flexible Spec Loading: Support for both URL-based and local file OpenAPI specifications
  • HTTP Client Integration: Built-in HTTP client with configurable base URLs and request handling
  • Parameter Mapping: Intelligent mapping of OpenAPI parameters (path, query, body) to MCP tool parameters
  • Output Schema Support: Automatic generation of output schemas from OpenAPI response definitions
  • Structured Content: Returns parsed JSON responses as structured content when output schemas are defined
  • Dual Usage Modes: Use as a standalone MCP server or integrate as a Rust library
  • Transport Support: SSE (Server-Sent Events) transport for MCP communication
  • Comprehensive Testing: Includes integration tests with JavaScript and Python MCP clients
  • Built with Official SDK: Uses the official Rust MCP SDK for reliable protocol compliance

Installation

Install Binary

cargo install rmcp-openapi

Build from Source

cargo build --release

As a Library

Add to your Cargo.toml:

[dependencies]
rmcp-openapi = "0.1.0"

Usage as a Library

Basic Example

use rmcp_openapi::{OpenApiServer, OpenApiSpecLocation};
use url::Url;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create server from OpenAPI spec URL
    let spec_location = OpenApiSpecLocation::from("https://petstore.swagger.io/v2/swagger.json");
    let mut server = OpenApiServer::new(spec_location);
    
    // Load the OpenAPI specification
    server.load_openapi_spec().await?;
    
    // Get information about generated tools
    println!("Generated {} tools", server.tool_count());
    println!("Available tools: {}", server.get_tool_names().join(", "));
    
    Ok(())
}

Advanced Example with Custom Base URL

use rmcp_openapi::{OpenApiServer, OpenApiSpecLocation, HttpClient};
use url::Url;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let spec_location = OpenApiSpecLocation::from("./api-spec.json");
    let base_url = Url::parse("https://api.example.com")?;
    
    // Create server with custom base URL
    let mut server = OpenApiServer::with_base_url(spec_location, base_url)?;
    server.load_openapi_spec().await?;
    
    // Validate the registry
    server.validate_registry()?;
    
    // Get tool metadata
    if let Some(tool) = server.registry.get_tool("getUserById") {
        println!("Tool: {} - {}", tool.name, tool.description);
        
        // Check if tool has output schema
        if let Some(output_schema) = &tool.output_schema {
            println!("Output schema: {}", serde_json::to_string_pretty(output_schema)?);
        }
    }
    
    Ok(())
}

Usage as an MCP Server

Basic Usage

# Basic usage with Petstore API
rmcp-openapi-server https://petstore.swagger.io/v2/swagger.json

# See all available options
rmcp-openapi-server --help

MCP Client Connection

The server exposes an SSE endpoint for MCP clients:

http://localhost:8080/sse

Example with Claude Desktop

Add to your Claude Desktop MCP configuration:

{
  "servers": {
    "petstore-api": {
      "command": "rmcp-openapi-server",
      "args": ["https://petstore.swagger.io/v2/swagger.json", "--port", "8080"]
    }
  }
}

Example with JavaScript MCP Client

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 }
});

Generated Tools

The server automatically generates MCP tools for each OpenAPI operation:

  • Tool Names: Uses operationId or generates from HTTP method + path
  • Parameters: Maps OpenAPI parameters (path, query, body) to tool parameters
  • Descriptions: Combines OpenAPI summary and description fields
  • Validation: Includes parameter schemas for validation
  • Output Schemas: Automatically generated from OpenAPI response definitions

Example generated tools for Petstore API:

  • addPet: Add a new pet to the store
  • findPetsByStatus: Find pets by status
  • getPetById: Find pet by ID
  • updatePet: Update an existing pet
  • deletePet: Delete a pet

Output Schema Support

The server now generates output schemas for all tools based on OpenAPI response definitions. This enables:

  1. Type-Safe Responses: MCP clients can validate response data against the schema
  2. Structured Content: When an output schema is defined, the server returns parsed JSON as structured_content
  3. Consistent Format: All responses are wrapped in a standard structure:
{
  "status": 200,           // HTTP status code
  "body": {                // Actual response data
    "id": 123,
    "name": "Fluffy",
    "status": "available"
  }
}

This wrapper ensures:

  • All output schemas are objects (required by MCP)
  • HTTP status codes are preserved
  • Both success and error responses follow the same structure
  • Clients can uniformly handle all responses

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"]
}

Error Handling

The library distinguishes between two types of errors:

Validation Errors (MCP Protocol Errors)

These occur before tool execution and are returned as MCP protocol errors:

  • ToolNotFound: Requested tool doesn't exist (includes suggestions for similar tool names)
  • InvalidParameters: Parameter validation failed (unknown names, missing required, constraint violations)
  • RequestConstructionError: Failed to construct the HTTP request

Execution Errors (Tool Output Errors)

These occur during tool execution and are returned as structured content in the tool response:

  • HttpError: HTTP error response from the API (4xx, 5xx status codes)
  • NetworkError: Network/connection failures (timeout, DNS, connection refused)
  • ResponseParsingError: Failed to parse the response

Error Response Format

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"]
      }
    ]
  }
}

Examples

See the examples/ directory for usage examples:

  • petstore.sh: Demonstrates server usage with the Swagger Petstore API

Testing

# 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

License

MIT License - see LICENSE file for details.