mcp-standards.md

Standards for developing Model Context Protocol (MCP) servers including error handling, security, and best practices

mcp-standards.mdv1.2.09.2 KB
mcp-standards.md(markdown)
1# MCP Standards
2
3## Overview
4
5Comprehensive standards for developing Model Context Protocol (MCP) servers, covering naming conventions, error handling, and security considerations.
6
7## Tool Naming Conventions
8
9### Name Collision Prevention
10
11When developing MCP servers that expose tools, **always** use namespaced tool names to prevent conflicts when multiple servers are running simultaneously.
12
13**Format**: `mcp_<server>_<tool_name>`
14
15**Examples**:
16- `mcp_filesystem_get_logs` (instead of `get_logs`)
17- `mcp_shell_get_logs` (instead of `get_logs`)
18- `mcp_database_list_tables` (instead of `list_tables`)
19- `mcp_github_create_issue` (instead of `create_issue`)
20
21### Rationale
22
23The MCP specification currently has no official mechanism for handling duplicate tool names across multiple servers. Different MCP clients handle this inconsistently:
24
25- Some clients crash with errors like "Multiple tools with the same name"
26- Some route to the first/last registered server unpredictably
27- Some clients (like Cursor) automatically namespace tools
28
29**Problem**: When multiple MCP servers expose tools with identical names (e.g., both a filesystem server and shell server exposing `get_logs`), the behavior is undefined and can cause:
30- Tool calls routing to wrong servers
31- Application crashes
32- Unpredictable behavior for end users
33
34### Implementation Guidelines
35
361. **Always namespace tools** - Never expose bare tool names like `get_logs`, `list_files`, etc.
372. **Use descriptive server names** - Choose clear, unique identifiers for your server type
383. **Document tool names clearly** - Make the namespacing obvious in documentation
394. **Test with multiple servers** - Always test your MCP server alongside other common servers
40
41## Error Handling Standards
42
43### MCP Error Types
44```typescript
45enum McpErrorCode {
46  ParseError = -32700,          // Invalid JSON received
47  InvalidRequest = -32600,      // Request is not valid MCP
48  MethodNotFound = -32601,      // Method does not exist
49  InvalidParams = -32602,       // Invalid method parameters
50  InternalError = -32603        // Internal server error
51}
52```
53
54### Error Response Pattern
55```typescript
56class McpError extends Error {
57  constructor(
58    public code: McpErrorCode,
59    message: string,
60    public data?: any
61  ) {
62    super(message);
63    this.name = 'McpError';
64  }
65  
66  toResponse(): McpErrorResponse {
67    return {
68      error: {
69        code: this.code,
70        message: this.message,
71        data: this.data
72      }
73    };
74  }
75}
76```
77
78### Error Handling Implementation
79```typescript
80// Request validation
81function validateRequest(request: any): void {
82  if (!request.method) {
83    throw new McpError(
84      McpErrorCode.InvalidRequest,
85      'Missing required field: method'
86    );
87  }
88  
89  if (typeof request.method !== 'string') {
90    throw new McpError(
91      McpErrorCode.InvalidRequest,
92      'Field "method" must be a string'
93    );
94  }
95}
96
97// Tool execution error handling
98async function executeTool(toolName: string, params: any): Promise<any> {
99  try {
100    const result = await toolHandlers[toolName](params);
101    return { content: [{ type: 'text', text: JSON.stringify(result) }] };
102  } catch (error) {
103    if (error instanceof SecurityError) {
104      throw new McpError(
105        McpErrorCode.InvalidParams,
106        'Security validation failed',
107        { reason: error.message }
108      );
109    }
110    
111    if (error instanceof ValidationError) {
112      throw new McpError(
113        McpErrorCode.InvalidParams,
114        'Parameter validation failed',
115        { details: error.details }
116      );
117    }
118    
119    // Don't leak internal errors
120    logger.error('MCP-Server', 'Tool execution failed', toolName, { error: error.message });
121    throw new McpError(
122      McpErrorCode.InternalError,
123      'Tool execution failed'
124    );
125  }
126}
127```
128
129## Security Considerations
130
131### Input Validation
132```typescript
133// Schema-based parameter validation
134function validateToolParams(toolName: string, params: any): void {
135  const schema = getToolSchema(toolName);
136  const result = validateSchema(params, schema);
137  
138  if (!result.valid) {
139    throw new McpError(
140      McpErrorCode.InvalidParams,
141      'Parameter validation failed',
142      { errors: result.errors }
143    );
144  }
145  
146  // Additional security validation
147  if (toolName.includes('file') && params.path) {
148    SecurityValidator.validatePath(params.path);
149  }
150}
151
152// Sanitize output data
153function sanitizeResponse(data: any): any {
154  // Remove sensitive fields
155  const sensitiveFields = ['password', 'secret', 'token', 'key'];
156  
157  if (typeof data === 'object' && data !== null) {
158    const sanitized = { ...data };
159    
160    sensitiveFields.forEach(field => {
161      if (field in sanitized) {
162        sanitized[field] = '[REDACTED]';
163      }
164    });
165    
166    return sanitized;
167  }
168  
169  return data;
170}
171```
172
173## Logging and Monitoring
174
175### MCP-Specific Logging
176```typescript
177// Log MCP protocol events
178function logMcpEvent(
179  event: 'request' | 'response' | 'error',
180  method: string,
181  details: any
182): void {
183  logger.info('MCP-Server', `${event}: ${method}`, method, {
184    event,
185    method,
186    ...details
187  });
188}
189
190// Performance monitoring
191function logMcpPerformance(
192  method: string,
193  startTime: number,
194  success: boolean,
195  metadata?: any
196): void {
197  const duration = Date.now() - startTime;
198  
199  logger.logPerformance(
200    'MCP-Server',
201    method,
202    undefined, // file size not applicable
203    duration,
204    undefined  // quota not applicable
205  );
206  
207  // Alert on slow operations
208  if (duration > 1000) {
209    logger.warn('MCP-Server', 'Slow operation detected', method, {
210      duration,
211      success,
212      ...metadata
213    });
214  }
215}
216```
217
218## Configuration Standards
219
220### Server Configuration
221```typescript
222interface McpServerConfig {
223  // Server identification
224  name: string;
225  version: string;
226  description: string;
227  
228  // Security settings
229  security: {
230    requireAuth: boolean;
231    allowedOrigins: string[];
232    enableCors: boolean;
233  };
234  
235  // Logging configuration
236  logging: {
237    level: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
238    enablePerformanceLogging: boolean;
239    enableSecurityLogging: boolean;
240  };
241  
242  // Tool configuration
243  tools: {
244    [toolName: string]: {
245      enabled: boolean;
246      permissions: string[];
247      rateLimit?: number;
248    };
249  };
250}
251```
252
253### Environment Configuration
254```typescript
255// Load configuration from environment
256function loadMcpConfig(): McpServerConfig {
257  return {
258    name: process.env.MCP_SERVER_NAME || 'unnamed-server',
259    version: process.env.MCP_SERVER_VERSION || '1.0.0'
260  };
261}
262```
263
264## Testing MCP Servers
265
266### Mock Client for Testing
267```typescript
268class MockMcpClient {
269  async sendRequest(request: any): Promise<any> {
270    // Simulate MCP protocol request/response
271    return await this.server.handleRequest(request);
272  }
273  
274  async callTool(name: string, params: any): Promise<any> {
275    return this.sendRequest({
276      method: 'tools/call',
277      params: { name, arguments: params }
278    });
279  }
280}
281```
282
283### Integration Testing
284```typescript
285describe('MCP Server Integration', () => {
286  it('should handle tool calls with proper namespacing', async () => {
287    const response = await client.callTool('mcp_filesystem_read_file', {
288      path: 'test.txt'
289    });
290    
291    expect(response.error).toBeUndefined();
292    expect(response.content).toBeDefined();
293  });
294  
295  it('should enforce rate limits', async () => {
296    // Make many requests rapidly
297    const promises = Array(150).fill(0).map(() =>
298      client.callTool('mcp_test_tool', {})
299    );
300    
301    const results = await Promise.allSettled(promises);
302    const failures = results.filter(r => r.status === 'rejected');
303    
304    expect(failures.length).toBeGreaterThan(0);
305  });
306});
307```
308
309## Cross-Cutting Concerns
310
311For shared functionality across multiple servers (logging, monitoring, health checks), coordination is essential:
312
313- **Agree on naming conventions** within your organization
314- **Consider consolidating** common tools into a single "utility" MCP server
315- **Document dependencies** between servers clearly
316- **Implement health checks** for server monitoring
317- **Use consistent error handling** patterns across servers
318
319## Best Practices Checklist
320
321### Development
322- [ ] Tools use proper `mcp_<server>_<tool>` naming convention
323- [ ] Comprehensive error handling with appropriate MCP error codes
324- [ ] Input validation and sanitization for all parameters
325- [ ] Security considerations documented and implemented
326
327### Testing
328- [ ] Unit tests cover all tool functionality
329- [ ] Integration tests with mock MCP clients
330- [ ] Security tests cover attack vectors
331
332### Documentation
333- [ ] Tool schemas clearly documented
334- [ ] Error conditions and responses documented
335- [ ] Configuration options explained
336- [ ] Security considerations outlined
337
338### Monitoring
339- [ ] MCP protocol events logged appropriately
340- [ ] Security events monitored
341- [ ] Health checks implemented
342
343## References
344
345- [MCP Tool Name Collision Discussion](https://github.com/orgs/modelcontextprotocol/discussions/291)
346- [Cursor Community: Tool Name Conflicts](https://forum.cursor.com/t/mcp-tools-with-name-conflicts-arent-routed-correctly/91168)
347- [Spring AI: Multiple Tools Issue](https://github.com/spring-projects/spring-ai/issues/2393)
348- [MCP Specification](https://modelcontextprotocol.io/docs/specification)
349
350---
351
352*Updated: 2025-05-31 - Comprehensive MCP development standards*

Metadata

Path
utaba/main/guidance/development/mcp-standards.md
Namespace
utaba/main/guidance/development
Author
utaba
Category
guidance
Technology
mcp
Contract Version
1.2.0
MIME Type
text/markdown
Published
18-Jul-2025
Last Updated
18-Jul-2025