feat(backend): implement MCP client infrastructure (#55)

Core MCP client implementation with comprehensive tooling:

**Services:**
- MCPClientManager: Main facade for all MCP operations
- MCPServerRegistry: Thread-safe singleton for server configs
- ConnectionPool: Connection pooling with auto-reconnection
- ToolRouter: Automatic tool routing with circuit breaker
- AsyncCircuitBreaker: Custom async-compatible circuit breaker

**Configuration:**
- YAML-based config with Pydantic models
- Environment variable expansion support
- Transport types: HTTP, SSE, STDIO

**API Endpoints:**
- GET /mcp/servers - List all MCP servers
- GET /mcp/servers/{name}/tools - List server tools
- GET /mcp/tools - List all tools from all servers
- GET /mcp/health - Health check all servers
- POST /mcp/call - Execute tool (admin only)
- GET /mcp/circuit-breakers - Circuit breaker status
- POST /mcp/circuit-breakers/{name}/reset - Reset circuit breaker
- POST /mcp/servers/{name}/reconnect - Force reconnection

**Testing:**
- 156 unit tests with comprehensive coverage
- Tests for all services, routes, and error handling
- Proper mocking and async test support

**Documentation:**
- MCP_CLIENT.md with usage examples
- Phase 2+ workflow documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-03 11:12:41 +01:00
parent 731a188a76
commit e5975fa5d0
22 changed files with 5763 additions and 0 deletions

View File

@@ -53,6 +53,12 @@ dependencies = [
# Celery for background task processing (Syndarix agent jobs)
"celery[redis]>=5.4.0",
"sse-starlette>=3.1.1",
# MCP (Model Context Protocol) for AI agent tool integration
"mcp>=1.0.0",
# Circuit breaker pattern for resilient connections
"pybreaker>=1.0.0",
# YAML configuration support
"pyyaml>=6.0.0",
]
# Development dependencies
@@ -151,6 +157,7 @@ unfixable = []
"app/alembic/env.py" = ["E402", "F403", "F405"] # Alembic requires specific import order
"app/alembic/versions/*.py" = ["E402"] # Migration files have specific structure
"tests/**/*.py" = ["S101", "N806", "B017", "N817", "S110", "ASYNC251", "RUF043"] # pytest: asserts, CamelCase fixtures, blind exceptions, try-pass patterns, and async test helpers are intentional
"app/services/mcp/*.py" = ["ASYNC109", "S311", "RUF022"] # timeout is config param not asyncio.timeout; random is ok for jitter; __all__ order is intentional for readability
"app/models/__init__.py" = ["F401"] # __init__ files re-export modules
"app/models/base.py" = ["F401"] # Re-exports Base for use by other models
"app/utils/test_utils.py" = ["N806"] # SQLAlchemy session factories use CamelCase convention
@@ -268,6 +275,14 @@ ignore_missing_imports = true
module = "httpx.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "pybreaker.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "yaml.*"
ignore_missing_imports = true
# SQLAlchemy ORM models - Column descriptors cause type confusion
[[tool.mypy.overrides]]
module = "app.models.*"
@@ -307,6 +322,11 @@ disable_error_code = ["assignment", "arg-type", "attr-defined", "unused-ignore"]
module = "app.services.oauth_service"
disable_error_code = ["assignment", "arg-type", "attr-defined"]
# MCP services - circuit breaker and httpx client handling
[[tool.mypy.overrides]]
module = "app.services.mcp.*"
disable_error_code = ["attr-defined", "arg-type"]
# Test utils - Testing patterns
[[tool.mypy.overrides]]
module = "app.utils.auth_test_utils"