This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: mcp-server-sdk-typescript

Model Context Protocol (MCP) TypeScript SDK Standard

Production invariants for developing MCP tool servers using @modelcontextprotocol/sdk: strict Zod input schemas, asynchronous tool call isolation, error payload formatting, and stdout JSON-RPC stream preservation.

Prohibited Anti-Pattern: AI creates MCP servers with console.log corrupting stdout JSON-RPC, untyped tool arguments without Zod schemas, or unhandled errors crashing daemon transports.

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Model Context Protocol (MCP) TypeScript SDK Standard - Production invariants for developing MCP tool servers using @modelcontextprotocol/sdk: strict Zod input schemas, asynchronous tool call isolation, error payload formatting, and stdout JSON-RPC stream preservation.
globs: src/mcp/**/*.ts, src/server/mcp/**/*.ts, mcp.ts
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/mcp-server-sdk-typescript"
---

# Model Context Protocol (MCP) TypeScript SDK Standard

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: AI creates MCP servers with console.log corrupting stdout JSON-RPC, untyped tool arguments without Zod schemas, or unhandled errors crashing daemon transports.

## System Constraints
You are an expert Model Context Protocol (MCP) engineer using @modelcontextprotocol/sdk. When implementing stdio-based MCP servers, never use console.log or print to stdout, as this instantly corrupts the JSON-RPC message framing and crashes client hosts. Direct all application logging exclusively to process.stderr.write or console.error. Always validate tool arguments using strict Zod schemas and map exceptions into formatted { content: [{ type: 'text', text: ... }], isError: true } error responses rather than unhandled promise rejections.

## Strict Guidelines
- NEVER emit debug output to stdout in stdio mode; route all diagnostic telemetry to process.stderr.write or console.error to avoid JSON-RPC framing corruption.
- Define all MCP tool parameters with explicit Zod schemas using z.object({...}) and pass them to zodToJsonSchema or SDK schema converters.
- Isolate tool execution inside try/catch blocks and return structured error objects with isError: true instead of throwing unhandled exceptions.
- Gracefully handle SIGINT and SIGTERM OS signals to close active transports and release network and database connection pools.

## Bad vs Good Implementations
### Stdio JSON-RPC Preservation & Zod Tool Definition

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: console.log writes arbitrary ASCII into stdout, immediately breaking JSON-RPC packet parsing in Claude Desktop, Cursor, and Windsurf.
```typescript
// Anti-pattern: console.log corrupts stdio JSON-RPC; untyped args crash server
import { Server } from "@modelcontextprotocol/sdk/server/index.js";

const server = new Server({ name: "weather-server", version: "1.0.0" }, { capabilities: { tools: {} } });
console.log("MCP Server starting on stdio..."); // CRITICAL BUG: Corrupts JSON-RPC stream!

server.setRequestHandler("callTool", async (request: any) => {
  // Untyped input: crashes if city is missing or not a string
  const response = await fetch(`https://api.weather.com/${request.params.arguments.city}`);
  return { content: [{ type: "text", text: await response.text() }] };
});
```

#### Production Standard (Correct)
> **Standard**: Safeguards the stdio pipe from contamination, strictly validates tool arguments with Zod, and returns recoverable error envelopes.
```typescript
// Production Standard: Clean stderr logging, Zod validation, structured error responses
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";

const CityQuerySchema = z.object({
  city: z.string().min(1).max(100).trim(),
  units: z.enum(["celsius", "fahrenheit"]).default("celsius"),
});

const server = new Server(
  { name: "weather-server", version: "1.0.0" },
  { capabilities: { tools: {} } }
);

// Safe diagnostic logging to stderr only
process.stderr.write("[MCP Info] Initializing stdio transport\n");

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name !== "get_weather") {
    return {
      content: [{ type: "text", text: `Unknown tool: ${request.params.name}` }],
      isError: true,
    };
  }

  const parseResult = CityQuerySchema.safeParse(request.params.arguments);
  if (!parseResult.success) {
    return {
      content: [{ type: "text", text: `Validation error: ${parseResult.error.message}` }],
      isError: true,
    };
  }

  try {
    const { city, units } = parseResult.data;
    return {
      content: [{ type: "text", text: JSON.stringify({ city, units, temp: 21, condition: "Sunny" }) }],
    };
  } catch (err: unknown) {
    const message = err instanceof Error ? err.message : String(err);
    return {
      content: [{ type: "text", text: `Execution failed: ${message}` }],
      isError: true,
    };
  }
});

const transport = new StdioServerTransport();
await server.connect(transport);
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Model Context Protocol (MCP) TypeScript SDK Standard

The Model Context Protocol (MCP) establishes an open JSON-RPC 2.0 communication standard enabling AI agents to query external tools, resources, and prompts across IDE hosts like Cursor, Claude Code, and Windsurf. In stdio transport architectures, stdout is strictly reserved for JSON-RPC frame serialization. Emitting application telemetry or console.log statements directly to stdout contaminates the transport pipe, triggering unrecoverable client framing desynchronization.

Framework Paradigm Shift & Drift MechanicsCoding assistants are trained heavily on standard CLI utilities where console.log is the conventional debugging output. In an MCP stdio server, however, stdout acts as the binary/protocol transport channel. Models also routinely omit Zod input schema validation, leading to silent type coercion bugs when host LLMs supply approximate or missing parameters.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
Stdout JSON-RPC Frame ContaminationAI places console.log('Starting server...') or console.log(data) in tool implementationsCritical
Immediately corrupts JSON-RPC packet framing, crashing Claude Desktop or Cursor MCP background daemons.
Strictly redirect all diagnostic logging to process.stderr.write or console.error; keep stdout 100% reserved for protocol frames.
Untyped Tool Arguments & Uncaught RejectionsAI declares tool handlers with raw any types and throws standard Error without catchingHigh
Causes unhandled promise rejections that kill the server process instead of returning structured recoverable errors.
Validate all arguments using strict Zod schemas and catch exceptions to return { content: [{ type: 'text', text: ... }], isError: true }.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

NEVER emit debug output to stdout in stdio mode

NEVER emit debug output to stdout in stdio mode; route all diagnostic telemetry to process.stderr.write or console.error to avoid JSON-RPC framing corruption.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Define all MCP tool parameters with explicit Zod schemas using z.object({...}) and pass them to zodToJsonSchema or SDK schema converters.

Define all MCP tool parameters with explicit Zod schemas using z.object({...}) and pass them to zodToJsonSchema or SDK schema converters.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Isolate tool execution inside try/catch blocks and return structured error objects with isError

Isolate tool execution inside try/catch blocks and return structured error objects with isError: true instead of throwing unhandled exceptions.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Gracefully handle SIGINT and SIGTERM OS signals to close active transports and release network and database connection pools.

Gracefully handle SIGINT and SIGTERM OS signals to close active transports and release network and database connection pools.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why does my MCP server disconnect immediately in Claude Desktop or Cursor?

The most frequent cause is debug logging to stdout (e.g. console.log). Because stdio transport uses standard input/output for JSON-RPC messages, any extraneous text breaks packet framing. Route all logs to process.stderr.write instead.

Q:How do I return errors in MCP tools without crashing the daemon?

Never let exceptions bubble out of the callTool request handler. Catch errors and return an MCP response envelope containing { content: [{ type: 'text', text: err.message }], isError: true }. This allows the AI agent to read the error message and self-correct.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

Model