The Model Context Protocol (MCP) standardizes how AI assistants interact with external tools and data. By building your own MCP server in TypeScript, you unlock custom integrations — internal APIs, deployment hooks, CMS bridges — without waiting for official servers. TypeScript gives you type safety, modern async patterns, and excellent SDK support.
This tutorial walks you through a minimal but production-ready MCP server using @modelcontextprotocol/sdk. You'll expose one tool over stdio, add a resource, and connect it to Claude Code for testing. Most developers can ship a useful internal server in under an hour.
Prerequisites
Node.js 20+ (LTS recommended)
pnpm (or npm/yarn)
A TypeScript project initialized
Claude Code for end-to-end testing (optional but recommended)
Practical deep-dives on LLMs, developer tools, and AI engineering. No filler. Unsubscribe any time.
// written byFIG. AUTH-01
538
Mahmudul Haque Qudrati
CEO & ML Engineer
CEO and ML Engineer at Pristren. Builds AI-powered software for teams and writes about machine learning, LLMs, developer tools, and practical AI applications.
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
const server = new McpServer({ name: 'pristren-internal', version: '1.0.0' });
server.tool(
'get_deploy_status',
'Returns last deploy status for an app slug',
{ app: z.string().describe('App slug e.g. zlyqor_web') },
async ({ app }) => {
// Replace with real API call
const status = { app, env: 'production', ok: true, version: '1.2.3' };
return {
content: [{ type: 'text', text: JSON.stringify(status, null, 2) }],
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
Explanation
McpServer: Core class from the SDK. You provide a name and version.
server.tool(): Registers a tool. First argument is the tool name (snake_case), second is a description, third is a Zod schema for parameters, fourth is the handler function.
StdioServerTransport: Communicates via standard input/output. Perfect for local development and Claude Code integration.
Handler return: Must include a content array with at least one text content item. You can also return images or embedded resources.
Build and test locally:
pnpm build
node dist/index.js
The server will start and listen for JSON-RPC messages on stdin. You can test it manually with a tool like mcp-cli or connect it to Claude Code.
Step 2: Connect to Claude Code
Claude Code supports MCP servers via the claude mcp add command. Register your server:
claude mcp add pristren-internal -- node dist/index.js
Now you can prompt Claude Code to use your tool:
"Use pristren-internal to check deploy status for zlyqor_web."
Claude will call the get_deploy_status tool with app: "zlyqor_web" and display the result. You can also chain multiple tools in one conversation.
Troubleshooting
If Claude doesn't find the server, verify the path to dist/index.js is absolute or relative to your working directory.
Check that the server starts without errors by running the command directly.
Use claude mcp list to see all registered servers.
Step 3: Add Resources (Read-Only Data)
Resources expose static data that the agent can read without executing shell commands. This is useful for configuration schemas, documentation, or reference data.
Resources use URIs for identification. The handler returns an array of content items. You can also return binary data with MIME types.
Step 4: Add Prompts (Optional)
Prompts are reusable templates that guide the AI on how to use your tools. They're like meta-instructions.
server.prompt('deploy-check', 'Check deploy status for an app', {
app: z.string().describe('App slug'),
}, ({ app }) => ({
messages: [{
role: 'user',
content: {
type: 'text',
text: `Use the get_deploy_status tool to check the deploy status for ${app}.`,
},
}],
}));
Prompts are especially useful when you have complex workflows that require multiple tool calls.
Production Checklist
Before deploying your MCP server to production, consider these best practices:
Validate inputs with Zod: Always use Zod schemas to validate tool parameters. This prevents malformed requests and provides clear error messages.
Never return secrets in tool output: If your tool calls an internal API, strip sensitive fields like API keys or tokens before returning.
Log tool calls server-side: For audit and debugging, log each tool invocation with timestamp, parameters, and result size.
Compact responses: AI models have token limits. Return only essential data. For large datasets, consider pagination or summarization. See our guide on MCP token bloat.
Version semver: Use semantic versioning for your server. Pin the version in your team's .mcp.json to avoid breaking changes.
Error handling: Wrap tool handlers in try-catch and return user-friendly error messages.
Pristren builds AI-powered software for teams. Zlyqor is our all-in-one workspace — chat, projects, time tracking, AI meeting summaries, and invoicing.
Frequently Asked Questions
What is an MCP server and why build one in TypeScript?
An MCP (Model Context Protocol) server is a lightweight service that exposes tools, resources, and prompts to AI assistants like Claude. Building it in TypeScript gives you type safety, modern async patterns, and seamless integration with the official `@modelcontextprotocol/sdk`. It's ideal for custom internal integrations without waiting for third-party servers.
How does an MCP server work with Claude Code?
Claude Code connects to MCP servers via stdio transport. You register your server with `claude mcp add`, and Claude can then call your tools during conversations. The server listens for JSON-RPC messages on stdin and returns results on stdout. This allows Claude to execute custom actions like checking deploy status or querying internal APIs.
What are best practices for building an MCP server in TypeScript?
Best practices include: validating inputs with Zod schemas, never returning secrets in tool output, logging tool calls for audit, keeping responses compact to avoid token bloat, using semantic versioning, handling errors gracefully with `isError: true`, and choosing the right transport (stdio for local, HTTP for remote with authentication).
How much does it cost to build and run an MCP server?
Building an MCP server is free — the SDK is open-source and you only need Node.js. Running costs depend on your infrastructure: a local server costs nothing, while a cloud-hosted HTTP server may incur minimal compute costs (e.g., $5–$20/month on a small VPS). The main cost is development time, which is typically under an hour for a basic server.
Is building an MCP server in TypeScript worth it in 2026?
Absolutely. MCP is becoming the standard for AI-tool integration, and TypeScript remains the most popular language for server-side development. Building your own server gives you full control over data and workflows, avoids vendor lock-in, and can be done quickly. It's especially valuable for teams with internal APIs or custom deployment pipelines.