Skip to main content
Glama

Proto Server

by umuterturk
RECURSIVE_RESOLUTION.md8.12 kB
# Recursive Type Resolution ## Problem When AI agents query proto definitions, they often need to understand the complete structure including all nested types. Without recursive resolution, this requires multiple round trips: 1. Call `get_service_definition("UserService")` → Get RPC methods 2. See request type is `CreateUserRequest` → Call `get_message_definition("CreateUserRequest")` 3. See field type is `UserRole` → Call `get_message_definition("UserRole")` 4. ... and so on for every nested type **Result:** 10+ round trips for a simple service, causing latency and inefficiency. ## Solution The MCP Proto Server now **automatically resolves all nested types recursively** in a single response. ### How It Works When you call `get_service_definition` or `get_message_definition`, the server: 1. **Starts with the requested definition** (service or message) 2. **Identifies all referenced types** (request/response types, field types) 3. **Recursively resolves each type** up to `max_depth` levels 4. **Detects cycles** to prevent infinite loops 5. **Returns everything in one JSON response** ## Features ### ✅ Automatic by Default Type resolution is **enabled by default** with `resolve_types=true`. ### ✅ Cycle Detection Prevents infinite loops from circular type references. ### ✅ Depth Control Configure `max_depth` (default: 10) to control how deep to recurse. ### ✅ Context-Aware Resolution Resolves types considering package context (handles both simple and qualified names). ### ✅ Preserves All Metadata Includes comments, field numbers, labels, and file paths for all resolved types. ## API ### get_service_definition ```json { "name": "UserService", "resolve_types": true, // default: true "max_depth": 10 // default: 10 } ``` **Response Structure:** ```json { "name": "UserService", "full_name": "api.v1.UserService", "comment": "User service handles...", "rpcs": [ { "name": "CreateUser", "request_type": "CreateUserRequest", "response_type": "CreateUserResponse", ... } ], "resolved_types": { "CreateUserRequest": { "kind": "message", "name": "CreateUserRequest", "full_name": "api.v1.CreateUserRequest", "fields": [...], "comment": "..." }, "CreateUserResponse": { "kind": "message", ... }, "UserRole": { "kind": "enum", "values": [...] }, "User": { "kind": "message", ... } } } ``` ### get_message_definition ```json { "name": "CreateUserRequest", "resolve_types": true, "max_depth": 10 } ``` **Response Structure:** ```json { "name": "CreateUserRequest", "full_name": "api.v1.CreateUserRequest", "fields": [ { "name": "role", "type": "UserRole", ... } ], "resolved_types": { "UserRole": { "kind": "enum", "name": "UserRole", "values": [...] } } } ``` ## Performance ### Test Results (2,093 proto files, 5,500 messages, 374 services) | Metric | Value | |--------|-------| | Resolution time | ~6ms per service | | Types resolved | 8-12 per service (avg) | | Response size | ~9 KB (compressed JSON) | | Efficiency gain | **8-11x fewer round trips** | ### Example: UserService **Without Resolution:** - 1 call for service → 5 RPCs - 10 calls for request/response messages - 4 calls for nested types - **Total: 15 round trips** 🐌 **With Resolution:** - 1 call gets everything - **Total: 1 round trip** 🚀 **Efficiency:** 15x faster! ## Use Cases ### 1. Service Exploration ``` AI: "Show me the UserService" ``` → Gets service + all 12 request/response/nested types in one call ### 2. Message Understanding ``` AI: "What's the structure of CreateUserRequest?" ``` → Gets message + UserRole enum + any nested types in one call ### 3. Code Generation ``` AI: "Generate a client for AuthService" ``` → Gets complete service definition with all types needed for generation ### 4. API Documentation ``` AI: "Document the ProductService API" ``` → Gets everything needed to write complete documentation ## Configuration ### Disable Resolution (if needed) ```json { "name": "UserService", "resolve_types": false } ``` Returns only the immediate definition without nested types. ### Control Depth ```json { "name": "UserService", "max_depth": 3 } ``` Limits recursion to 3 levels deep (useful for very deeply nested structures). ## Implementation Details ### Type Resolution Algorithm ```python def resolve_types(message, max_depth, visited): if max_depth <= 0: return {} resolved = {} for field in message.fields: if field.type in PRIMITIVES: continue # Skip primitives if field.type in visited: continue # Already resolved (cycle detection) visited.add(field.type) # Resolve as message or enum nested = find_type(field.type, message.package) if nested: resolved[field.type] = nested # Recurse resolved.update(resolve_types(nested, max_depth - 1, visited)) return resolved ``` ### Cycle Detection The algorithm tracks visited types in a set. If a type is encountered twice, it's skipped to prevent infinite loops. Example cycle: ```protobuf message Node { Node parent = 1; // Circular reference repeated Node children = 2; } ``` The resolver detects `Node` was already visited and stops recursion. ### Package Context Resolution Types are resolved considering the package context: 1. Try exact match: `UserRole` 2. Try with package: `api.v1.UserRole` 3. Try partial match: `*.UserRole` This handles both simple names and fully qualified names. ## Benefits for AI Agents ### Before (Multiple Round Trips) ``` User: "Show me UserService" AI: Call get_service_definition() AI: See CreateUserRequest, call get_message() AI: See UserRole, call get_message() AI: See User, call get_message() AI: ... (12+ calls total) AI: "Here's the service..." ``` ⏱️ ~500ms latency (50ms per call × 10 calls) ### After (Single Call) ``` User: "Show me UserService" AI: Call get_service_definition() → Gets EVERYTHING AI: "Here's the service..." ``` ⏱️ ~50ms latency (single call) **10x latency improvement!** ## Comparison | Aspect | Without Resolution | With Resolution | |--------|-------------------|-----------------| | API calls | 10-15 per service | 1 per service | | Latency | ~500ms | ~50ms | | Bandwidth | 15 small requests | 1 medium request | | Complexity | Manual type tracking | Automatic | | Error rate | Higher (more calls) | Lower (one call) | | User experience | Slow, chatty | Fast, efficient | ## Advanced Examples ### Deeply Nested Types ```protobuf message CreateOrderRequest { Order order = 1; } message Order { Customer customer = 1; repeated LineItem items = 2; Payment payment = 3; } message Customer { Address address = 1; PaymentMethod payment_method = 2; } // ... and so on ``` **Single call resolves:** - CreateOrderRequest - Order - Customer - Address - PaymentMethod - LineItem - Payment - ... (all nested types up to max_depth) ### Service with Streaming ```protobuf service ChatService { rpc StreamMessages(stream ChatMessage) returns (stream ChatMessage); } ``` **Resolution includes:** - ChatService - ChatMessage (request type) - All fields in ChatMessage - Any enums/nested messages in ChatMessage ## Testing Run the test suite: ```bash python test_recursive_resolution.py ``` Output shows: - ✅ Recursive resolution working - ✅ Cycle detection working - ✅ Depth control working - ✅ 8-11x efficiency improvement - ✅ Sub-10ms resolution time ## Conclusion Recursive type resolution makes the MCP Proto Server **dramatically more efficient** for AI agents by: 1. **Reducing round trips** from 10-15 to 1 2. **Cutting latency** by 10x 3. **Simplifying client logic** (no manual type tracking) 4. **Improving reliability** (fewer calls = fewer failure points) The feature is **enabled by default** and works transparently for all clients.

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/umuterturk/mcp-proto'

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