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.

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
| Challenge | Considerations |
|---|---|
| Interop | Standardizing interfaces between modules |
| State storage | Choosing the right DB for persistence |
| Composability | Ensuring modules can be reused cleanly |
| Type safety | Using 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.