Skip to main content
Glama

OpenAPI Search MCP Server

by Sheepion
CLAUDE.md12.7 kB
# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview This is an OpenAPI Search MCP Server - a Model Context Protocol server that loads, parses, and provides query tools for OpenAPI/Swagger documents. It uses a modular, layered architecture with clear separation of concerns. ## Environment Setup ```bash # Create and activate conda environment conda create -n openapi-search-mcp python=3.12 -y conda activate openapi-search-mcp # Install dependencies pip install -r requirements.txt ``` ## Running the Server ### STDIO Mode (for Claude Desktop integration) ```bash conda activate openapi-search-mcp python main.py ``` Edit `main.py` line 52 to use: ```python mcp.run() # STDIO mode ``` ### HTTP Mode (standalone server) ```bash conda activate openapi-search-mcp python main.py ``` Edit `main.py` line 52 to use: ```python mcp.run(transport="streamable-http", port=DEFAULT_HTTP_PORT) # HTTP mode (default) ``` ## Architecture ### Project Structure ``` openapi-search-mcp/ ├── main.py # Entry point (~50 lines) ├── requirements.txt ├── README.zh.md ├── CLAUDE.md ├── DESIGN.md ├── main.py.backup # Original monolithic version ├── src/ # Source code │ ├── __init__.py │ ├── config.py # Configuration constants │ ├── storage.py # Data storage layer │ ├── models/ # Data models │ │ ├── __init__.py │ │ └── openapi_document.py # Pydantic model for OpenAPI docs │ ├── loaders/ # Document loaders │ │ ├── __init__.py │ │ └── openapi_loader.py # URL loading and format detection │ ├── indexers/ # Index builders │ │ ├── __init__.py │ │ └── operation_indexer.py # operationId and tag indexing │ ├── services/ # Business logic layer │ │ ├── __init__.py │ │ ├── api_service.py # API loading and listing │ │ ├── path_service.py # Path queries │ │ ├── schema_service.py # Schema and auth queries │ │ ├── search_service.py # Endpoint search │ │ └── tag_service.py # Tag queries │ └── tools/ # MCP tool definitions │ ├── __init__.py │ ├── loading_tools.py # load_openapi, list_apis │ ├── query_tools.py # path, operation, schema queries │ └── search_tools.py # search, tag queries └── tests/ └── __init__.py ``` ### Layered Architecture The codebase follows a clean layered architecture: ``` ┌─────────────────────────────────────┐ │ main.py (Entry) │ → Application initialization ├─────────────────────────────────────┤ │ Tools Layer (src/tools/) │ → MCP tool definitions ├─────────────────────────────────────┤ │ Services Layer (src/services/) │ → Business logic ├─────────────────────────────────────┤ │ Storage Layer (src/storage.py) │ → Data access ├─────────────────────────────────────┤ │ Loaders/Indexers (src/loaders/, │ → Utilities │ src/indexers/) │ ├─────────────────────────────────────┤ │ Models (src/models/) │ → Data structures ├─────────────────────────────────────┤ │ Config (src/config.py) │ → Constants └─────────────────────────────────────┘ ``` ### Module Responsibilities #### 1. Configuration Layer (`src/config.py`) - **Purpose**: Centralized configuration constants - **Contents**: - HTTP method list (`HTTP_METHODS`) - Timeout settings (`HTTP_TIMEOUT`) - Error message templates (e.g., `ERROR_API_NOT_FOUND`) - **Design**: Eliminates magic strings and duplicate constants #### 2. Data Models Layer (`src/models/`) - **Purpose**: Type-safe data structures using Pydantic - **Key Model**: `OpenAPIDocument` - Represents parsed and indexed OpenAPI document - Provides validation and serialization - Factory method: `from_raw_document()` - **Benefits**: Type safety, auto-validation, clear structure #### 3. Storage Layer (`src/storage.py`) - **Purpose**: Unified in-memory data access - **Class**: `OpenAPIStorage` - **Methods**: - `add()`: Store a document - `get()`: Retrieve a document - `exists()`: Check if document exists - `list_all()`: Get all documents - `get_or_error()`: Get document or return formatted error - **Design**: Encapsulates storage logic, provides consistent error handling #### 4. Loaders Layer (`src/loaders/`) - **Purpose**: Load and parse OpenAPI documents from URLs - **Class**: `OpenAPILoader` - **Methods**: - `load_from_url()`: Fetch document via HTTP - `_parse_response()`: Auto-detect JSON/YAML format - `validate_document()`: Validate OpenAPI structure - **Features**: - Content-Type detection - URL extension detection (.json, .yaml, .yml) - Fallback format detection (try JSON, then YAML) #### 5. Indexers Layer (`src/indexers/`) - **Purpose**: Build indexes for fast lookups - **Class**: `OperationIndexer` - **Methods**: - `build_operation_index()`: Create operationId → {path, method} mapping - `extract_tags()`: Extract tags from document - **Strategy**: Prefers root-level tags, falls back to extracting from operations #### 6. Services Layer (`src/services/`) Each service handles a specific domain of business logic: - **`ApiService`**: Load and manage APIs - `load_openapi()`: Orchestrate loading, validation, indexing, storage - `list_apis()`: List all loaded APIs with metadata - **`PathService`**: Query paths and operations - `get_path_details()`: Get all methods for a path - `list_all_paths()`: List all paths - `get_operation_by_id()`: Fast operationId lookup - **`SchemaService`**: Query schemas and auth - `get_schema_details()`: Get schema from components/schemas - `get_auth_info()`: Get securitySchemes and global security - **`SearchService`**: Search endpoints - `search_endpoints()`: Multi-criteria search (keyword, method, tag) - **`TagService`**: Query tags - `list_tags()`: List all tags - `get_endpoints_by_tag()`: Get endpoints by tag **Design Principle**: All services receive `OpenAPIStorage` via dependency injection #### 7. Tools Layer (`src/tools/`) MCP tool registration functions that wire services to FastMCP: - **`loading_tools.py`**: `load_openapi`, `list_apis` - **`query_tools.py`**: `get_path_details`, `list_all_paths`, `get_operation_by_id`, `get_schema_details`, `get_auth_info` - **`search_tools.py`**: `search_endpoints`, `list_tags`, `get_endpoints_by_tag` **Pattern**: Each registration function receives `mcp` and required services, defines tool functions inline using `@mcp.tool()` decorator #### 8. Entry Point (`main.py`) - **Purpose**: Application initialization and startup - **Function**: `create_app()` 1. Create FastMCP instance 2. Initialize storage layer 3. Initialize service layer (with dependency injection) 4. Register all tools 5. Return configured MCP instance - **Design**: Clean separation, easily testable ## Tool Categories ### Loading & Discovery - `load_openapi(name, url)` - Load and parse OpenAPI document from URL - `list_apis()` - List all loaded APIs with metadata ### Path Querying - `list_all_paths(name)` - Get all paths and their HTTP methods - `get_path_details(name, path)` - Get complete documentation for a specific path - `get_operation_by_id(name, operation_id)` - Fast lookup by operationId ### Search & Filter - `search_endpoints(name, keyword?, method?, tag?)` - Multi-criteria search - `list_tags(name)` - List all tags in the API - `get_endpoints_by_tag(name, tag)` - Get all endpoints with specific tag ### Schema & Auth - `get_schema_details(name, schema_name)` - Get data model from components/schemas - `get_auth_info(name)` - Get securitySchemes and global security config ## Typical Workflow Patterns ### Exploring a New API ``` 1. load_openapi(name="petstore", url="...") 2. list_tags(name="petstore") 3. get_endpoints_by_tag(name="petstore", tag="pets") 4. get_path_details(name="petstore", path="/pets/{petId}") 5. get_schema_details(name="petstore", schema_name="Pet") ``` ### Finding Specific Endpoints ``` 1. search_endpoints(name="api", keyword="user", method="POST") 2. get_operation_by_id(name="api", operation_id="createUser") 3. get_path_details(name="api", path="/users") ``` ### Understanding Authentication ``` 1. get_auth_info(name="api") # Returns securitySchemes + global security ``` ## Key Implementation Details ### 1. Dependency Injection Pattern Services receive their dependencies via constructor: ```python storage = OpenAPIStorage() api_service = ApiService(storage) # Inject storage path_service = PathService(storage) # Inject storage ``` ### 2. Unified Error Handling `OpenAPIStorage.get_or_error()` provides consistent error responses: ```python doc_data, error = self.storage.get_or_error(name) if error: return error # Already formatted ``` ### 3. Format Detection (src/loaders/openapi_loader.py) Priority order: 1. Content-Type header (`json` or `yaml`) 2. URL file extension (`.json`, `.yaml`, `.yml`) 3. Try JSON parsing first 4. Fall back to YAML parsing ### 4. Operation Indexing (src/indexers/operation_indexer.py) Builds reverse index for O(1) operationId lookups: ```python { "getUserById": {"path": "/users/{id}", "method": "get"} } ``` ### 5. Tag Extraction (src/indexers/operation_indexer.py) 1. Prefer root-level `tags` array if present 2. Otherwise extract unique tags from all operations 3. Return sorted list of tag objects ## Testing Use public OpenAPI documents for testing: ```python # Load Swagger Petstore load_openapi(name="petstore", url="https://petstore.swagger.io/v2/swagger.json") # Test all tool categories list_apis() list_tags(name="petstore") get_endpoints_by_tag(name="petstore", tag="pet") search_endpoints(name="petstore", keyword="pet", method="get") get_operation_by_id(name="petstore", operation_id="getPetById") get_path_details(name="petstore", path="/pet/{petId}") get_schema_details(name="petstore", schema_name="Pet") get_auth_info(name="petstore") ``` ## Supported Formats - OpenAPI 3.0.x - OpenAPI 3.1.x - Swagger 2.0 Supports both JSON and YAML formats via auto-detection. ## Important Notes - Documents are **only stored in memory** - server restart requires reloading - Loading a document with an existing name **overwrites** the previous one - The server is **stateful** when running in HTTP mode (stateless_http=False) - All HTTP method checks are case-insensitive (normalized to lowercase) - Path parameters use OpenAPI syntax: `/users/{id}` not `/users/:id` ## Modifying the Codebase ### Adding a New Tool 1. Identify which service should handle the logic 2. Add method to appropriate service in `src/services/` 3. Add tool definition in appropriate tool file in `src/tools/` 4. Tool will be auto-registered via `create_app()` in `main.py` ### Adding a New Service 1. Create service file in `src/services/` 2. Implement service class with `__init__(self, storage: OpenAPIStorage)` 3. Import in `main.py` 4. Instantiate in `create_app()` with storage injection 5. Pass to tool registration functions ### Adding Configuration 1. Add constant to `src/config.py` 2. Import where needed: `from src.config import CONSTANT_NAME` ## Benefits of This Architecture 1. **Maintainability**: Clear separation of concerns, easy to locate code 2. **Testability**: Each layer can be unit tested independently 3. **Extensibility**: Add features without modifying existing code 4. **Reusability**: No duplicate code (constants, error handling, etc.) 5. **Type Safety**: Pydantic models + complete type annotations 6. **Readability**: Small, focused files instead of one 571-line file

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/Sheepion/openapi-search-mcp'

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