Development14 min read

TypeScript AI Agent and MCP Server Development Guide

Guide to building AI agents with TypeScript using Model Context Protocol server patterns. MCP architecture, tool definition, and agent orchestration covered.

Digital Applied Team
April 1, 2026
14 min read
97M+

MCP Package Downloads (NPM)

3

Core Capabilities: Tools, Resources, Prompts

OAuth 2.1

Auth Standard (2026 Roadmap)

JSON-RPC

Wire Protocol for All Transports

Key Takeaways

MCP standardizes how AI agents access tools, data, and prompts: The Model Context Protocol provides a universal interface between LLMs and external systems. Instead of writing bespoke integrations for every model provider, you build one MCP server that Claude, GPT, Gemini, and any compliant client can connect to through standardized JSON-RPC messaging.
TypeScript is the first-class language for MCP server development: The official MCP TypeScript SDK provides type-safe tool definitions, resource schemas, and prompt templates. TypeScript's type system catches integration errors at compile time rather than runtime, which matters when building infrastructure that AI agents depend on for autonomous decision-making.
Tools, resources, and prompts form the three capability pillars: MCP servers expose executable functions as tools, structured data as resources, and reusable interaction patterns as prompt templates. Understanding when to use each — and how they compose together — is the difference between a useful MCP server and a fragile one.
Production MCP servers require auth, rate limiting, and observability: The 2026 MCP roadmap includes OAuth 2.1 with PKCE for browser-based agents and enterprise identity provider integration. Shipping an MCP server without authentication and request throttling is shipping an unauthenticated API endpoint that autonomous agents will call at machine speed.

The Model Context Protocol has moved from an Anthropic research project to the default integration standard for AI agent tooling in under eighteen months. As of early 2026, MCP has surpassed 97 million NPM downloads, ships natively in Claude Desktop, ChatGPT, Gemini AI Studio, and every major code editor with AI capabilities. The protocol is no longer experimental — it is infrastructure.

For TypeScript developers, this represents both an opportunity and an obligation. An opportunity because MCP servers are TypeScript- native, with the official SDK providing full type safety across tool definitions, resource schemas, and prompt templates. An obligation because the AI agents your team builds — or the AI agents your clients use — need standardized access to your systems. Building that access layer as an MCP server rather than a bespoke integration means building it once and supporting every compliant AI client automatically.

This guide covers the complete development workflow: from initializing an MCP server project to defining tools, exposing resources, creating prompt templates, implementing authentication, and deploying to production. For context on where MCP fits within the broader AI agent protocol ecosystem including A2A, ACP, and UCP, that comparison covers how MCP relates to inter-agent communication protocols.

What Is the Model Context Protocol

The Model Context Protocol is an open standard that defines how AI applications connect to external data sources and tools. Think of it as USB-C for AI agents: a universal connector that replaces the fragmented landscape of custom integrations with a single, standardized interface. Before MCP, connecting an AI agent to a database required writing database-specific code. Connecting that same agent to a CRM required writing CRM-specific code. Each integration was a one-off engineering effort.

MCP eliminates that per-integration overhead. You build an MCP server that exposes your system's capabilities — what it can do, what data it holds, what workflows it supports — through a standardized protocol. Any MCP-compliant AI client can then discover and use those capabilities without custom integration code. The server describes itself; the client consumes that description dynamically.

Tools

Executable functions the LLM can invoke. Tools accept structured input, perform operations (API calls, database queries, file manipulation), and return structured results. They are the “actions” an agent can take.

Resources

Structured data that clients can read. Resources work like virtual file systems — each has a URI, a MIME type, and content. They expose data without executing operations, keeping read and write concerns separated.

Prompts

Pre-defined interaction templates with structured arguments. Prompts guide AI interactions toward specific workflows, ensuring consistent and reliable agent behavior across different use cases.

The protocol communicates over JSON-RPC 2.0, which means every message between client and server is a structured JSON object with a method name, parameters, and either a result or an error. This is the same wire format used by the Language Server Protocol (LSP) that powers IDE features like autocomplete and diagnostics. If you have built or consumed an LSP server, the MCP architecture will feel familiar.

MCP Architecture and Transport Layers

MCP uses a client-server architecture where the host application (Claude Desktop, an IDE, a custom agent) runs an MCP client that connects to one or more MCP servers. Each server maintains a one-to-one connection with the client through a transport layer. The transport handles the raw communication; the protocol layer on top handles capability negotiation, request routing, and lifecycle management.

STDIO Transport

Communication through standard input and output streams. The client spawns the server as a child process and sends JSON-RPC messages via stdin, receiving responses on stdout. Ideal for local development, CLI tools, and desktop applications.

SSE and Streamable HTTP Transports

HTTP-based transports that enable remote MCP servers. SSE (Server-Sent Events) provides server-to-client streaming over HTTP while the client sends requests via POST. Streamable HTTP is the newer transport option that supports full bidirectional communication with session management, making it suitable for production deployments where multiple clients connect simultaneously and sessions persist across requests.

The architecture also includes a capability negotiation phase during connection initialization. When a client connects, the server declares what it supports — which tools are available, which resources can be read, which prompt templates are offered. The client uses this declaration to understand what the server can do before making any requests. This is fundamentally different from a REST API where the client must already know the endpoint structure.

For production deployments, the 2026 MCP roadmap includes OAuth 2.1 with PKCE for browser-based agent authentication and integration with enterprise identity providers like Okta and Azure AD. This moves MCP from developer tooling into enterprise infrastructure, where authentication and access control are table stakes.

Setting Up a TypeScript MCP Server

The official TypeScript SDK is published as @modelcontextprotocol/sdk on NPM. A minimal MCP server requires four things: a project with TypeScript configured for ES modules, the SDK installed, an entry file that creates a server instance, and a build step that produces executable JavaScript.

Project Initialization Steps

  1. 1.Create a new directory and run npm init -y to initialize the project. Set "type": "module" in package.json to enable ES module syntax.
  2. 2.Install dependencies: npm install @modelcontextprotocol/sdk zod and npm install -D typescript @types/node. Zod is used for schema validation on tool inputs.
  3. 3.Configure tsconfig.json with target: "ES2022", module: "Node16", and moduleResolution: "Node16". Output to a dist/ directory.
  4. 4.Create src/index.ts as the server entry point. Import McpServer from the SDK and StdioServerTransport for local development.
  5. 5.Add a build script to package.json: "build": "tsc". Add a shebang line #!/usr/bin/env node at the top of the entry file for STDIO execution.

The server entry file follows a consistent pattern: create a server instance with a name and version, register capabilities (tools, resources, prompts), then connect the server to a transport. The McpServer class handles all protocol-level concerns — capability negotiation, request routing, error formatting — so your code focuses entirely on implementing the actual functionality.

The entry file creates a new McpServer with a configuration object specifying the server name, version string, and capability declarations. You then call server.tool(), server.resource(), and server.prompt() to register each capability. Finally, you call server.connect(transport) to start listening.

Defining Tools for LLM Consumption

Tools are the most commonly used MCP capability. A tool is a function that an AI agent can call to perform an action: querying a database, calling an external API, reading a file, sending an email, running a calculation. Each tool has a name, a description that helps the LLM understand when to use it, an input schema defined with Zod, and an async handler function.

The description is critically important. LLMs decide which tool to call based on the description, not the tool name. A vague description like “gets data” forces the LLM to guess. A precise description like “retrieves the current weather forecast for a US state, including temperature, wind speed, and precipitation probability for the next 24 hours” gives the LLM enough context to make correct tool selection decisions consistently.

Good Tool Design
  • Descriptive name that indicates the action: get_weather_forecast
  • Detailed description with input/output expectations
  • Strict Zod schema with field descriptions
  • Structured error responses with isError: true
  • Single-responsibility: one tool, one action
Common Mistakes
  • ×Vague descriptions that force LLM guessing
  • ×No input validation — trusting LLM output blindly
  • ×Throwing unhandled exceptions instead of returning errors
  • ×God tools that combine multiple unrelated operations
  • ×Missing Zod field descriptions that aid LLM parameter selection

The tool handler function receives the validated input object and must return a result object with a content array containing one or more content blocks. Each block has a type (text, image, or resource) and corresponding data. For most tools, a single text content block with a JSON-stringified result is sufficient. The LLM parses the text content and extracts the information it needs.

Exposing Resources and Data

Resources provide read-only access to data through a URI-based addressing scheme. Each resource has a unique URI (like config://app/settings or db://users/active), a MIME type, and content that can be text or binary. Resources are fundamentally different from tools: they expose data that the LLM can read and reason about, but they do not execute operations or modify state.

The distinction matters for security and predictability. A client can read all available resources without side effects. Tools, by contrast, perform actions that may change state. Keeping these concerns separate means you can grant resource access more liberally than tool access — an AI agent can read configuration data and documentation without being authorized to modify anything.

Common Resource Patterns

Static Resources

  • • Configuration files and environment settings
  • • API documentation and schema definitions
  • • Application logs and audit trails
  • • Template libraries and style guides

Dynamic Resources (Templates)

  • • Database query results: db://users/{userId}
  • • API response caches: api://weather/{city}
  • • Generated reports: report://monthly/{month}
  • • User profiles: profile://{email}

Resource templates use URI patterns with placeholders that the client fills in at request time. The server registers a template like db://users/{userId} and the handler receives the resolved URI with the actual user ID. This enables dynamic data access without requiring a separate tool for each data retrieval pattern. The MCP SDK supports subscription-based resources as well, where clients can subscribe to changes and receive notifications when resource content updates.

Prompt Templates and Workflows

Prompts are the third MCP capability and the least understood. They are pre-defined interaction templates that guide how an AI agent uses your server's tools and resources. A prompt template has a name, a description, optional arguments, and returns a structured message sequence that the client inserts into the conversation.

The practical use case is workflow standardization. Instead of relying on the LLM to figure out the correct sequence of tool calls for a complex task, you encode that sequence in a prompt template. A “generate-report” prompt might specify: first read the project configuration resource, then call the data-query tool with specific parameters, then call the format-output tool with the results. The LLM executes this predefined workflow rather than improvising.

Task Prompts

Single-purpose templates for common operations. Examples: “summarize-issue” reads a ticket resource and returns a structured summary. “check-deployment” calls monitoring tools and formats the status.

Workflow Prompts

Multi-step templates that orchestrate several tools and resources in sequence. Examples: “onboard-customer” creates a record, sends a welcome email, and schedules a follow-up task using three separate tools.

Agent Prompts

Templates that configure agent behavior for a specific domain. They embed system instructions, define available actions, and set guardrails. Useful for creating specialized agents from a general-purpose MCP server.

Prompt templates accept arguments defined with the same Zod-based schema system used by tools. The handler function receives validated arguments and returns a messages array containing role/content pairs. The client presents these messages to the LLM, which then follows the instructions to execute the workflow using the server's tools and resources.

Authentication and Rate Limiting

An MCP server without authentication is an unauthenticated API endpoint that autonomous agents will call at machine speed. This is the most consequential security consideration in MCP server development. STDIO-based servers running locally inherit the user's system permissions and are implicitly authenticated. Remote servers running over SSE or Streamable HTTP need explicit authentication.

Authentication Approaches
  • OAuth 2.1 with PKCE — the MCP standard for browser-based and remote agents. Ships in the 2026 specification update.
  • API key headers — simpler alternative for server-to-server connections. Validate keys in transport middleware before requests reach handlers.
  • mTLS certificates — mutual TLS for high-security environments where both client and server authenticate with certificates.
Rate Limiting Strategy
  • Per-client limits — throttle requests per authenticated client using token bucket or sliding window algorithms.
  • Per-tool limits — expensive operations (database writes, external API calls) get stricter limits than read-only operations.
  • Cost-based limits — assign cost weights to tools and limit total cost per time window rather than raw request count.

Rate limiting for MCP servers requires different thinking than rate limiting for human-facing APIs. AI agents execute tool calls in rapid sequences — an agent might call five tools in under a second during a multi-step workflow. Setting rate limits too low breaks legitimate agent workflows. Setting them too high exposes your backend to abuse. The practical approach is to start with generous per-client limits and add per-tool limits for operations that touch expensive resources.

For TypeScript implementations, middleware-based rate limiting works at the transport level. Intercept incoming JSON-RPC requests before they reach the MCP server's handler layer. Redis-backed rate limiters (like Upstash) work well for distributed deployments where multiple server instances share rate limit state. For single-instance deployments, in-memory rate limiting with a sliding window counter is sufficient.

Connecting to LLM Backends

A key advantage of the MCP approach is backend agnosticism. The MCP server you build works with any compliant client, regardless of which LLM powers it. Claude, GPT, Gemini, Llama, and open- source models running locally can all consume the same MCP server. The server does not need to know or care which model is calling its tools.

Major MCP Client Implementations

AI Assistants

  • • Claude Desktop and Claude API
  • • ChatGPT and OpenAI Assistants API
  • • Google Gemini (AI Studio, Vertex AI)
  • • Amazon Q and Bedrock agents

Developer Tools

  • • VS Code with GitHub Copilot
  • • Cursor and Windsurf editors
  • • JetBrains IDEs (IntelliJ, WebStorm)
  • • Zed editor

When building an MCP server, you design your tools, resources, and prompts for the protocol layer, not for any specific model. The tool descriptions, input schemas, and output formats should be clear enough that any capable LLM can use them correctly. This means writing descriptions in natural language that is unambiguous, providing field-level descriptions on every Zod schema property, and returning results in structured formats that are easy for models to parse.

For teams that want to build their own MCP client — for example, embedding MCP tool consumption into a custom agent built with the multi-protocol agent patterns — the TypeScript SDK includes a Client class that handles capability discovery, tool invocation, resource reading, and prompt retrieval. Building both the server and client in TypeScript gives you end-to-end type safety through shared schema definitions.

Testing, Debugging, and Deployment

The MCP ecosystem includes a dedicated testing tool: the MCP Inspector. It is a developer tool that connects to your server as a client, displays all registered capabilities, and lets you invoke tools, read resources, and trigger prompts manually. This is invaluable during development because it removes the LLM from the testing loop — you can verify that your server works correctly before testing with an actual AI agent.

Unit Testing

Test tool handler functions in isolation with mocked dependencies. Verify that valid inputs produce expected outputs and invalid inputs return structured errors. Use Vitest or Jest with TypeScript for full type coverage in test assertions.

Integration Testing

Spin up the server with a test client and exercise the full request lifecycle: capability negotiation, tool invocation, resource reading, prompt retrieval. The SDK's InMemoryTransport enables fast integration tests without network overhead.

Deployment

STDIO servers deploy as NPM packages or standalone binaries (via pkg or esbuild bundling). HTTP- based servers deploy to any Node.js hosting: Vercel Functions, AWS Lambda, Railway, Fly.io, or containerized on Kubernetes.

For debugging, MCP servers should log all incoming requests and outgoing responses at the transport level. In STDIO mode, logging goes to stderr. In HTTP mode, logging goes to your standard observability stack. Include the request method, tool name, input parameters (sanitized to exclude sensitive data), execution duration, and response status in every log entry. When an agent makes an unexpected tool call or receives an unexpected result, these logs are the primary debugging tool.

Production deployment should include health checks, graceful shutdown handling, and connection lifecycle management. The SDK provides lifecycle hooks for server startup and shutdown. Use them to initialize database connections, warm caches, and clean up resources. For Streamable HTTP deployments, implement session persistence so that long-running agent workflows survive server restarts without losing conversation state.

Conclusion

The Model Context Protocol has become the standard interface between AI agents and external systems. Building MCP servers in TypeScript is not a speculative investment in a protocol that might gain adoption — it is the current infrastructure layer for agent-enabled applications across every major LLM provider. The 97 million download milestone is a trailing indicator of adoption that has already happened.

The development workflow is straightforward: initialize a TypeScript project, install the SDK, define your tools with Zod schemas and descriptive metadata, expose your data as resources, encode your workflows as prompt templates, and add authentication and rate limiting before deploying. Each component builds on standard TypeScript patterns that you already know. The protocol layer is what is new; the implementation logic is the same business code you have always written.

For teams evaluating where to start, the highest-value pattern is wrapping existing internal APIs as MCP tools. This gives your AI agents immediate access to your systems through a standardized protocol while preserving the existing API as the source of truth. From there, add resources for data access and prompts for workflow standardization. The developer guide to building and selling custom AI agents covers the business side of productizing these capabilities.

Ready to Build AI Agent Infrastructure?

Our development team builds custom MCP servers and AI agent integrations that connect your systems to every major LLM platform through a single standardized protocol.

Free consultation
TypeScript expertise
Production-ready delivery

Related Articles

Continue exploring with these related guides