---
globs: src/tools.ts,src/resources.ts,src/prompts.ts,src/server.ts
description: "Code generation patterns for MCP server components"
---
# MCP Component Generation Patterns
## Tool Generation Rules
When generating tools in [tools.ts](mdc:src/tools.ts):
```typescript
// ALWAYS follow this exact pattern
server.tool(
'action_noun', // Use snake_case, action + noun format
'Action description in imperative mood',
{
// REQUIRED parameters first, then optional
required_param: z.string().describe('Clear description'),
optional_param: z.string().optional().describe('Optional description'),
},
async ({ required_param, optional_param }) => {
try {
// Validate inputs if needed
if (!required_param?.trim()) {
throw new Error('Required parameter cannot be empty');
}
// Core logic here
const result = await performAction(required_param, optional_param);
return {
content: [{
type: "text",
text: `Success: ${result.message}`
}],
result // Include actual data for programmatic use
};
} catch (error) {
return {
content: [{
type: "text",
text: `Error: ${error.message}`
}],
isError: true
};
}
}
);
```
**Tool Naming Convention:**
- `create_item` not `createItem` or `item_create`
- `get_status` not `status` or `getStatus`
- `update_settings` not `updateSettings`
## Resource Generation Rules
When generating resources in [resources.ts](mdc:src/resources.ts):
```typescript
// Pattern for single item resources
server.resource(
'get_item',
'data://service/items/{id}',
async (uri: URL) => {
const id = uri.pathname.split('/').pop();
// Implementation
}
);
// Pattern for collection resources
server.resource(
'list_items',
'data://service/items?filter={filter}',
async (uri: URL) => {
const filter = uri.searchParams.get('filter');
// Implementation
}
);
```
**Resource URI Patterns:**
- Use descriptive schemes: `data://`, `config://`, `status://`
- Always include placeholders: `{id}`, `{category}`, `{filter}`
- Support query parameters for filtering/options
## Prompt Generation Rules
When generating prompts in [prompts.ts](mdc:src/prompts.ts):
```typescript
// Interactive prompts for user guidance
server.prompt(
'help_getting_started',
'Get help with initial setup and usage',
(args?: { topic?: string }) => ({
messages: [{
role: 'assistant',
content: {
type: 'text',
text: `Welcome! I can help you with ${args?.topic || 'getting started'}.
Here are the available options:
1. Basic setup - Get started with initial configuration
2. Advanced features - Learn about advanced capabilities
3. Troubleshooting - Solve common issues
What would you like to learn about?`
}
}]
})
);
// System prompts for AI behavior
server.prompt(
'system_behavior',
'Configure AI assistant behavior for this domain',
() => ({
messages: [{
role: 'system',
content: {
type: 'text',
text: `You are a helpful assistant specialized in [domain].
Guidelines:
- Always be accurate and helpful
- Ask clarifying questions when needed
- Provide step-by-step instructions
- Include relevant examples`
}
}]
})
);
```
## Server Extension Pattern
When extending the server class in [server.ts](mdc:src/server.ts):
```typescript
export class DomainMcpServer extends McpHonoServerDO<Env> {
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
}
getImplementation(): Implementation {
return {
name: 'DomainMcpServer', // Use descriptive, domain-specific name
version: '1.0.0',
};
}
configureServer(server: McpServer): void {
setupServerTools(server); // Always include all three
setupServerResources(server);
setupServerPrompts(server);
}
// Only add setupRoutes if custom HTTP endpoints are needed
protected setupRoutes(app: Hono<{ Bindings: Env }>): void {
super.setupRoutes(app); // CRITICAL: Always call parent first
// Group related endpoints
app.get('/api/health', this.handleHealthCheck.bind(this));
app.post('/api/webhook', this.handleWebhook.bind(this));
}
private async handleHealthCheck(c: any) {
return c.json({ status: 'ok', timestamp: Date.now() });
}
private async handleWebhook(c: any) {
// Implementation
}
}
```
## Error Handling Patterns
Always include proper error handling:
```typescript
// In tools
try {
const result = await riskyOperation();
return { content: [{ type: "text", text: `Success: ${result}` }] };
} catch (error) {
console.error('Tool error:', error);
return {
content: [{ type: "text", text: `Error: ${error.message}` }],
isError: true
};
}
// In resources
try {
const data = await fetchData();
return { contents: [{ text: JSON.stringify(data), uri: uri.href }] };
} catch (error) {
throw new Error(`Resource fetch failed: ${error.message}`);
}
```
## Validation Patterns
Use Zod for comprehensive validation:
```typescript
// Complex parameter schemas
{
// Strings with constraints
title: z.string().min(1).max(100).describe('Item title (1-100 chars)'),
// Enums for controlled values
status: z.enum(['draft', 'published', 'archived']).describe('Publication status'),
// Optional with defaults
priority: z.number().min(1).max(5).default(3).describe('Priority level (1-5)'),
// Arrays with validation
tags: z.array(z.string().min(1)).optional().describe('List of tags'),
// Nested objects
metadata: z.object({
category: z.string(),
subcategory: z.string().optional()
}).optional().describe('Additional metadata')
}
```