|
| 1 | +# Security Design Document: MCP Remote Client |
| 2 | + |
| 3 | +## Executive Summary |
| 4 | + |
| 5 | +The MCP Remote Client is an example open-source web application that demonstrates how to build a client for the Model Context Protocol (MCP). It is designed as a standalone, statically-served application without a backend server, intended for educational and reference purposes rather than production use. The application enables users to connect to MCP servers and inference providers (like OpenRouter) to interact with AI models and tools. |
| 6 | + |
| 7 | +## Application Architecture |
| 8 | + |
| 9 | +### Deployment Model |
| 10 | +- **Static Web Application**: Deployed as static HTML/JS/CSS files |
| 11 | +- **No Backend Server**: All processing occurs client-side in the browser |
| 12 | +- **No Data Exfiltration**: No user data is sent to external analytics or backend services |
| 13 | +- **Local-First Design**: All data persistence uses browser localStorage |
| 14 | + |
| 15 | +### Core Components |
| 16 | + |
| 17 | +1. **MCP Connection Manager**: Handles connections to MCP servers via SSE or HTTP streaming |
| 18 | +2. **Inference Provider System**: Manages connections to AI inference services (OpenRouter) |
| 19 | +3. **Conversation Manager**: Stores and manages conversation history locally |
| 20 | +4. **OAuth Manager**: Handles OAuth 2.0 + PKCE flows for authentication |
| 21 | + |
| 22 | +## Authentication and Authorization |
| 23 | + |
| 24 | +### OAuth 2.0 Implementation |
| 25 | + |
| 26 | +#### MCP Server Authentication |
| 27 | +- **OAuth 2.0 with PKCE**: Implements authorization code flow with Proof Key for Code Exchange |
| 28 | +- **State Parameter**: Includes connection ID prefix (`mcp:${connectionId}`) for callback routing |
| 29 | +- **Code Verifier**: Generated using crypto.getRandomValues() with SHA-256 challenge |
| 30 | +- **Token Storage**: Access tokens stored in localStorage at `mcp_oauth_tokens_${connectionId}` |
| 31 | +- **Client Registration**: OAuth client information cached per server URL to minimize re-registration |
| 32 | + |
| 33 | +#### Inference Provider Authentication |
| 34 | +- **Dual Authentication**: Supports both API keys and OAuth flows |
| 35 | +- **OpenRouter OAuth**: Similar PKCE implementation with `inference:` state prefix |
| 36 | +- **Token Persistence**: Tokens stored in localStorage with automatic loading on app start |
| 37 | +- **No Refresh Tokens**: Current implementation does not support token refresh |
| 38 | + |
| 39 | +### API Key Management |
| 40 | +- **Local Storage**: API keys stored in browser localStorage |
| 41 | +- **No Transmission**: Keys are never sent to third-party services beyond the intended providers |
| 42 | +- **User-Controlled**: Users manually input and manage their API keys |
| 43 | + |
| 44 | +## Data Storage and Privacy |
| 45 | + |
| 46 | +### Storage Architecture |
| 47 | +- **localStorage**: Primary persistence mechanism for all application data |
| 48 | +- **No Encryption**: Data stored in plaintext (security trade-off for example application) |
| 49 | +- **Browser Sandbox**: Relies on browser same-origin policy for isolation |
| 50 | + |
| 51 | +### Data Types Stored |
| 52 | +1. **Conversation History**: Complete message history including AI responses |
| 53 | +2. **OAuth Tokens**: Access tokens for MCP servers and inference providers |
| 54 | +3. **API Keys**: User-provided API keys for inference services |
| 55 | +4. **Connection Configurations**: MCP server URLs and settings |
| 56 | +5. **OAuth Client Registrations**: Cached OAuth client credentials |
| 57 | + |
| 58 | +## External Service Integration |
| 59 | + |
| 60 | +### MCP Server Connections |
| 61 | +- **Transport Methods**: SSE (Server-Sent Events) and Streamable HTTP |
| 62 | +- **CORS Dependency**: Requires proper CORS headers from MCP servers |
| 63 | +- **Connection Isolation**: Each server connection runs independently |
| 64 | +- **Error Handling**: Fallback from HTTP streaming to SSE on connection failure |
| 65 | + |
| 66 | +### Inference Provider Integration |
| 67 | +- **OpenRouter**: Primary supported provider with OAuth and API key authentication |
| 68 | +- **Tool Calling**: Native support for function/tool calling with parameter validation |
| 69 | +- **Message Format**: Standard OpenAI-compatible message format |
| 70 | + |
| 71 | +## Security Controls |
| 72 | + |
| 73 | +### Input Validation |
| 74 | +- **URL Validation**: MCP server URLs validated before connection attempts |
| 75 | +- **Tool Parameter Validation**: Function parameters validated against defined schemas |
| 76 | +- **Message Sanitization**: React's built-in XSS protection for rendering |
| 77 | + |
| 78 | +### OAuth Security |
| 79 | +- **PKCE Implementation**: Proper code verifier/challenge generation |
| 80 | +- **State Validation**: State parameter checked for OAuth callback verification |
| 81 | +- **Popup Windows**: OAuth flows use popup windows to maintain app state |
| 82 | +- **Origin Checking**: postMessage origin validation for popup communication |
| 83 | + |
| 84 | +### Transport Security |
| 85 | +- **HTTPS Enforcement**: Relies on browser security for HTTPS connections |
| 86 | +- **No Certificate Pinning**: Standard browser certificate validation |
| 87 | +- **WebSocket Security**: Uses secure WebSocket connections for SSE |
| 88 | + |
| 89 | +## Known Security Considerations |
| 90 | + |
| 91 | +### Client-Side Storage Risks |
| 92 | +- **localStorage Exposure**: All data accessible to JavaScript code |
| 93 | +- **XSS Vulnerability**: Stored tokens/keys exposed if XSS attack succeeds |
| 94 | +- **No Encryption**: Sensitive data stored in plaintext |
| 95 | + |
| 96 | +### Authentication Risks |
| 97 | +- **Token Persistence**: No automatic token expiration or rotation |
| 98 | +- **Public Client**: OAuth uses public client flow (no client secret) |
| 99 | +- **Popup Blocking**: OAuth flow fails if popups are blocked |
| 100 | + |
| 101 | +### Code Execution Risks |
| 102 | +- **eval() Usage**: Mathematical expression evaluation uses eval() with regex filtering |
| 103 | +- **Tool Execution**: Executes tools based on MCP server responses |
| 104 | +- **No Sandboxing**: Tool responses rendered directly in UI |
| 105 | + |
| 106 | +## Security Boundaries |
| 107 | + |
| 108 | +### Trust Boundaries |
| 109 | +1. **Browser Sandbox**: Primary security boundary |
| 110 | +2. **Same-Origin Policy**: Prevents cross-origin data access |
| 111 | +3. **User Consent**: Users explicitly add MCP servers and API keys |
| 112 | + |
| 113 | +### Data Flow |
| 114 | +``` |
| 115 | +User Input -> React App -> localStorage |
| 116 | + -> OAuth Provider -> External Service |
| 117 | + -> MCP Server -> Tool Execution |
| 118 | +``` |
| 119 | + |
| 120 | +## Incident Response Considerations |
| 121 | + |
| 122 | +### Logging and Monitoring |
| 123 | +- **Console Logging**: Errors logged to browser console |
| 124 | +- **No Audit Trail**: No persistent security event logging |
| 125 | +- **User-Visible Errors**: Error messages displayed directly to users |
| 126 | + |
| 127 | +### Data Cleanup |
| 128 | +- **Manual Cleanup**: Users must manually clear localStorage |
| 129 | +- **Logout Function**: Clears authentication tokens but not conversation history |
| 130 | +- **No Automatic Expiry**: Data persists indefinitely |
| 131 | + |
| 132 | +## Compliance and Privacy |
| 133 | + |
| 134 | +### Data Residency |
| 135 | +- **Client-Side Only**: All data remains in user's browser |
| 136 | +- **No Data Collection**: No analytics or telemetry |
| 137 | +- **User Control**: Full user control over data persistence |
| 138 | + |
| 139 | +### GDPR Considerations |
| 140 | +- **No Personal Data Processing**: Application doesn't process data server-side |
| 141 | +- **Right to Erasure**: Users can clear localStorage at any time |
| 142 | +- **Data Portability**: Conversations stored in standard JSON format |
| 143 | + |
| 144 | +## Security Recommendations for Production Use |
| 145 | + |
| 146 | +While this is an example application not intended for production, organizations adapting this code should consider: |
| 147 | + |
| 148 | +1. **Encrypt localStorage**: Implement client-side encryption for sensitive data |
| 149 | +2. **Replace eval()**: Use a safe expression parser library |
| 150 | +3. **Add CSP Headers**: Implement Content Security Policy |
| 151 | +4. **Token Rotation**: Implement automatic token refresh and rotation |
| 152 | +5. **Audit Logging**: Add security event logging |
| 153 | +6. **Input Sanitization**: Additional validation beyond React defaults |
| 154 | +7. **Rate Limiting**: Prevent abuse of OAuth flows |
| 155 | +8. **Secure Token Storage**: Consider Web Crypto API for token encryption |
| 156 | + |
| 157 | +## Conclusion |
| 158 | + |
| 159 | +The MCP Remote Client demonstrates a functional implementation of the Model Context Protocol with OAuth authentication and local data persistence. As an example application, it prioritizes simplicity and clarity over production-grade security controls. The local-first architecture eliminates many traditional web application security concerns but introduces client-side storage risks that users should understand. |
0 commit comments