# 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.

- Skill: `majiayu000/mcp-patterns` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/mcp-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/mcp-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- License: MIT
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/mcp-patterns

---


# MCP 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](../../packages/mcp/README.md) for setup and usage.
> **For universal patterns**: See [`.claude/rules/code-patterns.md`](../../.claude/rules/code-patterns.md)

## When to Use This Skill

Use this skill when:
- Developing or contributing to `@youdotcom-oss/mcp` package
- 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

```bash
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:

```typescript
// ✅ 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?**
- `.describe()` provides human-readable documentation in MCP inspector
- 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:

```typescript
// ✅ 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
- `isError: true` flag allows clients to handle errors gracefully

### Logging

Use `getLogger(mcp)` for MCP server notifications, NEVER `console.log`:

```typescript
// ✅ 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
- `console.log` outputs to stdout, interfering with stdio transport
- `getLogger()` properly routes messages through MCP notification system

### Response Format

All MCP tools must return both `content` and `structuredContent`:

```typescript
return {
  content: [
    { type: 'text', text: 'User-readable summary' }
  ],
  structuredContent: {
    results: [...], // Structured data
    metadata: {...}
  }
};
```

**Why this pattern?**
- `content` provides human-readable text for display
- `structuredContent` enables programmatic processing by clients
- Both formats serve different use cases

### MCP Inspector

Test and debug MCP tools interactively:

```bash
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:

```typescript
// ✅ 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):
1. MCP Client → stdin → `stdio.ts` → MCP Server → You.com API → stdout → MCP Client

**HTTP Transport** (Remote Deployment):
1. MCP Client → SSE (`/mcp`) → `http.ts` (Bearer auth) → MCP Server → You.com API → SSE → MCP Client

### Core Files

- `src/stdio.ts` - Stdio transport entry point
- `src/http.ts` - HTTP transport with Bearer token auth, `/mcp` (SSE), `/mcp-health`
- `src/get-mcp-server.ts` - MCP server factory
- `src/*/register-*-tool.ts` - Tool registration
- `src/*/*.schemas.ts` - Zod schemas
- `src/*/*.utils.ts` - API calls, formatting
- `src/utils.ts` - Public API export for library consumers

## Troubleshooting

### YDC_API_KEY not found

```bash
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 `bun test --bail` to stop after first failure
- Check rate limits at [api.you.com](https://api.you.com)

### MCP Client Connection Issues (Stdio)

```bash
# Verify server starts
bun run dev

# Check API key is set
echo $YDC_API_KEY
```

### MCP Client Connection Issues (HTTP)

```bash
# 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](../../AGENTS.md#publishing)

### MCP-Specific Deployment

After npm publish, this package triggers:

1. **Remote Deployment** (via `repository_dispatch`):
   - `update-mcp-version` event to deployment repository
   - Stable releases: `deploy-mcp-production` after version update completes
   - Prereleases skip production deployment

2. **Anthropic MCP Registry** (stable releases only):
   - Auto-updates `server.json` versions
   - Makes server discoverable at `io.github.youdotcom-oss/mcp`
   - Runs after successful production deployment

**Workflow**: `.github/workflows/publish-mcp.yml`

## Related Skills

- [`.claude/rules/code-patterns.md`](../../.claude/rules/code-patterns.md) - Universal code patterns
- [`.claude/rules/git-workflow.md`](../../.claude/rules/git-workflow.md) - Git conventions
- [`.claude/skills/documentation`](../../.claude/skills/documentation/) - Documentation standards

## Contributing

See [root AGENTS.md](../../AGENTS.md#contributing) and [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines.

**Package scope**: Use `mcp` in commit messages:

```bash
feat(mcp): add new search filter
fix(mcp): resolve timeout issue
```

