Claude-skill-registry-data mcp-patterns
MCP server development patterns including Zod schema design, error handling, logging, response format, and testing strategies. Use when developing or contributing to @youdotcom-oss/mcp package.
git clone https://github.com/majiayu000/claude-skill-registry-data
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry-data "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/mcp-patterns" ~/.claude/skills/majiayu000-claude-skill-registry-data-mcp-patterns && rm -rf "$T"
data/mcp-patterns/SKILL.mdMCP Server Development Patterns
Development patterns for building MCP (Model Context Protocol) servers with the You.com MCP package.
For end users: See packages/mcp/README.md for setup and usage. For universal patterns: See
.claude/rules/code-patterns.md
When to Use This Skill
Use this skill when:
- Developing or contributing to
package@youdotcom-oss/mcp - Implementing MCP tools and utilities
- Debugging MCP server issues
- Understanding MCP-specific patterns and conventions
Tech Stack
- Runtime: Bun >= 1.2.21 (not Node.js)
- MCP SDK: @modelcontextprotocol/sdk ^1.24.3
- Validation: Zod ^4.1.13
- HTTP Transport: Hono ^4.10.7 with Bearer token auth
- Testing: Bun test (built-in test runner)
- Code Quality: Biome 2.3.8 (linter + formatter)
Quick Start
cd packages/mcp # Install dependencies (from monorepo root) cd ../.. bun install # Set up API key echo "export YDC_API_KEY=your-actual-api-key-here" > .env source .env # From package directory cd packages/mcp bun run dev # Start stdio server bun start # Start HTTP server on port 4000 bun test # Run tests bun run check # Run all checks
MCP-Specific Patterns
Schema Design with Zod
All MCP tool inputs and API responses must use Zod schemas:
// ✅ Use .describe() for documentation (shows in MCP inspector) export const SearchQuerySchema = z.object({ query: z.string().describe('Search query string'), count: z.number().int().min(1).max(20).default(10).describe('Number of results'), }); // ✅ Validate API responses const response = SearchApiResponseSchema.parse(await apiCall());
Why this pattern?
provides human-readable documentation in MCP inspector.describe()- Zod validation catches API response format changes early
- Type safety ensures tool inputs match expected schema
Error Handling
MCP tools must NEVER throw errors - always return error messages:
// ✅ Correct - return error as content try { const result = await apiCall(); return { content: [{ type: 'text', text: result }] }; } catch (err: unknown) { const error = err instanceof Error ? err.message : String(err); return { content: [{ type: 'text', text: `Error: ${error}` }], isError: true }; } // ❌ Wrong - throwing breaks MCP protocol throw new Error('API failed');
Why this pattern?
- MCP protocol expects all tool calls to return responses
- Throwing errors breaks the client-server connection
flag allows clients to handle errors gracefullyisError: true
Logging
Use
getLogger(mcp) for MCP server notifications, NEVER console.log:
// ✅ Correct - MCP notifications const log = getLogger(mcp); log('Calling You.com API'); // ❌ Wrong - bypasses MCP protocol console.log('Calling You.com API');
Why this pattern?
- MCP clients expect structured notifications via protocol
outputs to stdout, interfering with stdio transportconsole.log
properly routes messages through MCP notification systemgetLogger()
Response Format
All MCP tools must return both
content and structuredContent:
return { content: [ { type: 'text', text: 'User-readable summary' } ], structuredContent: { results: [...], // Structured data metadata: {...} } };
Why this pattern?
provides human-readable text for displaycontent
enables programmatic processing by clientsstructuredContent- Both formats serve different use cases
MCP Inspector
Test and debug MCP tools interactively:
bun run inspect # Automatically loads .env variables
Why this tool?
- Interactive testing without writing test code
- Visual inspection of tool schemas and responses
- Quick validation of changes during development
Testing
MCP-Specific Testing: Shared vs Dedicated Clients
Long-running tests with retries may disconnect shared MCP clients from
beforeAll. Use dedicated clients for isolated tests:
// ✅ Dedicated client for long-running or isolated tests test.serial('memory test', async () => { const stdioPath = Bun.resolveSync('../../bin/stdio', import.meta.dir); const transport = new StdioClientTransport({ command: 'npx', args: [stdioPath], env: { YDC_API_KEY }, }); const memoryClient = new Client({ name: 'memory-test-client', version: '1.0.0', }); await memoryClient.connect(transport); await memoryClient.callTool(/* ... */); await memoryClient.close(); }, { timeout: 15_000 });
When to use:
- Shared client: Quick tests (<30s), no retry, basic integration tests
- Dedicated client: Long tests (>30s), tests with retry, performance tests
See
src/tests/processing-lag.spec.ts for complete example.
Architecture
Request Flow
Stdio Transport (Local Development):
- MCP Client → stdin →
→ MCP Server → You.com API → stdout → MCP Clientstdio.ts
HTTP Transport (Remote Deployment):
- MCP Client → SSE (
) →/mcp
(Bearer auth) → MCP Server → You.com API → SSE → MCP Clienthttp.ts
Core Files
- Stdio transport entry pointsrc/stdio.ts
- HTTP transport with Bearer token auth,src/http.ts
(SSE),/mcp/mcp-health
- MCP server factorysrc/get-mcp-server.ts
- Tool registrationsrc/*/register-*-tool.ts
- Zod schemassrc/*/*.schemas.ts
- API calls, formattingsrc/*/*.utils.ts
- Public API export for library consumerssrc/utils.ts
Troubleshooting
YDC_API_KEY not found
echo "export YDC_API_KEY=your-actual-api-key-here" > .env source .env echo $YDC_API_KEY # Verify it's set
Test Failures with API Rate Limits
Symptom: Tests fail with 429 (Too Many Requests)
Solution:
- Wait a few minutes before re-running tests
- Run specific test suites instead of all at once
- Use
to stop after first failurebun test --bail - Check rate limits at api.you.com
MCP Client Connection Issues (Stdio)
# Verify server starts bun run dev # Check API key is set echo $YDC_API_KEY
MCP Client Connection Issues (HTTP)
# Verify server starts on port 4000 bun start # Test health endpoint curl http://localhost:4000/mcp-health # Test with valid Bearer token curl -H "Authorization: Bearer your-key-here" \ http://localhost:4000/mcp
Publishing
For standard publishing process: See root AGENTS.md
MCP-Specific Deployment
After npm publish, this package triggers:
-
Remote Deployment (via
):repository_dispatch
event to deployment repositoryupdate-mcp-version- Stable releases:
after version update completesdeploy-mcp-production - Prereleases skip production deployment
-
Anthropic MCP Registry (stable releases only):
- Auto-updates
versionsserver.json - Makes server discoverable at
io.github.youdotcom-oss/mcp - Runs after successful production deployment
- Auto-updates
Workflow:
.github/workflows/publish-mcp.yml
Related Skills
- Universal code patterns.claude/rules/code-patterns.md
- Git conventions.claude/rules/git-workflow.md
- Documentation standards.claude/skills/documentation
Contributing
See root AGENTS.md and CONTRIBUTING.md for guidelines.
Package scope: Use
mcp in commit messages:
feat(mcp): add new search filter fix(mcp): resolve timeout issue