Add MCP Gold Standard + wire into AGENTS.md as mandatory reference

This commit is contained in:
Jake Shore 2026-02-14 05:33:50 -05:00
parent 9d5c7cc0e8
commit bc27e38b01
2 changed files with 435 additions and 1 deletions

View File

@ -82,12 +82,19 @@ This keeps identity, memory, and progress backed up. Consider making it private
- End every reply with a model tag: `· sonnet` or `· opus` - End every reply with a model tag: `· sonnet` or `· opus`
- This costs ~2 tokens, helps Jake track what's being used - This costs ~2 tokens, helps Jake track what's being used
## MCP Work — MANDATORY Commit Rule + Factory Checklist ## MCP Work — MANDATORY Rules
**ALL MCP-related work MUST be committed and pushed to `mcpengine-repo/` (`BusyBee3333/mcpengine`).** **ALL MCP-related work MUST be committed and pushed to `mcpengine-repo/` (`BusyBee3333/mcpengine`).**
This is non-negotiable. The mcpengine repo is the single source of truth. This is non-negotiable. The mcpengine repo is the single source of truth.
### MANDATORY: Gold Standard
**Before ANY MCP server work (building, fixing, upgrading, reviewing):** Read `mcp-gold-standard.md`.
This file defines the EXACT architecture, patterns, and quality bar for every MCP server.
It covers: server architecture (main.ts/server.ts with lazy loading), API client patterns, tool file structure (Zod + naming + descriptions + pagination), React app patterns (ErrorBoundary, dark theme, mock data), landing page patterns (chat demo with 6 widget types, GSAP animations, site-generator config), and README requirements.
**Every sub-agent prompt for MCP work must reference the relevant sections from this file.**
**No exceptions. This is the gold standard. Jake said so.**
### MANDATORY: Factory Checklist ### MANDATORY: Factory Checklist
**Before spawning ANY MCP build agent:** Read `mcp-factory-checklist.md` and follow the pre-flight checklist. **Before spawning ANY MCP build agent:** Read `mcp-factory-checklist.md` and follow the pre-flight checklist.
**After ANY agent completes:** Run the post-completion verification. NEVER trust agent narratives — verify the filesystem. **After ANY agent completes:** Run the post-completion verification. NEVER trust agent narratives — verify the filesystem.

427
mcp-gold-standard.md Normal file
View File

@ -0,0 +1,427 @@
# MCP Server Gold Standard — MANDATORY REFERENCE
> **READ THIS before ANY MCP server work. No exceptions.**
> This is the definitive spec for how every MCPEngine server must be built.
> Last updated: 2026-02-14
---
## 1. Server Architecture
### `main.ts` — Entry Point
```typescript
#!/usr/bin/env node
```
- Shebang line for CLI execution
- Env validation with clear error messages (e.g., "Get your access token from: Settings > Apps > ...")
- Graceful shutdown handlers for SIGINT/SIGTERM
- Health check support
- Dual transport: stdio (default) + HTTP/SSE option via `--http --port=3000`
- Loads config → creates API client → creates server → starts transport
### `server.ts` — Server Class
- **MUST be a CLASS** (e.g., `ShopifyMCPServer`), not inline code
- `toolModules: Map<string, () => Promise<ToolModule[]>>` for **lazy loading**
- `setupToolModules()` — registers each tool file via dynamic `import()`:
```typescript
this.toolModules.set('orders', async () => {
const module = await import('./tools/orders.js');
return module.default;
});
```
- `setupHandlers()` — registers `ListToolsRequestSchema` and `CallToolRequestSchema`
- `loadAllTools()` — resolves all lazy modules for ListTools
- CallTool handler routes by tool name to correct handler function
- Capabilities: `{ tools: {}, resources: {} }`
### `package.json`
```json
{
"name": "@mcpengine/{platform-name}",
"version": "1.0.0",
"type": "module",
"main": "dist/main.js",
"bin": { "@mcpengine/{platform-name}": "dist/main.js" },
"scripts": {
"build": "tsc",
"start": "node dist/main.js",
"dev": "tsx watch src/main.ts"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.12.1",
"axios": "^1.7.0",
"zod": "^3.23.0"
},
"devDependencies": {
"typescript": "^5.6.0",
"tsx": "^4.19.0",
"@types/node": "^22.0.0"
}
}
```
### `tsconfig.json`
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "dist",
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true,
"resolveJsonModule": true,
"forceConsistentCasingInFileNames": true,
"noUncheckedIndexedAccess": true,
"jsx": "react-jsx"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "src/apps", "src/ui", "src/**/react-app"]
}
```
**NOTE:** Always exclude apps/ui from TSC — they compile separately.
---
## 2. API Client (`src/client/{platform}-client.ts` or `src/clients/{platform}.ts`)
- **Axios-based** with `AxiosInstance`
- Constructor takes config object: `{ accessToken, baseUrl, timeout?, apiVersion? }`
- **Request interceptor:** Timestamp logging of method + URL
- **Response interceptor:** Rate limit header parsing, warning at 80% threshold, error normalization
- Rate limit tracking: `{ current, max }` from response headers
- **Pagination helpers:** Return `{ data: T[], pageInfo: { hasNextPage, nextPageUrl } }`
- Typed error handling with status code + message
- Default timeout: 30000ms
- Base URL constructed from env vars
### Client Methods Pattern:
```typescript
async get<T>(path: string, params?: Record<string, unknown>): Promise<T>
async create<T>(path: string, data: unknown): Promise<T>
async update<T>(path: string, data: unknown): Promise<T>
async delete(path: string): Promise<void>
```
---
## 3. Tool Files (`src/tools/*.ts`)
### Structure:
```typescript
import { z } from 'zod';
import { PlatformClient } from '../clients/platform.js';
const ListOrdersInput = z.object({
limit: z.number().min(1).max(250).default(50).describe('Results per page'),
page_info: z.string().optional().describe('Cursor for pagination'),
status: z.enum(['open', 'closed', 'any']).optional().describe('Filter by status'),
created_at_min: z.string().optional().describe('Filter by min creation date (ISO 8601)'),
});
// ... more Zod schemas ...
export default [
{
name: '{platform}_list_orders',
description: 'List orders with pagination and filtering by status, date range, and financial status. Use when the user wants to browse, search, or export their order history. Returns paginated results with cursor-based navigation.',
inputSchema: {
type: 'object' as const,
properties: { /* JSON Schema from Zod */ },
required: ['limit'],
},
handler: async (input: unknown, client: PlatformClient) => {
const validated = ListOrdersInput.parse(input);
const result = await client.get('/orders.json', validated);
return {
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
};
},
},
// ... more tools
];
```
### Naming Conventions (MANDATORY):
- `{platform}_list_*` — paginated collections
- `{platform}_get_*` — single resource by ID
- `{platform}_create_*` — create new resource
- `{platform}_update_*` — update existing resource
- `{platform}_delete_*` — delete resource
- `{platform}_search_*` — query-based lookup
- Domain verbs: `{platform}_send_email`, `{platform}_cancel_order`, `{platform}_archive_card`
- **ALL snake_case, ALL lowercase**
- **NEVER** mix `fetch_*` / `get_*` / `retrieve_*` — pick ONE (we use `get_`)
### Description Requirements:
- **BAD:** "Lists contacts"
- **GOOD:** "Lists contacts from HubSpot with optional filtering by email, name, company, or lifecycle stage. Use when the user wants to browse, search, or export their contact database. Returns paginated results with cursor-based navigation. Supports up to 100 results per page."
- Every description must tell an AI agent **WHEN** and **WHY** to use the tool
- Include: what it returns, pagination details, filtering options, rate limit notes
### Pagination (MANDATORY for all `list_*` tools):
- `limit` param with min/max/default
- `page_info` or `cursor` or `offset` param
- Response includes `has_more` / `hasNextPage` indicator
- Response includes `next_cursor` / `next_page_url` for follow-up
### Handler Pattern:
1. Validate input with Zod `.parse(input)`
2. Call client method
3. Return `{ content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }`
### Tool Count Minimums:
| API Size | Minimum Tools |
|----------|--------------|
| Small (<30 endpoints) | 15-20 |
| Medium (30-100 endpoints) | 30-50 |
| Large (100+ endpoints) | 50-80+ |
| **7-8 tools = a demo, NOT a product** |
---
## 4. Types (`src/types/index.ts`)
- TypeScript interfaces for ALL API entities
- Export everything (interfaces, type aliases, enums)
- Include: request params, response types, pagination types, error types
- Example:
```typescript
export interface Contact {
id: string;
firstName: string;
lastName: string;
email: string;
phone?: string;
company?: string;
createdAt: string;
updatedAt: string;
}
export interface PaginatedResponse<T> {
data: T[];
pageInfo: {
hasNextPage: boolean;
nextPageUrl?: string;
};
}
```
---
## 5. Apps (`src/apps/{app-name}/`)
Each app is a **self-contained React application** in its own subdirectory.
### Files per app:
```
src/apps/{app-name}/
App.tsx — Main React component
main.tsx — Entry point with ErrorBoundary + Suspense
index.html — HTML shell
styles.css — Dark theme styling
```
### `main.tsx` Pattern:
```typescript
import { Suspense, lazy, Component, ErrorInfo, ReactNode } from 'react';
import { createRoot } from 'react-dom/client';
const App = lazy(() => import('./App'));
// ErrorBoundary class with getDerivedStateFromError + componentDidCatch
// LoadingSkeleton component with shimmer divs
const container = document.getElementById('root');
if (container) {
const root = createRoot(container);
root.render(
<ErrorBoundary>
<Suspense fallback={<LoadingSkeleton />}>
<App />
</Suspense>
</ErrorBoundary>
);
}
```
### `App.tsx` Pattern:
- Self-contained with **mock data** (no live API calls)
- `useState` for state management
- `useDebounce` hook for search
- `useToast` hook for notifications
- `useTransition` for non-blocking updates
- Search/filter/sort functionality
- Responsive layout
- Mock data should be realistic and platform-relevant
### `index.html`:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{App Name} - {Platform} MCP</title>
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>
```
### `styles.css` — Dark Theme:
```css
:root {
--bg-primary: #0f172a;
--bg-secondary: #1e293b;
--bg-tertiary: #334155;
--text-primary: #f1f5f9;
--text-secondary: #cbd5e1;
--text-muted: #94a3b8;
--accent: #3b82f6;
--accent-hover: #2563eb;
--success: #10b981;
--error: #ef4444;
--warning: #f59e0b;
--border: #475569;
}
```
### App Ideas per Platform Type:
- **CRM:** contact-manager, deal-pipeline, activity-feed, report-dashboard
- **E-commerce:** order-management, product-catalog, inventory-tracker, analytics-dashboard
- **Project Mgmt:** task-board, timeline-view, team-workload, sprint-dashboard
- **Support:** ticket-queue, knowledge-base, customer-timeline, satisfaction-dashboard
- **HR:** employee-directory, time-off-calendar, org-chart, payroll-dashboard
---
## 6. Landing Pages
### Generation:
- Use `landing-pages/site-generator.js` with config object
- Run: `node site-generator.js {platform-id}`
- Output: single HTML file
### Config Structure:
```javascript
{
name: 'Platform Name',
tagline: 'AI-Power Your {Domain} in 2 Clicks',
color: '#HEX', // Brand color
tools: '47', // Tool count string
description: 'The complete {Platform} MCP server. {What it does} with AI.',
features: [
{ title: 'Feature Name', desc: 'What it does in one sentence.' },
// 4 features
],
painPoints: [
{ bad: 'Manual way of doing X', good: 'AI does X automatically' },
// 3 pain points
]
}
```
### Chat Demo Config (`chatDemoData`):
```javascript
{
platformId: {
messages: [
{ type: 'user', text: 'Natural question about the platform' },
{
type: 'ai',
text: 'Response text',
widgetData: { type: 'metrics|tickets|board|deals|pnl|schedule', ... },
action: '✓ Summary of what was done'
},
{ type: 'user', text: 'Follow-up action request' },
{ type: 'ai', text: 'Confirmation', action: '✓ Action completed summary' }
]
}
}
```
### 6 Widget Types for Chat Demo:
1. **tickets** — Table with ID, subject, priority badge, time. Has summary + alert.
2. **metrics** — 3-column grid of metric cards with label, value, change (+/-). Has alert.
3. **board** — Kanban-style columns with cards
4. **deals** — Pipeline/deal cards with values
5. **pnl** — Profit/loss bars with labels
6. **schedule** — Time slots with bookings
### Landing Page Sections:
1. Hero with gradient text + glow effect
2. Features grid (4 cards with hover glow)
3. **Animated chat demo** — scroll-triggered GSAP, messages appear sequentially (1s delay)
4. Pain points (bad → good comparisons)
5. CTA section
6. Footer
### Animations:
- `animate-float` / `animate-float-delayed` / `animate-float-slow` — floating elements
- `card-glow:hover` — box-shadow + translateY(-4px)
- `gradient-shift` — animated gradient background
- `video-glow` — pulsing box-shadow
- GSAP ScrollTrigger for chat demo (plays once on viewport enter)
---
## 7. README.md
Every server MUST have a README with:
1. **Title + description**
2. **Features list** (bullet points of capabilities)
3. **Installation** (`npm install && npm run build`)
4. **Environment Variables table** — Variable, Required (✅/❌), Description, Example
5. **Getting Your Access Token** — Step-by-step for that specific platform
6. **Required API Scopes** — List of permissions needed
7. **Usage** — Stdio mode + HTTP mode examples
8. **Coverage Manifest:**
```
Total API endpoints: X
Tools implemented: Y
Intentionally skipped: Z (with reasons)
Coverage: Y/X = NN%
```
---
## 8. File Tree Summary
```
servers/{platform}/
├── package.json # @mcpengine/{platform}, type:module, bin field
├── tsconfig.json # ES2022, Node16, strict, exclude apps
├── README.md # Full docs + coverage manifest
├── src/
│ ├── main.ts # Entry: env validation, graceful shutdown
│ ├── server.ts # Server CLASS with lazy-loaded tool modules
│ ├── clients/ # (or client/)
│ │ └── {platform}.ts # Axios client with interceptors + rate limiting
│ ├── types/
│ │ └── index.ts # All TypeScript interfaces
│ ├── tools/
│ │ ├── orders.ts # export default [...tools]
│ │ ├── customers.ts
│ │ └── ... # One file per domain area
│ └── apps/
│ ├── order-management/
│ │ ├── App.tsx
│ │ ├── main.tsx
│ │ ├── index.html
│ │ └── styles.css
│ └── ... # One dir per app
└── landing-pages/
└── sites/{platform}.html # Generated landing page
```
---
*This is the gold standard. Every MCP server we build or fix must match this spec.*