Skip to main content
Glama

OpenAPI to Model Context Protocol (MCP)

# SPDX-License-Identifier: MIT # Copyright (c) 2025 Roger Gujord # https://github.com/gujord/OpenAPI-MCP import re from typing import Dict, Any class SchemaConverter: """Converts OpenAPI schemas to MCP-compatible resource schemas.""" @staticmethod def convert_openapi_to_mcp_schema(schema: Dict[str, Any]) -> Dict[str, Any]: """Convert OpenAPI schema to MCP resource schema.""" if not schema: return {"type": "object", "properties": {}} return SchemaConverter._convert_schema_recursive(schema) @staticmethod def _convert_schema_recursive(schema: Dict[str, Any]) -> Dict[str, Any]: """Recursively convert schema properties.""" if not isinstance(schema, dict): return {"type": "string", "description": ""} properties = {} required = schema.get("required", []) for prop_name, prop_schema in schema.get("properties", {}).items(): converted_prop = SchemaConverter._convert_property(prop_schema) properties[prop_name] = converted_prop resource_schema = { "type": "object", "properties": properties } if required: resource_schema["required"] = required return resource_schema @staticmethod def _convert_property(prop_schema: Dict[str, Any]) -> Dict[str, Any]: """Convert individual property schema.""" if not isinstance(prop_schema, dict): return {"type": "string", "description": ""} prop_type = prop_schema.get("type", "string") description = prop_schema.get("description", "") if prop_type == "integer": return { "type": "number", "description": description } elif prop_type == "array": items_schema = SchemaConverter._convert_schema_recursive( prop_schema.get("items", {}) ) return { "type": "array", "items": items_schema, "description": description } elif prop_type == "object": nested_schema = SchemaConverter._convert_schema_recursive(prop_schema) nested_schema["description"] = description return nested_schema else: return { "type": prop_type, "description": description } class NameSanitizer: """Handles name sanitization for tools and resources.""" @staticmethod def sanitize_name(name: str, max_length: int = 64) -> str: """Sanitize name to be safe for MCP usage.""" # Replace non-alphanumeric characters with underscores sanitized = re.sub(r"[^a-zA-Z0-9_-]", "_", name) # Ensure it doesn't start with a number if sanitized and sanitized[0].isdigit(): sanitized = f"_{sanitized}" # Truncate to max length return sanitized[:max_length] @staticmethod def sanitize_tool_name(name: str, server_prefix: str = None, max_length: int = 64) -> str: """Sanitize tool name with optional server prefix.""" if server_prefix: prefixed_name = f"{server_prefix}_{name}" return NameSanitizer.sanitize_name(prefixed_name, max_length) return NameSanitizer.sanitize_name(name, max_length) @staticmethod def sanitize_resource_name(name: str, server_prefix: str = None, max_length: int = 64) -> str: """Sanitize resource name with optional server prefix.""" if server_prefix: prefixed_name = f"{server_prefix}_{name}" return NameSanitizer.sanitize_name(prefixed_name, max_length) return NameSanitizer.sanitize_name(name, max_length) class ResourceNameProcessor: """Processes resource names for CRUD operation detection.""" @staticmethod def singularize_resource(resource: str) -> str: """Convert plural resource names to singular form.""" if resource.endswith("ies"): return resource[:-3] + "y" elif resource.endswith("sses"): return resource # Keep as-is for words like "classes" elif resource.endswith("s") and not resource.endswith("ss"): return resource[:-1] return resource

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/gujord/OpenAPI-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server