# Tools Environment Registry The Tools Environment Registry is a comprehensive system for managing and integrating various types of API services and tools. It provides a unified interface for OpenAPI services, TRM (Tool Runtime Manager) tools, and MCP (Model Context Protocol) servers. ## ๐Ÿš€ Quick Start ### Starting the Registry Server ```bash # Start the registry server uv run python -m cuga.backend.tools_env.registry.registry.api_registry_server # Or with custom configuration MCP_SERVERS_FILE=/path/to/your/config.yaml uv run python -m cuga.backend.tools_env.registry.registry.api_registry_server ``` The server will start on `http://127.0.0.1:8001` by default. ### API Endpoints - `GET /applications` - List all registered applications - `GET /applications/{app_name}/apis` - List APIs for a specific application - `GET /apis` - List all APIs across all applications - `POST /functions/call` - Call a specific function/tool - `POST /functions/onboard` - Onboard new tools dynamically ## ๐Ÿ“‹ Configuration The registry supports multiple service types through YAML configuration files. By default, it uses `config/mcp_servers.yaml`. ### Configuration Structure ```yaml # Legacy OpenAPI services services: - service_name: url: "https://api.example.com/openapi.json" description: "Description of the service" type: "openapi" # Optional, inferred from URL include: # Optional: filter specific operations - "operation_id_1" - "operation_id_2" api_overrides: # Optional: customize operations - operation_id: "get_users" description: "Custom description" drop_request_body_parameters: ["internal_param"] drop_query_parameters: ["debug_mode"] # MCP (Model Context Protocol) servers mcpServers: server_name: url: "http://localhost:8000/sse" command: "python" # Optional: for local MCP servers args: ["-m", "my_mcp_server"] # Optional: command arguments # TRM (Tool Runtime Manager) services trmServices: trm_service: url: "http://localhost:9000" tools: ["tool1", "tool2"] auth: type: "Authorization" value: "Bearer your-token" ``` ## ๐Ÿ› ๏ธ Adding Different Types of Services ### 1. OpenAPI Services OpenAPI services are automatically discovered and integrated from their OpenAPI specification. **Example Configuration:** ```yaml services: - digital_sales: url: "https://digitalsales.example.com/openapi.json" description: "Digital Sales API for customer management" include: # Only include specific operations - "getMyAccounts" - "getAccountsTpp" - "getJobRoles" api_overrides: - operation_id: "getAccountsTpp" description: "Retrieve accounts from TPP with enhanced filtering" drop_query_parameters: ["debug", "internal_flag"] ``` **Features:** - Automatic parameter extraction and validation - Response schema parsing - Security scheme detection - Parameter filtering and customization ### 2. MCP (Model Context Protocol) Servers MCP servers provide tools through the Model Context Protocol standard. #### Remote MCP Server ```yaml mcpServers: sales_mcp: url: "http://127.0.0.1:8000/sse" description: "Sales MCP server with customer tools" ``` #### Local MCP Server ```yaml mcpServers: local_tools: command: "python" args: ["-m", "my_local_mcp_server"] description: "Local MCP server with file system tools" ``` #### File System MCP Server Example Here's how to add a file system MCP server: ```yaml mcpServers: filesystem: command: "npx" args: ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/directory"] description: "File system operations MCP server" ``` > **๐Ÿ’ก Best Practice**: When developing custom MCP servers, include response schema information in tool descriptions to work around MCP protocol limitations. See the [MCP Response Schema Representation](#mcp-response-schema-representation) section for implementation details. **Sample File System MCP Server Configuration:** ```yaml # config/mcp_servers_filesystem.yaml mcpServers: # File system server for document management document_fs: command: "npx" args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/documents"] description: "Document management file system server" # File system server for project files project_fs: command: "npx" args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/projects", "--readonly"] description: "Read-only access to project files" # Custom Python file system server custom_fs: command: "python" args: ["-m", "my_fs_server", "--root", "/safe/directory", "--max-file-size", "10MB"] description: "Custom file system server with safety limits" ``` ### 3. TRM (Tool Runtime Manager) Services TRM services provide tools through a runtime management system. ```yaml trmServices: data_tools: url: "http://localhost:9000" tools: ["query_database", "export_data", "generate_report"] auth: type: "Authorization" value: "Bearer your-api-token" description: "Data processing and reporting tools" ``` ## ๐Ÿ“ Sample Configurations ### Complete Sample Configuration ```yaml # config/sample_complete.yaml # OpenAPI Services services: - sales_api: url: "https://sales.example.com/openapi.json" description: "Sales management API" include: ["getAccounts", "createLead", "updateContact"] - inventory_api: url: "https://inventory.example.com/api/docs/openapi.json" description: "Inventory management system" api_overrides: - operation_id: "getProducts" description: "Get products with enhanced filtering" drop_query_parameters: ["internal_debug"] # MCP Servers mcpServers: # Remote MCP server customer_tools: url: "http://customer-tools.example.com:8000/sse" description: "Customer relationship management tools" # Local file system server documents: command: "npx" args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/shared/documents"] description: "Document management system" # Local Python MCP server data_processor: command: "python" args: ["-m", "data_mcp_server", "--config", "config.json"] description: "Data processing and analysis tools" # Git repository server code_repo: command: "npx" args: ["-y", "@modelcontextprotocol/server-git", "/path/to/repo"] description: "Git repository operations" # TRM Services trmServices: analytics: url: "http://analytics.internal:9000" tools: ["run_analysis", "generate_insights", "export_dashboard"] auth: type: "X-API-Key" value: "your-analytics-api-key" description: "Analytics and reporting platform" ``` ### File System MCP Server Samples ```yaml # config/filesystem_samples.yaml mcpServers: # Basic file operations file_manager: command: "npx" args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/workspace"] description: "File management operations" # Read-only document access docs_readonly: command: "npx" args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/documents", "--readonly"] description: "Read-only access to documents" # Multiple directory access multi_dir: command: "python" args: ["-m", "filesystem_mcp", "--dirs", "/Users/projects,/Users/temp", "--max-depth", "3"] description: "Multi-directory file system access" # Secure file server with restrictions secure_fs: command: "python" args: [ "-m", "secure_fs_mcp", "--root", "/safe/sandbox", "--allowed-extensions", ".txt,.md,.json,.yaml", "--max-file-size", "5MB", "--no-hidden-files" ] description: "Secure file system with safety restrictions" ``` ## ๐Ÿ”ง How It Works ### Service Discovery and Integration 1. **Configuration Loading**: The registry reads YAML configuration files to discover services 2. **Service Initialization**: Each service type is initialized with its specific adapter 3. **Tool Registration**: Tools/APIs are registered with consistent naming (`service_name_tool_name`) 4. **Unified Interface**: All services expose the same standardized API format ### API Format Standardization All services return APIs in a consistent format: ```json { "service_name_api_name": { "app_name": "service_name", "secure": false, "api_name": "service_name_api_name", "path": "/api/endpoint", "method": "POST", "description": "API description", "parameters": [ { "name": "param_name", "type": "string", "required": true, "description": "Parameter description", "constraints": ["must be one of: [value1, value2]"] } ], "response_schemas": { "success": {"result": "object"}, "failure": {"error": "string"} } } } ``` ### Tool Calling ```bash # Call a tool via HTTP API curl -X POST http://localhost:8001/functions/call \ -H "Content-Type: application/json" \ -d '{ "app_name": "sales_api", "function_name": "sales_api_get_accounts", "args": { "limit": 10, "status": "active" } }' ``` ## ๐Ÿงช Testing ### Running Tests ```bash # Run all registry tests uv run pytest cuga/backend/tools_env/registry/tests/ -v # Run specific test categories uv run pytest cuga/backend/tools_env/registry/tests/test_legacy_openapi.py -v uv run pytest cuga/backend/tools_env/registry/tests/test_mcp_server.py -v uv run pytest cuga/backend/tools_env/registry/tests/test_mixed_configuration.py -v ``` ### Test Configurations The test suite includes sample configurations for different scenarios: - **Legacy OpenAPI**: Tests OpenAPI service integration - **MCP Servers**: Tests MCP server tool registration and calling - **Mixed Configuration**: Tests multiple service types together - **E2E Testing**: Tests the full HTTP API server ## โš ๏ธ Important Limitations and Workarounds ### MCP Response Schema Representation Due to limitations in the MCP (Model Context Protocol) specification, response schemas are not natively supported in tool definitions. This means that tools created from MCP servers may not have complete response schema information available to consumers. Recommended way as of today: https://gofastmcp.com/servers/tools#output-schemas Or: continue reading for workarounds **Recommended Workaround:** When creating MCP servers, it's recommended to include response schema information directly in the tool descriptions. This can be done by customizing the MCP component during server creation. **Example Implementation:** ```python from fastmcp import FastMCP from fastmcp.server.openapi import OpenAPITool def customize_components(route, component): """Add response schema to tool descriptions""" if isinstance(component, OpenAPITool): # Add response schema to description component.description = f"{component.description}\nresponse schema: ```\n{component.output_schema}```" # Create MCP server with customization mcp = FastMCP.from_openapi( openapi_spec=spec, client=client, mcp_component_fn=customize_components, ) ``` **Alternative Approaches:** 1. **Schema as Dictionary**: Include the response schema as a structured dictionary in the description: ```python component.description = f"{component.description}\n\nExpected Response Format:\n{json.dumps(response_schema, indent=2)}" ``` 2. **Example Response**: Include a sample response without actual values: ```python example_response = { "accounts": [{"name": "string", "state": "string", "revenue": "integer"}], "coverage_id": "string", "client_status": "string" } component.description = f"{component.description}\n\nExample Response:\n{json.dumps(example_response, indent=2)}" ``` **Registry Implementation:** The Tools Environment Registry addresses this limitation by: - Extracting response schemas from OpenAPI specifications when available - Providing consistent response schema information across all service types - Including response schemas in the standardized API format **Custom Output Schema in MCP Tools: ( Recommended )** When developing your own MCP servers, you can define custom output schemas using the `@mcp.tool()` decorator: ```python @mcp.tool(output_schema={ "type": "object", "properties": { "data": {"type": "string"}, "metadata": {"type": "object"} } }) def custom_schema_tool() -> dict: """Tool with custom output schema.""" return {"data": "Hello", "metadata": {"version": "1.0"}} ``` This approach provides structured output schema information that can be used by the registry system. **Reference Example:** See `docs/examples/client_package_usage/fast_mcp_example.py` for a complete implementation of this workaround. ## ๐Ÿ” Debugging and Troubleshooting ### Common Issues 1. **MCP Server Connection Failed** ``` Error: Failed to connect to MCP server at http://localhost:8000/sse ``` - Ensure the MCP server is running and accessible - Check the URL and port configuration - Verify network connectivity 2. **OpenAPI Schema Loading Failed** ``` Error: Failed to fetch OpenAPI schema from https://api.example.com/openapi.json ``` - Verify the URL is accessible - Check authentication requirements - Ensure the schema is valid OpenAPI format 3. **Tool Not Found** ``` Error: Tool 'service_name_tool_name' not found in any server ``` - Verify the service is properly configured and loaded - Check the exact tool name (should include service prefix) - Ensure the service initialization completed successfully ### Logging Enable debug logging to troubleshoot issues: ```python import logging logging.basicConfig(level=logging.DEBUG) ``` ### Health Checks ```bash # Check server health curl http://localhost:8001/ # List all applications curl http://localhost:8001/applications # Check specific application curl http://localhost:8001/applications/your_service_name/apis ``` ## ๐Ÿš€ Advanced Usage ### Dynamic Tool Onboarding ```python # Onboard tools dynamically via API import requests payload = { "app_name": "dynamic_service", "schemas": [ { "name": "custom_tool", "description": "A dynamically added tool", "input_schema": { "type": "object", "properties": { "input": {"type": "string"} }, "required": ["input"] } } ] } response = requests.post("http://localhost:8001/functions/onboard", json=payload) ``` ### Custom MCP Server Development ```python # Example custom MCP server with output schemas from mcp import FastMCP app = FastMCP() @app.tool("custom_analysis", output_schema={ "type": "object", "properties": { "result": {"type": "string"}, "confidence": {"type": "number"}, "metadata": { "type": "object", "properties": { "method": {"type": "string"}, "timestamp": {"type": "string"} } } }, "required": ["result", "confidence"] }) def analyze_data(data: str, method: str = "default") -> dict: """Analyze data using specified method with structured output""" import datetime # Your analysis logic here result = f"Analysis result for {data} using {method}" return { "result": result, "confidence": 0.95, "metadata": { "method": method, "timestamp": datetime.datetime.now().isoformat() } } @app.tool("simple_tool", output_schema={ "type": "object", "properties": { "data": {"type": "string"}, "status": {"type": "string"} } }) def simple_tool(input_text: str) -> dict: """Simple tool with basic output schema""" return { "data": f"Processed: {input_text}", "status": "success" } if __name__ == "__main__": app.run() ``` ## ๐Ÿ“š Additional Resources - [MCP Protocol Documentation](https://modelcontextprotocol.io/) - [OpenAPI Specification](https://swagger.io/specification/) - [FastAPI Documentation](https://fastapi.tiangolo.com/) ## ๐Ÿค Contributing 1. Add new service adapters in `mcp_manager/` 2. Update tests in `tests/` 3. Follow the standardized API format 4. Add configuration samples 5. Update this README with new features --- For more examples and advanced configurations, check the `tests/` directory and `config/` samples.