Model Context Protocol (MCP) Explained for Web Developers: Giving Tools to AI Agents
MCP is one of the fastest-growing topics in developer search queries right now; establishing an early article here builds high search authority.
Until recently, connecting an LLM to your database or internal API meant writing proprietary, bespoke function-calling wrappers. Every AI client (OpenAI, Anthropic, LangChain) had a different schema format, and reusing tools across platforms required endless adapter boilerplate.
Enter the Model Context Protocol (MCP), open-sourced by Anthropic. MCP is rapidly becoming the USB-C of AI development: an open standard that allows any AI agent to discover and invoke tools, inspect databases, and query business systems securely.
In this guide, we'll explain how MCP works and walk through building your first MCP server in TypeScript.
1. The MCP Client-Server Model
MCP standardizes how an AI Host (Claude Desktop, Cursor, Antigravity) talks to external tools through lightweight JSON-RPC over Standard I/O (stdio) or Server-Sent Events (sse):
[AI Host / Agent]
│ (JSON-RPC protocol)
â–¼
[MCP Server]
├── Prompts: Pre-packaged prompt workflows
├── Resources: File contents, logs, documentation
└── Tools: Executable functions (e.g. `query_database`, `create_invoice`)
2. Building an MCP Server in 40 Lines of TypeScript
Let's build an MCP server that exposes a database query tool to an AI agent using the official @modelcontextprotocol/sdk:
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 server = new Server(
{ name: 'enterprise-crm-mcp', version: '1.0.0' },
{ capabilities: { tools: {} } }
)
// 1. Declare available tools to the AI Agent
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'query_customer_invoices',
description: 'Lookup outstanding customer invoices and balance by customer ID',
inputSchema: {
type: 'object',
properties: {
customerId: { type: 'string', description: 'Customer identifier (e.g. CUST-1042)' },
minAmount: { type: 'number', description: 'Optional minimum invoice amount filter' }
},
required: ['customerId']
}
}
]
}
})
// 2. Handle tool execution requested by the LLM
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === 'query_customer_invoices') {
const { customerId, minAmount = 0 } = request.params.arguments as any
const invoices = await db.invoices.findMany({
where: { customerId, amount: { gte: minAmount } }
})
return {
content: [
{
type: 'text',
text: JSON.stringify(invoices, null, 2)
}
]
}
}
throw new Error(`Tool ${request.params.name} not found`)
})
// 3. Connect via Standard I/O
const transport = new StdioServerTransport()
await server.connect(transport)
3. Human-in-the-Loop (HITL) Safeguards
When designing MCP tools that execute write or financial operations (e.g. send_payment_reminder, refund_transaction — as in my OpérIA copilot project), never execute the write immediately.
Instead, have the MCP tool return a Staged Action Object:
{
"action": "DISPUTE_CREDIT",
"status": "STAGED",
"recipient": "client@enterprise.com",
"amount": 450.00,
"requiresApproval": true
}
The operator reviews and confirms the staged payload in the UI before the system commits the transaction to production.
Share this article
Adam Abdel-Djamal
Full Stack DeveloperAdam Abdel-Djamal is a Full-Stack & AI Engineer crafting high-performance web applications with Nuxt, Vue, Laravel, and autonomous AI agents.
Related Articles
6 Common API Mistakes (And How to Fix Them)
From wrong HTTP methods to leaking sensitive data — the errors most developers make when building their first API, and the concrete fixes.
API Rate Limiting in Practice: Token Bucket vs. Sliding Window with Redis
Comparing rate-limiting algorithms to protect your backend against scrapers, credential stuffing, and bot spam with minimal latency overhead.