Skip to main content
Glama

FastAPI OpenAPI MCP Server

by jason-chang
endpoints.py4.66 kB
""" Endpoints Resources 提供 API 端点相关的 Resources。 """ import json from typing import Any, ClassVar from openapi_mcp.resources.base import BaseResource class EndpointsListResource(BaseResource): """端点列表 Resource URI: openapi://endpoints 提供所有 API 端点的概要信息。 Attributes: uri_template: URI 模板 'openapi://endpoints' name: Resource 名称 description: Resource 描述 """ uri_template: ClassVar[str] = 'openapi://endpoints' name: ClassVar[str] = 'API Endpoints List' description: ClassVar[str] = '所有 API 端点的概要信息列表' async def read(self, uri: str) -> str: """读取端点列表 Args: uri: 请求的 URI Returns: JSON 格式的端点列表字符串 Raises: ValueError: 当 URI 不匹配时 RuntimeError: 当无法获取 OpenAPI spec 时 """ if not self.matches_uri(uri): raise ValueError(f'URI {uri} 不匹配模板 {self.uri_template}') try: spec = await self.get_openapi_spec() endpoints = self._extract_endpoints(spec) return json.dumps(endpoints, indent=2, ensure_ascii=False) except Exception as e: raise RuntimeError(f'无法获取端点列表: {e}') from e def _extract_endpoints(self, spec: dict[str, Any]) -> list[dict[str, Any]]: """从 OpenAPI spec 中提取端点信息 Args: spec: OpenAPI specification Returns: 端点信息列表 """ endpoints = [] paths = spec.get('paths', {}) for path, path_item in paths.items(): if not isinstance(path_item, dict): continue for method, operation in path_item.items(): if method.upper() in [ 'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS', ] and isinstance(operation, dict): endpoint = { 'path': path, 'method': method.upper(), 'operationId': operation.get('operationId'), 'summary': operation.get('summary', ''), 'description': operation.get('description', ''), 'tags': operation.get('tags', []), } endpoints.append(endpoint) return endpoints class EndpointResource(BaseResource): """具体端点 Resource URI: openapi://endpoints/{path} 提供特定端点的详细信息。 Attributes: uri_template: URI 模板 'openapi://endpoints/{path}' name: Resource 名称 description: Resource 描述 """ uri_template: ClassVar[str] = 'openapi://endpoints/{path}' name: ClassVar[str] = 'API Endpoint Details' description: ClassVar[str] = '特定 API 端点的详细信息' async def read(self, uri: str) -> str: """读取端点详情 Args: uri: 请求的 URI Returns: JSON 格式的端点详情字符串 Raises: ValueError: 当 URI 不匹配或端点不存在时 RuntimeError: 当无法获取 OpenAPI spec 时 """ if not self.matches_uri(uri): raise ValueError(f'URI {uri} 不匹配模板 {self.uri_template}') params = self.extract_params(uri) path = params.get('path', '') if not path: raise ValueError('路径参数不能为空') # 确保路径以 / 开头 if not path.startswith('/'): path = '/' + path try: spec = await self.get_openapi_spec() endpoint = self._extract_endpoint(spec, path) if not endpoint: raise ValueError(f'端点不存在: {path}') return json.dumps(endpoint, indent=2, ensure_ascii=False) except Exception as e: if isinstance(e, (ValueError, RuntimeError)): raise raise RuntimeError(f'无法获取端点详情: {e}') from e def _extract_endpoint( self, spec: dict[str, Any], path: str ) -> dict[str, Any] | None: """从 OpenAPI spec 中提取特定端点信息 Args: spec: OpenAPI specification path: 端点路径 Returns: 端点详细信息,如果不存在返回 None """ paths = spec.get('paths', {}) path_item = paths.get(path) if not path_item: return None # 构建端点详细信息 endpoint = { 'path': path, 'methods': {}, 'parameters': path_item.get('parameters', []), } for method, operation in path_item.items(): if method.upper() in [ 'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS', ]: endpoint['methods'][method.upper()] = { 'operationId': operation.get('operationId'), 'summary': operation.get('summary', ''), 'description': operation.get('description', ''), 'tags': operation.get('tags', []), 'parameters': operation.get('parameters', []), 'requestBody': operation.get('requestBody'), 'responses': operation.get('responses', {}), 'security': operation.get('security'), } return endpoint

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/jason-chang/fastapi-openapi-mcp'

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