724 lines
20 KiB
Markdown
724 lines
20 KiB
Markdown
# MCP Server Blueprint — February 2026
|
|
|
|
**This is the definitive template for building production-ready MCP servers in 2026.**
|
|
|
|
Use this checklist for EVERY new MCP server. No skipping steps. These patterns ensure your server is:
|
|
- ✅ Usable (not just functional)
|
|
- ✅ Fast (lazy loading, efficient queries)
|
|
- ✅ Discoverable (labels, descriptions)
|
|
- ✅ Interactive (MCP Apps where appropriate)
|
|
- ✅ Debuggable (logging, progress)
|
|
- ✅ Production-ready (error handling, deployment)
|
|
|
|
---
|
|
|
|
## Phase 1: Planning (Before Writing Code)
|
|
|
|
### 1.1 Define Server Scope
|
|
- [ ] What API/service are you integrating?
|
|
- [ ] What are the 5-10 most important operations?
|
|
- [ ] Who is the target user? (developers, business users, etc.)
|
|
- [ ] What data is most frequently accessed?
|
|
|
|
### 1.2 Identify Tool Categories
|
|
Label your tools by category. Common patterns:
|
|
- [ ] **CRUD operations** (create, read, update, delete)
|
|
- [ ] **Search/Filter** (find data with queries)
|
|
- [ ] **Analytics/Reporting** (stats, dashboards, summaries)
|
|
- [ ] **Workflows** (multi-step operations)
|
|
- [ ] **Admin** (configuration, settings)
|
|
|
|
### 1.3 Identify UI Opportunities
|
|
Which operations benefit from visual display?
|
|
- [ ] **Data grids** — Contact lists, search results, tables
|
|
- [ ] **Dashboards** — Metrics, KPIs, analytics
|
|
- [ ] **Cards** — Detail views (invoices, opportunities, profiles)
|
|
- [ ] **Timelines** — Activity feeds, history
|
|
- [ ] **Forms** — Quick actions (booking, creating records)
|
|
- [ ] **Kanban** — Pipeline views, project boards
|
|
|
|
If you have 3+ UI opportunities, plan for MCP Apps.
|
|
|
|
---
|
|
|
|
## Phase 2: Core Server Setup
|
|
|
|
### 2.1 Project Structure
|
|
```bash
|
|
mkdir mcp-server-myservice
|
|
cd mcp-server-myservice
|
|
npm init -y
|
|
npm install @modelcontextprotocol/sdk
|
|
npm install -D typescript @types/node tsx fs-extra @types/fs-extra
|
|
```
|
|
|
|
### 2.2 File Structure
|
|
```
|
|
mcp-server-myservice/
|
|
├── src/
|
|
│ ├── index.ts # Main server (or server.ts)
|
|
│ ├── clients/
|
|
│ │ └── api-client.ts # API client
|
|
│ ├── apps/ # If using MCP Apps
|
|
│ │ └── index.ts # Apps manager
|
|
│ ├── ui/ # If using MCP Apps
|
|
│ │ ├── contact-grid.html
|
|
│ │ └── dashboard.html
|
|
│ └── types/
|
|
│ └── index.ts # Shared types
|
|
├── dist/ # Build output
|
|
├── scripts/
|
|
│ └── copy-ui.js # UI build script
|
|
├── package.json
|
|
├── tsconfig.json
|
|
├── .env.example
|
|
├── .gitignore
|
|
├── .npmignore
|
|
├── Dockerfile
|
|
├── railway.json
|
|
└── README.md
|
|
```
|
|
|
|
### 2.3 Package Configuration
|
|
```json
|
|
{
|
|
"name": "mcp-server-myservice",
|
|
"version": "1.0.0",
|
|
"type": "module",
|
|
"main": "dist/index.js",
|
|
"bin": {
|
|
"mcp-server-myservice": "dist/index.js"
|
|
},
|
|
"scripts": {
|
|
"build": "npm run build:ts && npm run build:ui",
|
|
"build:ts": "tsc",
|
|
"build:ui": "node scripts/copy-ui.js",
|
|
"dev": "tsx src/index.ts",
|
|
"start": "node dist/index.js"
|
|
},
|
|
"files": ["dist", "README.md", "LICENSE"],
|
|
"keywords": ["mcp", "mcp-server", "model-context-protocol", "myservice"]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 3: Tool Design (The Most Important Phase)
|
|
|
|
### 3.1 Tool Naming Convention
|
|
✅ **Use:** `verb_noun` (snake_case)
|
|
❌ **Avoid:** camelCase, PascalCase, kebab-case
|
|
|
|
**CRUD patterns:**
|
|
- `list_contacts` (with pagination + filters)
|
|
- `get_contact` (by ID)
|
|
- `create_contact` (returns created object)
|
|
- `update_contact` (partial updates)
|
|
- `delete_contact` (confirm before delete)
|
|
- `search_contacts` (full-text search if different from list)
|
|
|
|
**Other patterns:**
|
|
- `send_email`, `schedule_appointment`, `export_report`, `analyze_pipeline`
|
|
|
|
### 3.2 Tool Metadata & Labels ⭐ CRITICAL
|
|
Every tool MUST have `_meta` with labels:
|
|
|
|
```typescript
|
|
{
|
|
name: "search_contacts",
|
|
description: "Search contacts with filters. Returns paginated results.",
|
|
inputSchema: { /* ... */ },
|
|
_meta: {
|
|
labels: {
|
|
category: "contacts", // Group by feature
|
|
access: "read", // read | write | delete
|
|
complexity: "simple", // simple | complex | batch
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
**Label categories to use:**
|
|
- `category`: contacts, deals, analytics, calendar, email, admin, workflows
|
|
- `access`: read, write, delete
|
|
- `complexity`: simple (1 API call), complex (multiple calls), batch (loops)
|
|
- `sensitivity`: public, internal, confidential (optional)
|
|
|
|
### 3.3 Input Schemas — Best Practices
|
|
```typescript
|
|
inputSchema: {
|
|
type: "object" as const,
|
|
properties: {
|
|
// Always describe parameters
|
|
page: {
|
|
type: "number",
|
|
description: "Page number (default 1, starts at 1)"
|
|
},
|
|
pageSize: {
|
|
type: "number",
|
|
description: "Results per page (default 50, max 100)"
|
|
},
|
|
// Use enums for fixed options
|
|
status: {
|
|
type: "string",
|
|
description: "Filter by status",
|
|
enum: ["active", "inactive", "pending"],
|
|
},
|
|
// ISO 8601 for dates
|
|
createdAfter: {
|
|
type: "string",
|
|
description: "Filter created after (ISO 8601: 2026-02-03T14:00:00Z)"
|
|
},
|
|
},
|
|
// Mark required fields explicitly
|
|
required: ["contactId"],
|
|
}
|
|
```
|
|
|
|
### 3.4 Pagination (Mandatory for List Operations)
|
|
Every `list_` or `search_` tool MUST support pagination:
|
|
|
|
```typescript
|
|
{
|
|
name: "list_contacts",
|
|
description: "List contacts with pagination and filters",
|
|
inputSchema: {
|
|
type: "object" as const,
|
|
properties: {
|
|
page: { type: "number", description: "Page number (default 1)" },
|
|
pageSize: { type: "number", description: "Results per page (default 50, max 100)" },
|
|
query: { type: "string", description: "Search query (optional)" },
|
|
},
|
|
},
|
|
_meta: {
|
|
labels: { category: "contacts", access: "read", complexity: "simple" },
|
|
},
|
|
}
|
|
```
|
|
|
|
**In handler:**
|
|
```typescript
|
|
case "list_contacts": {
|
|
const { page = 1, pageSize = 50, query } = args;
|
|
const params = new URLSearchParams();
|
|
params.append("page", String(page));
|
|
params.append("pageSize", String(Math.min(Number(pageSize), 100))); // Cap at API max
|
|
if (query) params.append("query", query);
|
|
|
|
return await client.get(`/contacts?${params}`);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 4: Lazy-Loaded Resources ⭐ NEW
|
|
|
|
### 4.1 When to Use Resources vs Tools
|
|
**Use resources for:**
|
|
- Large datasets (contact lists, transaction history)
|
|
- Frequently changing data (real-time dashboards)
|
|
- Reference data (documentation, schemas)
|
|
- User-specific data (per-user settings, dashboards)
|
|
|
|
**Use tools for:**
|
|
- Operations with parameters (search, filter, create)
|
|
- One-time fetches
|
|
- Mutations (create, update, delete)
|
|
|
|
### 4.2 Resource Setup
|
|
```typescript
|
|
import { ListResourcesRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
|
|
// Declare resources capability
|
|
const server = new Server(
|
|
{ name: "myservice-mcp", version: "1.0.0" },
|
|
{ capabilities: { tools: {}, resources: {} } } // ✅ Enable resources
|
|
);
|
|
|
|
// List available resources (metadata only)
|
|
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
return {
|
|
resources: [
|
|
{
|
|
uri: "myservice://contacts/all",
|
|
name: "All Contacts",
|
|
description: "Complete contact database (lazy-loaded)",
|
|
mimeType: "application/json",
|
|
},
|
|
{
|
|
uri: "myservice://analytics/dashboard",
|
|
name: "Analytics Dashboard",
|
|
description: "Real-time analytics data",
|
|
mimeType: "application/json",
|
|
},
|
|
],
|
|
};
|
|
});
|
|
|
|
// Fetch resource content on-demand
|
|
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
const { uri } = request.params;
|
|
|
|
switch (uri) {
|
|
case "myservice://contacts/all": {
|
|
const contacts = await client.get("/contacts?limit=1000"); // Fetch when requested
|
|
return {
|
|
contents: [{
|
|
uri,
|
|
mimeType: "application/json",
|
|
text: JSON.stringify(contacts, null, 2),
|
|
}],
|
|
};
|
|
}
|
|
|
|
case "myservice://analytics/dashboard": {
|
|
const analytics = await client.get("/analytics/dashboard");
|
|
return {
|
|
contents: [{
|
|
uri,
|
|
mimeType: "application/json",
|
|
text: JSON.stringify(analytics, null, 2),
|
|
}],
|
|
};
|
|
}
|
|
|
|
default:
|
|
throw new Error(`Unknown resource: ${uri}`);
|
|
}
|
|
});
|
|
```
|
|
|
|
### 4.3 Resource Templates (Dynamic URIs)
|
|
```typescript
|
|
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
return {
|
|
resourceTemplates: [
|
|
{
|
|
uriTemplate: "myservice://contact/{id}",
|
|
name: "Contact Details",
|
|
description: "Full contact record by ID",
|
|
mimeType: "application/json",
|
|
},
|
|
],
|
|
};
|
|
});
|
|
|
|
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
const { uri } = request.params;
|
|
|
|
const contactMatch = uri.match(/^myservice:\/\/contact\/(.+)$/);
|
|
if (contactMatch) {
|
|
const contactId = contactMatch[1];
|
|
const contact = await client.get(`/contacts/${contactId}`);
|
|
return {
|
|
contents: [{
|
|
uri,
|
|
mimeType: "application/json",
|
|
text: JSON.stringify(contact, null, 2),
|
|
}],
|
|
};
|
|
}
|
|
|
|
throw new Error(`Unknown resource: ${uri}`);
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 5: MCP Apps (If Applicable)
|
|
|
|
### 5.1 Should You Build Apps?
|
|
Build MCP Apps if you have:
|
|
- ✅ Visual data (grids, cards, dashboards)
|
|
- ✅ 3+ UI opportunities identified in Phase 1
|
|
- ✅ Complex data relationships (better shown than described)
|
|
- ✅ Interactive workflows (drag-drop, forms)
|
|
|
|
Skip apps if:
|
|
- ❌ Simple CRUD operations only
|
|
- ❌ All operations return small JSON objects
|
|
- ❌ No visual benefit
|
|
|
|
### 5.2 App Architecture
|
|
See `mcp-apps-integration` skill for full details. Quick checklist:
|
|
|
|
- [ ] Create `src/apps/index.ts` — MCPAppsManager class
|
|
- [ ] Create `src/ui/` directory — HTML components
|
|
- [ ] Register resource handlers for UI files
|
|
- [ ] Add app tools with `_meta.ui.resourceUri`
|
|
- [ ] Implement `ListResourcesRequestSchema` handler
|
|
- [ ] Implement `ReadResourceRequestSchema` handler
|
|
- [ ] Add `build:ui` script to copy HTML to `dist/app-ui/`
|
|
|
|
### 5.3 App Tool Naming
|
|
**Pattern:** `view_` or `show_` prefix
|
|
|
|
```typescript
|
|
{
|
|
name: "view_contact_grid",
|
|
description: "Display contact search results in a data grid (visual UI component)",
|
|
inputSchema: { /* ... */ },
|
|
_meta: {
|
|
labels: { category: "contacts", access: "read", complexity: "simple" },
|
|
ui: { resourceUri: "ui://myservice/contact-grid" },
|
|
},
|
|
}
|
|
```
|
|
|
|
### 5.4 Common App Patterns
|
|
- **Contact Grid** — Search results table
|
|
- **Dashboard** — Multi-widget analytics view
|
|
- **Pipeline Board** — Kanban with drag-drop
|
|
- **Opportunity Card** — Detail view for single record
|
|
- **Calendar View** — Appointment/event calendar
|
|
- **Timeline** — Activity feed
|
|
|
|
Reference: 11 production GHL apps in `/Users/jakeshore/.clawdbot/workspace/mcp-diagrams/ghl-mcp-apps-only/`
|
|
|
|
---
|
|
|
|
## Phase 6: Progress & Logging
|
|
|
|
### 6.1 Progress Notifications (For Long Operations)
|
|
Any operation taking >5 seconds MUST send progress updates:
|
|
|
|
```typescript
|
|
if (name === "import_contacts") {
|
|
const progressToken = request.params._meta?.progressToken;
|
|
|
|
if (progressToken) {
|
|
await server.notification({
|
|
method: "notifications/progress",
|
|
params: {
|
|
progressToken,
|
|
progress: 0.3, // 30%
|
|
total: 1.0,
|
|
},
|
|
});
|
|
}
|
|
|
|
// ... do work
|
|
|
|
if (progressToken) {
|
|
await server.notification({
|
|
method: "notifications/progress",
|
|
params: { progressToken, progress: 1.0, total: 1.0 },
|
|
});
|
|
}
|
|
}
|
|
```
|
|
|
|
### 6.2 Structured Logging
|
|
Log important operations for debugging:
|
|
|
|
```typescript
|
|
import { LoggingLevel } from "@modelcontextprotocol/sdk/types.js";
|
|
|
|
await server.notification({
|
|
method: "notifications/message",
|
|
params: {
|
|
level: LoggingLevel.Info,
|
|
logger: "myservice",
|
|
data: {
|
|
operation: "create_contact",
|
|
contactId: newContact.id,
|
|
timestamp: new Date().toISOString(),
|
|
},
|
|
},
|
|
});
|
|
```
|
|
|
|
**When to log:**
|
|
- Info: Successful operations (create, update, delete)
|
|
- Warning: Rate limits, retries, fallbacks
|
|
- Error: API failures, validation errors
|
|
- Debug: Detailed request/response data (dev only)
|
|
|
|
---
|
|
|
|
## Phase 7: Error Handling (Production-Ready)
|
|
|
|
### 7.1 Tool Handler Error Wrapping
|
|
```typescript
|
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
const { name, arguments: args } = request.params;
|
|
|
|
try {
|
|
const result = await handleTool(client, name, args || {});
|
|
return {
|
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
};
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
|
|
// Log the error
|
|
await server.notification({
|
|
method: "notifications/message",
|
|
params: {
|
|
level: LoggingLevel.Error,
|
|
logger: "myservice",
|
|
data: { tool: name, error: message },
|
|
},
|
|
});
|
|
|
|
return {
|
|
content: [{ type: "text", text: `Error: ${message}` }],
|
|
isError: true,
|
|
};
|
|
}
|
|
});
|
|
```
|
|
|
|
### 7.2 API Client Error Handling
|
|
```typescript
|
|
async request(endpoint: string, options: RequestInit = {}) {
|
|
const response = await fetch(url, options);
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
|
|
// Parse API error if JSON
|
|
try {
|
|
const errorJson = JSON.parse(errorText);
|
|
throw new Error(
|
|
`API error: ${response.status} - ${errorJson.message || errorJson.error || errorText}`
|
|
);
|
|
} catch {
|
|
throw new Error(
|
|
`API error: ${response.status} ${response.statusText} - ${errorText}`
|
|
);
|
|
}
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 8: Prompts (Optional but Recommended)
|
|
|
|
### 8.1 When to Add Prompts
|
|
Add prompts for:
|
|
- Common analysis workflows (e.g., "Analyze pipeline health")
|
|
- Report generation (e.g., "Generate contact summary")
|
|
- Quick actions (e.g., "Find overdue tasks")
|
|
- Data exploration (e.g., "Show top performers")
|
|
|
|
### 8.2 Prompt Implementation
|
|
```typescript
|
|
import { ListPromptsRequestSchema, GetPromptRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
|
|
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
return {
|
|
prompts: [
|
|
{
|
|
name: "contact_summary",
|
|
description: "Generate comprehensive contact summary with recent activity",
|
|
arguments: [
|
|
{ name: "contactId", description: "Contact ID", required: true },
|
|
],
|
|
},
|
|
],
|
|
};
|
|
});
|
|
|
|
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
const { name, arguments: args } = request.params;
|
|
|
|
if (name === "contact_summary") {
|
|
const { contactId } = args;
|
|
const contact = await client.get(`/contacts/${contactId}`);
|
|
const activities = await client.get(`/contacts/${contactId}/activities`);
|
|
|
|
return {
|
|
description: `Summary for ${contact.name}`,
|
|
messages: [{
|
|
role: "user",
|
|
content: {
|
|
type: "text",
|
|
text: `Generate a comprehensive summary:\n\n${JSON.stringify({ contact, activities }, null, 2)}`,
|
|
},
|
|
}],
|
|
};
|
|
}
|
|
|
|
throw new Error(`Unknown prompt: ${name}`);
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 9: Testing Checklist
|
|
|
|
### 9.1 Local Testing
|
|
- [ ] All tools compile without errors (`npm run build`)
|
|
- [ ] Server starts successfully (`npm start`)
|
|
- [ ] Environment variables validated on startup
|
|
- [ ] Test each tool in Claude Desktop
|
|
- [ ] Test pagination (page 1, page 2)
|
|
- [ ] Test error cases (invalid IDs, missing params)
|
|
- [ ] Test apps render correctly (if applicable)
|
|
- [ ] Check logs in Claude Desktop console
|
|
|
|
### 9.2 Performance Testing
|
|
- [ ] List operations return in <2 seconds
|
|
- [ ] Lazy-loaded resources only fetch when requested
|
|
- [ ] No unnecessary API calls
|
|
- [ ] Pagination caps at API maximum
|
|
- [ ] Progress notifications for operations >5 seconds
|
|
|
|
---
|
|
|
|
## Phase 10: Documentation
|
|
|
|
### 10.1 README.md Structure
|
|
```markdown
|
|
# MCP Server for MyService
|
|
|
|
MCP integration for MyService. Enables Claude Desktop to [core value prop].
|
|
|
|
## Features
|
|
- ✅ List/search/CRUD contacts
|
|
- ✅ Analytics dashboard (MCP App)
|
|
- ✅ Pipeline visualization (MCP App)
|
|
- ✅ Progress tracking for imports
|
|
|
|
## Installation
|
|
[npx / manual / docker options]
|
|
|
|
## Configuration
|
|
[Environment variables with .env.example]
|
|
|
|
## Available Tools
|
|
[List of tools with descriptions]
|
|
|
|
## MCP Apps (Rich UI)
|
|
[List of app tools with screenshots]
|
|
|
|
## Development
|
|
[Build/dev instructions]
|
|
```
|
|
|
|
### 10.2 .env.example
|
|
```bash
|
|
# MyService API Credentials
|
|
MY_SERVICE_API_KEY=your_api_key_here
|
|
MY_SERVICE_API_SECRET=your_secret_here
|
|
|
|
# Optional: Override base URL
|
|
# MY_SERVICE_BASE_URL=https://sandbox.api.myservice.com
|
|
|
|
# Optional: Logging
|
|
# LOG_LEVEL=debug
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 11: Deployment
|
|
|
|
### 11.1 Docker
|
|
- [ ] Multi-stage Dockerfile
|
|
- [ ] .dockerignore file
|
|
- [ ] Test build locally
|
|
- [ ] Test run locally
|
|
|
|
### 11.2 Railway
|
|
- [ ] railway.json with build + start commands
|
|
- [ ] Environment variables documented
|
|
- [ ] Test deployment
|
|
|
|
### 11.3 npm Publishing
|
|
- [ ] `bin` field in package.json
|
|
- [ ] `files` field includes only dist/
|
|
- [ ] .npmignore excludes src/, .env
|
|
- [ ] Keywords for discoverability
|
|
- [ ] Test `npx` installation locally
|
|
|
|
### 11.4 GitHub
|
|
- [ ] README.md complete
|
|
- [ ] LICENSE file
|
|
- [ ] .gitignore excludes node_modules, dist, .env
|
|
- [ ] GitHub Actions for CI/CD (optional)
|
|
|
|
---
|
|
|
|
## Production Checklist (Final Review)
|
|
|
|
### Code Quality
|
|
- [ ] All tools have `_meta.labels`
|
|
- [ ] All parameters have descriptions
|
|
- [ ] Required fields marked explicitly
|
|
- [ ] Pagination implemented for list operations
|
|
- [ ] Error handling in all tool handlers
|
|
- [ ] No hardcoded API keys or secrets
|
|
- [ ] Logging for important operations
|
|
|
|
### Features
|
|
- [ ] Lazy-loaded resources for large datasets
|
|
- [ ] Progress notifications for long operations (>5s)
|
|
- [ ] MCP Apps for visual data (if applicable)
|
|
- [ ] Prompts for common workflows (if applicable)
|
|
|
|
### Documentation
|
|
- [ ] README with installation instructions
|
|
- [ ] .env.example with all required variables
|
|
- [ ] Tool descriptions clear and helpful
|
|
- [ ] Examples in README
|
|
|
|
### Deployment
|
|
- [ ] Compiles without errors
|
|
- [ ] Runs in Claude Desktop
|
|
- [ ] Docker image builds (if using Docker)
|
|
- [ ] Railway deploys successfully (if using Railway)
|
|
- [ ] npm package installs via npx (if publishing)
|
|
|
|
---
|
|
|
|
## Anti-Patterns to Avoid
|
|
|
|
❌ **No labels on tools** — Always add `_meta.labels`
|
|
❌ **Loading all data upfront** — Use lazy-loaded resources
|
|
❌ **No pagination** — Every list operation needs page/pageSize
|
|
❌ **Silent failures** — Always log errors and return clear messages
|
|
❌ **No progress for slow ops** — Add progress notifications for >5s operations
|
|
❌ **Building apps when not needed** — Only build apps if visually beneficial
|
|
❌ **Missing descriptions** — Every parameter needs a description
|
|
❌ **No environment validation** — Check env vars on startup
|
|
❌ **Skipping error handling** — Wrap all tool handlers in try-catch
|
|
❌ **Generic error messages** — Be specific ("Contact not found" not "Error")
|
|
|
|
---
|
|
|
|
## Reference Materials
|
|
|
|
- **Skills:**
|
|
- `mcp-server-development` — Full TypeScript patterns
|
|
- `mcp-apps-integration` — MCP Apps guide
|
|
- `mcp-deployment` — Docker/Railway/npm
|
|
|
|
- **Example Servers:**
|
|
- `/Users/jakeshore/.clawdbot/workspace/mcp-diagrams/mcp-servers/`
|
|
- 30 production servers with all patterns
|
|
|
|
- **Example Apps:**
|
|
- `/Users/jakeshore/.clawdbot/workspace/mcp-diagrams/ghl-mcp-apps-only/`
|
|
- 11 production apps with UI components
|
|
|
|
---
|
|
|
|
## TL;DR — The Golden Rules
|
|
|
|
1. **Labels on every tool** — category, access, complexity
|
|
2. **Lazy-load large datasets** — Use resources, not tools
|
|
3. **Paginate everything** — page/pageSize on all lists
|
|
4. **Progress for slow ops** — >5 seconds = progress notifications
|
|
5. **Apps for visual data** — Grids, dashboards, cards, timelines
|
|
6. **Log important operations** — Info, Warning, Error levels
|
|
7. **Handle errors gracefully** — Clear messages, no silent failures
|
|
8. **Document thoroughly** — README, .env.example, descriptions
|
|
9. **Test before shipping** — All tools work in Claude Desktop
|
|
10. **Deploy with confidence** — Docker, Railway, npm ready to go
|
|
|
|
**Follow this blueprint and your MCP servers will be production-ready, usable, and optimized for February 2026.**
|