- Add MCPOAuthProvider implementing OAuthClientProvider interface - Implement popup-based OAuth flow with message passing - Add automatic connection retry after OAuth completion - Support client registration persistence per server URL - Add proper error suppression for expected OAuth UnauthorizedErrors - Create comprehensive OAuth implementation documentation - Clean up debug logging with emoji status indicators 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
9.2 KiB
9.2 KiB
MCP Provider Interface Design
⚠️ DRAFT/TENTATIVE DESIGN
This document outlines a proposed design for the MCP provider system. The design is subject to iteration and refinement during implementation.
Overview
The MCP Provider system manages connections to multiple MCP servers, providing a unified interface for tool calling, resource access, and connection management. It follows similar architectural patterns to the InferenceProvider system.
Goals
- Multi-Server Support: Connect to multiple MCP servers simultaneously
- Transport Abstraction: Support SSE and Streamable HTTP transports with automatic fallback
- Tool Aggregation: Combine tools from all servers with conflict resolution
- Connection Management: Handle connection lifecycle, reconnection, and error recovery
- OAuth Integration: Support MCP server OAuth flows with proper callback routing
- Debug Visibility: Comprehensive debugging interface for development and troubleshooting
Core Interfaces
MCPConnection
interface MCPConnection {
id: string; // Unique connection identifier
name: string; // User-provided server name
url: string; // Server URL
status: 'connecting' | 'connected' | 'failed' | 'disconnected';
client?: Client; // MCP SDK client instance
transport: 'sse' | 'streamable-http';
authType: 'none' | 'oauth';
// Available capabilities
tools: Tool[]; // Tools with name-prefixed identifiers
resources?: Resource[]; // Available resources
prompts?: Prompt[]; // Available prompts
// Connection metadata
error?: string; // Last error message
lastConnected?: Date; // Last successful connection
capabilities?: ServerCapabilities; // Server-advertised capabilities
// Debug information
messageTrace?: MCPMessage[]; // Recent message exchange history
connectionAttempts: number; // Number of reconnection attempts
}
MCPServerConfig
interface MCPServerConfig {
name: string; // User-provided display name
url: string; // Server endpoint URL
transport?: 'sse' | 'streamable-http' | 'auto'; // Default: auto-detect
authType?: 'none' | 'oauth'; // Default: none
oauthConfig?: {
// OAuth configuration if needed
clientId?: string;
};
autoReconnect?: boolean; // Default: true
maxReconnectAttempts?: number; // Default: 5
}
MCPContextValue
interface MCPContextValue {
// Connection state
connections: MCPConnection[];
isLoading: boolean;
error: string | null;
// Connection management
addMcpServer: (config: MCPServerConfig) => Promise<string>; // Returns connection ID
removeMcpServer: (connectionId: string) => void;
reconnectServer: (connectionId: string) => Promise<void>;
// Tool access (explicit server routing)
getAllTools: () => Tool[]; // All tools with prefixed names
getToolsForServer: (connectionId: string) => Tool[];
callTool: (connectionId: string, toolName: string, args: any) => Promise<any>;
// Resource access
getAllResources: () => Resource[];
getResourcesForServer: (connectionId: string) => Resource[];
// Status and debugging
getConnectedServers: () => MCPConnection[];
getServerStatus: (connectionId: string) => MCPConnection['status'];
getConnectionById: (connectionId: string) => MCPConnection | undefined;
getMessageTrace: (connectionId: string) => MCPMessage[];
}
Tool Name Resolution
Prefixing Strategy
Tools from each server are prefixed with the user-provided server name to avoid conflicts:
// Original tool from weather server: "get_weather"
// Prefixed tool: "weather_server.get_weather"
// Original tool from calendar server: "get_events"
// Prefixed tool: "calendar.get_events"
Tool Discovery and Registration
class MCPConnection {
private async discoverTools(): Promise<Tool[]> {
const tools = await this.client.listTools();
return tools.map(tool => ({
...tool,
function: {
...tool.function,
name: `${this.name}.${tool.function.name}`, // Add prefix
description: `[${this.name}] ${tool.function.description}`, // Add server context
}
}));
}
}
Connection Management
Connection Lifecycle
class MCPConnection {
async connect(): Promise<void> {
this.status = 'connecting';
try {
// 1. Try StreamableHTTP first
if (this.transport === 'auto' || this.transport === 'streamable-http') {
await this.tryStreamableHttp();
}
// 2. Fallback to SSE if needed
if (this.status !== 'connected' && (this.transport === 'auto' || this.transport === 'sse')) {
await this.trySSE();
}
// 3. Initialize capabilities
await this.initializeCapabilities();
this.status = 'connected';
this.lastConnected = new Date();
this.connectionAttempts = 0;
} catch (error) {
this.status = 'failed';
this.error = error.message;
this.connectionAttempts++;
if (this.autoReconnect && this.connectionAttempts < this.maxReconnectAttempts) {
setTimeout(() => this.connect(), this.getBackoffDelay());
}
}
}
}
Auto-Reconnection Strategy
- Exponential backoff: 1s, 2s, 4s, 8s, 16s
- Maximum 5 attempts by default
- Reset attempt counter on successful connection
- User can manually retry after max attempts reached
React Integration
MCPProvider Context
export function MCPProvider({ children }: { children: ReactNode }) {
const [connections, setConnections] = useState<MCPConnection[]>([]);
const [connectionStates, setConnectionStates] = useState<Record<string, any>>({});
// Load persisted connections from localStorage on mount
useEffect(() => {
loadPersistedConnections();
}, []);
// Auto-save connections to localStorage
useEffect(() => {
persistConnections(connections);
}, [connections]);
// ... implementation
}
Hook Usage
const {
connections,
addMcpServer,
callTool,
getAllTools
} = useMCP();
// Add a server
const connectionId = await addMcpServer({
name: 'Weather Service',
url: 'https://weather.mcp.example.com',
transport: 'auto'
});
// Call a tool
const result = await callTool(connectionId, 'get_weather', {
location: 'San Francisco'
});
Authentication & OAuth
OAuth Flow for MCP Servers
Following the established callback routing pattern:
- OAuth callbacks:
/oauth/mcp/{connectionId}/callback - Server-specific state management
- Automatic token refresh handling
interface MCPOAuthProvider {
authenticate(connectionId: string): Promise<void>;
refreshToken(connectionId: string): Promise<void>;
getAuthStatus(connectionId: string): 'authenticated' | 'pending' | 'failed';
}
Error Handling & Debugging
Message Tracing
interface MCPMessage {
timestamp: Date;
direction: 'sent' | 'received';
type: 'request' | 'response' | 'notification';
method?: string;
id?: string | number;
content: any;
error?: any;
}
Connection Debugging
- Real-time connection status monitoring
- Message trace viewer with filtering
- Transport fallback information
- OAuth flow status tracking
- Tool discovery and registration logs
Implementation Strategy
Phase 1: Core Connection Management ⏳
- Basic MCPConnection class with transport support
- MCPProvider React context with connection lifecycle
- Tool discovery and name prefixing
- Basic error handling and reconnection
Phase 2: Debug Interface ⏳
- Connection status dashboard
- Tool listing and testing interface
- Message trace viewer
- Manual connection controls
Phase 3: OAuth & Advanced Features
- OAuth integration for authenticated servers
- Resource and prompt support
- Enhanced debugging and monitoring
- Performance optimizations
Phase 4: Integration
- Integration with agent loop and inference provider
- Unified tool calling across test tools and MCP tools
- Advanced error recovery and resilience
Security Considerations
- URL Validation: Validate MCP server URLs to prevent malicious redirects
- OAuth Security: Proper PKCE implementation for OAuth flows
- Message Validation: Validate all MCP messages against protocol schema
- Storage Security: Secure storage of OAuth tokens and sensitive config
- CORS Handling: Proper CORS error detection and user guidance
Testing Strategy
Unit Tests
- MCPConnection class functionality
- Tool name prefixing and conflict resolution
- Connection lifecycle and error handling
- OAuth flow simulation
Integration Tests
- Real MCP server connections (with test servers)
- Transport fallback scenarios
- Multi-server tool calling
- OAuth authentication flows
Future Enhancements
- Advanced Tool Routing: Smart tool routing based on capability matching
- Connection Pooling: Efficient connection reuse and management
- Caching: Tool schema and response caching
- Monitoring: Connection health monitoring and alerts
- Batch Operations: Bulk tool calling and resource access
- Custom Transports: Support for WebSocket and custom transport protocols