mcp-server-development

Expert guidance for building MCP (Model Context Protocol) servers using the TypeScript SDK. Use when developing MCP servers, implementing tools/resources/prompts, or working with the @modelcontextprotocol/sdk package. Covers server initialization, request handlers, Zod schemas, error handling, and JSON-RPC patterns.

5 stars

Best use case

mcp-server-development is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Expert guidance for building MCP (Model Context Protocol) servers using the TypeScript SDK. Use when developing MCP servers, implementing tools/resources/prompts, or working with the @modelcontextprotocol/sdk package. Covers server initialization, request handlers, Zod schemas, error handling, and JSON-RPC patterns.

Teams using mcp-server-development should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/mcp-server-development/SKILL.md --create-dirs "https://raw.githubusercontent.com/akiojin/llmlb/main/.claude/skills/mcp-server-development/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/mcp-server-development/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How mcp-server-development Compares

Feature / Agentmcp-server-developmentStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Expert guidance for building MCP (Model Context Protocol) servers using the TypeScript SDK. Use when developing MCP servers, implementing tools/resources/prompts, or working with the @modelcontextprotocol/sdk package. Covers server initialization, request handlers, Zod schemas, error handling, and JSON-RPC patterns.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

This skill provides comprehensive guidance for building robust MCP servers, with specific focus on the unity-mcp-server architecture and patterns.

## Core Philosophy

MCP servers bridge AI assistants to external systems. They must be:
- **Reliable**: Handle errors gracefully, never crash unexpectedly
- **Discoverable**: Tools should have clear, self-documenting schemas
- **Performant**: Minimize latency, especially for stdio transport
- **Protocol-compliant**: Follow JSON-RPC 2.0 and MCP spec exactly

## Architecture Patterns

### Handler-Based Design

**ALWAYS** use a handler class per tool. Each handler encapsulates:
- Input validation (Zod schema)
- Business logic execution
- Error handling and response formatting

```javascript
// Pattern: One handler per tool
export class SystemPingToolHandler extends BaseToolHandler {
  constructor(unityConnection) {
    super({
      name: 'system_ping',
      description: 'Check Unity Editor connectivity',
      inputSchema: { type: 'object', properties: {} }
    });
    this.unityConnection = unityConnection;
  }

  async execute(params) {
    const result = await this.unityConnection.send({ command: 'ping' });
    return { status: 'ok', ...result };
  }
}
```

### BaseToolHandler Contract

All handlers MUST:
1. Call `super()` with tool metadata
2. Implement `execute(params)` method
3. Return plain objects (framework handles JSON-RPC wrapping)
4. Throw errors with descriptive messages

### Input Validation with Zod

**ALWAYS** validate inputs before processing:

```javascript
import { z } from 'zod';

const inputSchema = z.object({
  name: z.string().min(1).describe('GameObject name'),
  primitiveType: z.enum(['cube', 'sphere', 'cylinder']).optional()
});

validate(input) {
  return inputSchema.parse(input);
}
```

## Transport Layer

### Content-Length Framing (Standard)

MCP uses LSP-style Content-Length framing for stdio:

```
Content-Length: 123\r\n
\r\n
{"jsonrpc":"2.0","id":1,"method":"tools/call"...}
```

**ALWAYS** use Content-Length for output. NEVER mix framing formats in a session.

### Hybrid Input (Compatibility)

Accept both Content-Length and NDJSON input for client compatibility:
- Claude Desktop: Content-Length
- Some CLI tools: NDJSON (newline-delimited)

## Error Handling

### Structured Errors

Use MCP error codes from the spec:

```javascript
const McpError = {
  ParseError: -32700,
  InvalidRequest: -32600,
  MethodNotFound: -32601,
  InvalidParams: -32602,
  InternalError: -32603
};

throw new Error(JSON.stringify({
  code: McpError.InvalidParams,
  message: 'primitiveType must be one of: cube, sphere, cylinder'
}));
```

### Error Response Format

```javascript
{
  jsonrpc: '2.0',
  id: requestId,
  error: {
    code: -32602,
    message: 'Invalid params',
    data: { field: 'name', issue: 'required' }
  }
}
```

## Unity-Specific Patterns

### Command Protocol

Unity communication uses a simple request/response pattern:

```javascript
const result = await this.unityConnection.send({
  command: 'gameobject_create',
  params: { name: 'Cube', primitiveType: 'cube' }
});
```

### Workspace Root Resolution

**ALWAYS** include `workspaceRoot` in commands requiring file paths:

```javascript
execute(params) {
  return this.unityConnection.send({
    command: 'screenshot_capture',
    workspaceRoot: config.workspaceRoot,
    ...params
  });
}
```

## Testing Patterns

### TDD for Handlers

1. **Contract test first**: Define expected input/output schema
2. **Mock Unity connection**: Isolate handler logic
3. **Test error paths**: Invalid input, connection failures
4. **Test happy path last**: After contracts are verified

```javascript
describe('CreateGameObjectHandler', () => {
  it('validates primitiveType enum', async () => {
    const handler = new CreateGameObjectHandler(mockConnection);
    await assert.rejects(
      () => handler.handle({ name: 'Cube', primitiveType: 'invalid' }),
      /primitiveType must be one of/
    );
  });
});
```

### Integration Testing

Test full request/response cycle including JSON-RPC framing:

```javascript
const stdin = new PassThrough();
const stdout = new PassThrough();
const transport = new HybridStdioServerTransport(stdin, stdout);

stdin.write('Content-Length: 50\r\n\r\n{"jsonrpc":"2.0","id":1,"method":"ping"}');
// Assert stdout contains Content-Length response
```

## Common Mistakes

**Mixing framing formats**:
- NEVER: Output NDJSON after receiving Content-Length input
- ALWAYS: Output Content-Length regardless of input format

**Swallowing errors**:
- NEVER: `catch (e) { return null; }`
- ALWAYS: Propagate errors with context

**Missing validation**:
- NEVER: Trust raw input from clients
- ALWAYS: Validate with Zod before processing

**Blocking stdio**:
- NEVER: Synchronous operations on transport
- ALWAYS: Use async/await throughout

## Handler Registration

Register all handlers in a central index:

```javascript
// src/handlers/index.js
export function createHandlers(unityConnection) {
  return [
    new SystemPingToolHandler(unityConnection),
    new CreateGameObjectHandler(unityConnection),
    new ScreenshotHandler(unityConnection),
    // ...
  ];
}
```

## Remember

- **Content-Length always**: Output framing must be consistent
- **Validate everything**: Never trust client input
- **One handler, one tool**: Keep handlers focused
- **Test error paths**: Most bugs hide in error handling
- **Protocol compliance**: Follow JSON-RPC 2.0 exactly

Related Skills

gwt-spec-to-issue-migration

5
from akiojin/llmlb

Migrate legacy spec sources to artifact-first GitHub Issue specs. Supports local `specs/SPEC-*` directories and body-canonical `gwt-spec` Issues using the bundled migration script.

gwt-pty-communication

5
from akiojin/llmlb

PTY based communication tools for Project Mode orchestration (Lead/Coordinator/Developer).

gwt-pr

5
from akiojin/llmlb

Create or update GitHub Pull Requests with the gh CLI, including deciding whether to create a new PR or only push based on existing PR merge status. Use when the user asks to open/create/edit a PR, generate a PR body/template, or says 'open a PR/create a PR/gh pr'. Defaults: base=develop, head=current branch (same-branch only; never create/switch branches).

gwt-pr-check

5
from akiojin/llmlb

Check GitHub PR status with the gh CLI, including unmerged PR detection and post-merge new-commit detection for the current branch.

gwt-fix-pr

5
from akiojin/llmlb

Inspect GitHub PR for CI failures, merge conflicts, update-branch requirements, reviewer comments, change requests, and unresolved review threads. Create fix plans and implement after user approval. Reply to ALL reviewer comments with action taken or reason for not addressing, then resolve threads. Notify reviewers after fixes.

release

5
from akiojin/llmlb

Execute the release workflow when the user asks `release` or `/release`: sync develop, update version/changelog, create `chore(release)` commit, collect closing issues, create develop->main release PR, and verify release/publish artifacts.

hotfix

5
from akiojin/llmlb

Execute the hotfix workflow when the user asks `hotfix` or `/hotfix`: create a hotfix branch from main, guide fix+checks, open PR to main, and confirm patch release.

drawio

5
from akiojin/llmlb

Create and edit draw.io diagrams in XML format. Use when the user wants to create flowcharts, architecture diagrams, sequence diagrams, or any visual diagrams. Handles XML structure, styling, fonts (Noto Sans JP), arrows, connectors, and PNG export.

skill-installer

5
from akiojin/llmlb

Install Codex skills into $CODEX_HOME/skills from a curated list or a GitHub repo path. Use when a user asks to list installable skills, install a curated skill, or install a skill from another repo (including private repos).

skill-creator

5
from akiojin/llmlb

Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Codex's capabilities with specialized knowledge, workflows, or tool integrations.

plan

5
from akiojin/llmlb

Generate a plan for how an agent should accomplish a complex coding task. Use when a user asks for a plan, and optionally when they want to save, find, read, update, or delete plan files in $CODEX_HOME/plans (default ~/.codex/plans).

web-design-guidelines

5
from akiojin/llmlb

Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".