Skip to main content
Glama
alamkanak

FastAPI MCP OpenAPI

by alamkanak
test_mcp_tool_execution.py7.24 kB
""" Tests for actual MCP tool execution to ensure coverage of registered functions. """ import json from fastapi.testclient import TestClient from fastapi_mcp_openapi import FastAPIMCPOpenAPI class TestMCPToolExecution: """Test actual execution of registered MCP tools.""" def test_actual_list_endpoints_tool_execution(self, basic_app): """Test actual execution of the registered listEndpoints tool via HTTP.""" FastAPIMCPOpenAPI(basic_app) client = TestClient(basic_app) # Call the actual tool via MCP protocol payload = { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "listEndpoints", "arguments": {}}, } response = client.post("/mcp", json=payload) assert response.status_code == 200 result = response.json() assert result["jsonrpc"] == "2.0" assert result["id"] == 1 assert "result" in result # Parse the actual tool output content = result["result"]["content"][0]["text"] response_data = json.loads(content) endpoints = response_data["endpoints"] # Verify the endpoints are correct (should have basic_app endpoints) assert len(endpoints) == 3 # root, get_user, create_user endpoint_paths = [e["path"] for e in endpoints] assert "/" in endpoint_paths assert "/users/{user_id}" in endpoint_paths assert "/users/" in endpoint_paths # Verify structure of each endpoint for endpoint in endpoints: assert "path" in endpoint assert "methods" in endpoint assert "name" in endpoint assert "summary" in endpoint assert isinstance(endpoint["methods"], list) def test_actual_list_endpoints_with_no_docstring(self, empty_app): """Test listEndpoints tool with endpoints that have no docstring.""" @empty_app.get("/no-doc") async def no_doc_endpoint(): return {"message": "No docstring"} FastAPIMCPOpenAPI(empty_app) client = TestClient(empty_app) payload = { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "listEndpoints", "arguments": {}}, } response = client.post("/mcp", json=payload) assert response.status_code == 200 content = response.json()["result"]["content"][0]["text"] response_data = json.loads(content) endpoints = response_data["endpoints"] # Should have the no-doc endpoint no_doc_ep = next(e for e in endpoints if e["path"] == "/no-doc") assert no_doc_ep["summary"] is None def test_actual_list_endpoints_excludes_mcp_health(self, basic_app): """Test that actual tool excludes MCP endpoints and health endpoint.""" FastAPIMCPOpenAPI(basic_app) client = TestClient(basic_app) payload = { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "listEndpoints", "arguments": {}}, } response = client.post("/mcp", json=payload) content = response.json()["result"]["content"][0]["text"] response_data = json.loads(content) endpoints = response_data["endpoints"] # Verify no MCP paths are included mcp_paths = [e["path"] for e in endpoints if e["path"].startswith("/mcp")] assert len(mcp_paths) == 0 # Verify no health endpoints are included (MCP creates these) health_paths = [ e["path"] for e in endpoints if e["path"] == "/health" and e["name"] == "health_endpoint" ] assert len(health_paths) == 0 def test_actual_list_endpoints_with_custom_mount(self, basic_app): """Test listEndpoints tool with custom mount path.""" custom_mount = "/custom-mcp" FastAPIMCPOpenAPI(basic_app, mount_path=custom_mount) client = TestClient(basic_app) payload = { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "listEndpoints", "arguments": {}}, } response = client.post(custom_mount, json=payload) content = response.json()["result"]["content"][0]["text"] response_data = json.loads(content) endpoints = response_data["endpoints"] # Should exclude custom mount path custom_paths = [ e["path"] for e in endpoints if e["path"].startswith(custom_mount) ] assert len(custom_paths) == 0 # Should still include user endpoints user_paths = [e["path"] for e in endpoints if e["path"].startswith("/users")] assert len(user_paths) == 2 def test_actual_get_endpoint_docs_tool_execution(self, basic_app): """Test actual execution of the registered getEndpointDocs tool.""" FastAPIMCPOpenAPI(basic_app) client = TestClient(basic_app) payload = { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "getEndpointDocs", "arguments": {"endpoint_path": "/users/{user_id}", "method": "GET"}, }, } response = client.post("/mcp", json=payload) assert response.status_code == 200 result = response.json() content = result["result"]["content"][0]["text"] docs = json.loads(content) assert docs["path"] == "/users/{user_id}" assert docs["method"] == "GET" assert "operation" in docs assert "parameters" in docs["operation"] def test_complex_app_endpoints_coverage(self, complex_app): """Test listEndpoints with complex app to cover various endpoint types.""" FastAPIMCPOpenAPI(complex_app) client = TestClient(complex_app) payload = { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "listEndpoints", "arguments": {}}, } response = client.post("/mcp", json=payload) content = response.json()["result"]["content"][0]["text"] response_data = json.loads(content) endpoints = response_data["endpoints"] # Complex app should have many endpoints assert len(endpoints) >= 5 # Verify different HTTP methods are captured all_methods = set() for endpoint in endpoints: all_methods.update(endpoint["methods"]) # Should have various HTTP methods assert "GET" in all_methods assert "POST" in all_methods assert "PUT" in all_methods assert "DELETE" in all_methods # Verify summaries are extracted from docstrings endpoints_with_summaries = [e for e in endpoints if e["summary"] is not None] assert len(endpoints_with_summaries) > 0 # Check specific endpoints exist endpoint_paths = [e["path"] for e in endpoints] assert "/" in endpoint_paths assert "/users/{user_id}" in endpoint_paths assert "/users/" in endpoint_paths

Latest Blog Posts

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

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