AI Model Context Protocol (MCP)

Anthropic proposed the Model Context Protocol (MCP) in 2024 as a standard for connecting AI models to external data, tools, and services, and it has become the interface most agent tooling now targets. MCP defines how a model reaches tools and data through a consistent, modular structure, and this post covers what that means in practice and how I implement it with TypeScript and current AI tooling.

Illustration of MCP's role in AI model integration

What MCP standardizes

MCP is a specification for how AI models interact with external APIs, databases, and tools. Because it defines context, tools, and workflows explicitly, it gives agentic systems a structure beyond prompting, and it lets developers:

  • Declare the tools and capabilities a model can use.
  • Share memory and execution logs across calls.
  • Keep model logic separate from business logic.

Why a protocol is needed now

Applications moved from one-shot prompts to multi-step reasoning systems, and LLMs gained function calling, streaming, and memory integration along the way. Tooling like LangChain.js, Mastra, and the Vercel AI SDK now supports MCP-style architecture in TypeScript, and MCP gives that complexity a standard interface that improves reuse, observability, and control.

Implementing MCP in TypeScript

TypeScript's static types, module system, and growing set of AI libraries make it a good fit for systems that follow the MCP specification. The examples below cover three properties I want in that code: modular tools, composition at runtime, and persistent state.

Modular tools as isolated units of capability

// tools/search.ts
export const search = async (query: string) => {
  const res = await fetch(`/api/search?q=${query}`);
  return res.json();
};
 
// memory/vector.ts
export const storeEmbedding = async (embedding: number[]) => {
  await db.insert({ embedding });
};

Composing modules into an agent

import { Agent } from 'mastra';
import { search } from './tools/search';
import { storeEmbedding } from './memory/vector';
 
const agent = new Agent({ tools: [search], memory: { store: storeEmbedding } });
await agent.run("Find latest AI news and store key terms");

Persisting state across sessions

const memory = new VectorMemory({ db: pgvector });
 
await memory.save({ userId: '123', embedding: await getEmbedding("AI regulation") });
const context = await memory.query({ userId: '123' });

Persistent memory lets an agent carry context from one session to the next, which is what long-running plans and consistent behavior depend on.

Where this structure pays off

The same pattern supports several kinds of product:

  • Agents that remember user preferences.
  • Workflow automation with persistent state.
  • Multi-agent systems coordinating through shared memory.
  • AI-powered dashboards whose logic can be updated module by module.

Open design questions

ChallengeConsiderations
InteropStandardizing interfaces between modules
State storageChoosing the right DB for persistence
ComposabilityEnsuring modules can be reused cleanly
Type safetyUsing TypeScript to enforce contracts between components

I use MCP to keep model input and output behind a contract, so modules stay replaceable, types stay honest, and the rest of the app never needs to know which model is on the other side.

Related writing