ADR-049: Multi-Protocol Virtual ServersΒΆ
StatusΒΆ
Accepted
ContextΒΆ
Virtual servers may need to expose multiple protocol interfaces simultaneously to serve diverse clients and use cases:
- MCP (SSE/WebSocket) for standard tool access and server-to-agent communication
- A2A (JSON-RPC) for agent-to-agent communication with structured task workflows
- REST/gRPC for integration with external systems
A single virtual server instance should be able to host multiple protocol bindings without duplication. Currently, server configuration is tightly coupled to a single protocol, limiting flexibility.
DecisionΒΆ
Introduce a ServerInterface model (server_interfaces table) that stores per-protocol configuration with a unique constraint on (server_id, protocol, binding). Each interface has its own version, tenant scope, and enabled flag.
CREATE TABLE server_interfaces (
id VARCHAR(36) PRIMARY KEY,
server_id VARCHAR(36) NOT NULL,
protocol VARCHAR(50) NOT NULL, -- e.g., 'a2a-jsonrpc', 'mcp-sse', 'mcp-ws', 'rest'
binding VARCHAR(255), -- e.g., '/a2a', '/mcp', '/rest'
version VARCHAR(50), -- Protocol-specific version
tenant_id VARCHAR(36), -- Inherited or overridden
enabled BOOLEAN DEFAULT TRUE,
config_json TEXT, -- Protocol-specific config
created_at TIMESTAMP,
updated_at TIMESTAMP,
UNIQUE KEY unique_server_protocol_binding (server_id, protocol, binding),
FOREIGN KEY (server_id) REFERENCES servers(id)
);
Additionally, introduce an A2AAgentAuth model (a2a_agent_auth table) that extracts agent authentication configuration into a dedicated 1:1 table for cleaner schema evolution.
CREATE TABLE a2a_agent_auth (
id VARCHAR(36) PRIMARY KEY,
server_interface_id VARCHAR(36) NOT NULL UNIQUE,
auth_type VARCHAR(50), -- 'api_key', 'jwt', 'oauth2'
api_key_hash VARCHAR(255), -- For API key auth
jwt_issuer VARCHAR(255), -- For JWT auth
oauth2_provider VARCHAR(255), -- For OAuth2 auth
created_at TIMESTAMP,
updated_at TIMESTAMP,
FOREIGN KEY (server_interface_id) REFERENCES server_interfaces(id)
);
ConsequencesΒΆ
PositiveΒΆ
- Flexibility: A single server can have both
a2a-jsonrpcandmcp-sseinterfaces simultaneously - Clean separation: Protocol-specific configuration is isolated from the main server record
- Extensibility: New protocols can be added without schema migration sprawl
- Agent card generation: Derives supported interfaces from interface records, enabling discovery
- Protocol routing: Uses interface binding URLs to dispatch requests to the correct handler
- Auth isolation:
A2AAgentAuthextracts auth configuration for independent management
NegativeΒΆ
- Schema complexity: Additional tables and relationships increase the model surface area
- Query complexity: Multi-protocol lookups require joins across interface records
- Migration burden: Existing single-protocol servers must be migrated to the new model
- Testing scope: Multi-protocol scenarios require comprehensive integration testing
Implementation NotesΒΆ
- Backward compatibility: Single-protocol servers continue to function; gradual migration to multi-protocol is optional
- Agent card generation discovers all enabled interfaces on a server and reports them in the agent card
- Protocol routing uses the binding path to select the appropriate handler
- The
A2AAgentAuthmodel is optional; servers without A2A interfaces do not require auth records - Interface versioning allows independent version bumps for different protocols on the same server
ReferencesΒΆ
mcpgateway/db.py- ORM models forServerInterfaceandA2AAgentAuthmcpgateway/services/- Protocol-specific routing logicdocs/docs/architecture/multitenancy.md- Multi-tenancy model