MCP Server Use Cases

November 20, 2024AI • Technical • Development

Server architecture and protocols

Loading...

What is the Model Context Protocol (MCP)?

The Model Context Protocol (MCP) standardizes how AI applications discover and call tools over a secure, streaming channel. An MCP server exposes capabilities—APIs, databases, filesystems, or internal services—as typed tools that any compliant client (your app, an agent, or an IDE plugin) can list, describe, and invoke. This decouples tool integration from model prompts and lets teams evolve capabilities without hard‑wiring them into prompts.

Why engineers adopt MCP servers

MCP server architecture (practical)

A minimal production layout has four pieces: the client, the transport, the tool registry, and the handlers. The example below sketches a server with two tools: searchTickets and createTicket.

// pseudo-typescript: mcp server skeleton
import { createServer, tool } from '@acme/mcp';

const server = createServer({
  transport: { kind: 'websocket', url: process.env.MCP_WS_URL },
  auth: { strategy: 'bearer', verify: async (t) => t.startsWith('mcp_') }
});

server.register(tool({
  name: 'searchTickets',
  input: { query: 'string' },
  output: { results: 'array' },
  handler: async ({ query }, ctx) => ctx.db.search(query)
}));

server.register(tool({
  name: 'createTicket',
  input: { title: 'string', body: 'string', priority: 'enum(low|med|high)' },
  output: { id: 'string', url: 'string' },
  handler: async (i, ctx) => ctx.tracker.create(i)
}));

server.start();

Common use cases

Case study: reducing ticket time-to-first-touch by 42%

A B2B SaaS team served 2k+ weekly support tickets across three regions. Agents used an LLM assistant inside the help desk, but answers were inconsistent and actions (creating follow‑ups, linking issues) required tab‑hopping. The team deployed an MCP server with three tools: searchTickets, summarizeIssue, and createTicket. The server handled auth to Zendesk, masked emails/phone numbers, and emitted structured telemetry.

Deployment tips

  1. Start read‑only: ship list/get/search tools first, then add writes with approvals.
  2. Schema everything: define inputs/outputs narrowly; reject unknown fields to prevent prompt injection.
  3. Budget tokens: return compact objects; let the client render rich UI if needed.
  4. Observe: log inputs/outputs, latencies, and error classes; sample transcripts for prompt tuning.

Security and governance

Treat the MCP server as a policy gateway. Enforce per‑tool scopes, redact sensitive fields, and add guardrails (regex allowlists, numeric bounds). For regulated data, run the server inside your VPC and proxy any third‑party traffic.

Checklist before production

SEO FAQs

Is MCP just for agents? No—web apps and IDEs benefit equally from a uniform tool layer.

How is it different from plain REST? MCP standardizes discovery, typing, and streaming I/O for tools the model can call directly.

When to avoid MCP? For a single, static integration, direct SDK calls may be simpler. Choose MCP when you expect multiple tools/clients or evolving capabilities.

Further reading

Real‑world use case: Add an MCP tool to an agent

Expose a calendar or docs API via MCP to your agent.

  1. Pick one tool
  2. Implement schema + server
  3. Connect client and test

Expected outcome: Reliable tool calling with typed I/O.

Implementation guide

  1. Define the tool schema and guardrails.
  2. Implement the MCP server; test locally.
  3. Register the tool with the client; run end‑to‑end test.

Architecture


LLM Agent (tool calling)
   |  tool: calendar.createEvent(args)
   v
Tool Bridge (HTTP JSON‑RPC)
   |  POST /rpc { method, params }
   v
MCP Server (Calendar)
   |  stores events; validates schema
   v
External Calendar Provider (optional)

Input (example)


{
  "method": "calendar.createEvent",
  "params": {
    "title": "Product sync",
    "start": "2025-11-10T15:00:00Z",
    "end": "2025-11-10T15:30:00Z",
    "attendees": ["dev@acme.co", "pm@acme.co"],
    "notes": "Agenda: triage + roadmap"
  },
  "id": 1,
  "jsonrpc": "2.0"
}

Code (POC)

calendar-mcp-server.ts (minimal JSON‑RPC server with validation)

import http from 'http';

type CreateEventParams = {
  title: string;
  start: string; // ISO8601
  end: string;   // ISO8601
  attendees?: string[];
  notes?: string;
};

type JsonRpcRequest = { jsonrpc: '2.0'; method: string; params?: unknown; id?: number|string };
type JsonRpcResponse = { jsonrpc: '2.0'; result?: unknown; error?: { code: number; message: string }; id?: number|string };

const events: Array<CreateEventParams & { id: string }> = [];

function isCreateEventParams(x: any): x is CreateEventParams {
  return x && typeof x.title === 'string' && typeof x.start === 'string' && typeof x.end === 'string';
}

function handleRpc(req: JsonRpcRequest): JsonRpcResponse {
  if (req.method === 'calendar.createEvent') {
    if (!isCreateEventParams(req.params)) {
      return { jsonrpc: '2.0', error: { code: -32602, message: 'Invalid params' }, id: req.id };
    }
    const ev = { id: 'evt_' + Math.random().toString(36).slice(2), ...req.params };
    events.push(ev);
    return { jsonrpc: '2.0', result: { id: ev.id, status: 'created' }, id: req.id };
  }
  if (req.method === 'calendar.listEvents') {
    return { jsonrpc: '2.0', result: events, id: req.id };
  }
  return { jsonrpc: '2.0', error: { code: -32601, message: 'Method not found' }, id: req.id };
}

const server = http.createServer((req, res) => {
  if (req.method !== 'POST' || req.url !== '/rpc') { res.statusCode = 404; return res.end('Not found'); }
  let body = '';
  req.on('data', (c) => (body += c));
  req.on('end', () => {
    try {
      const rpc = JSON.parse(body) as JsonRpcRequest;
      const out = handleRpc(rpc);
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify(out));
    } catch (e: any) {
      res.statusCode = 400;
      res.end(JSON.stringify({ jsonrpc: '2.0', error: { code: -32700, message: 'Parse error' } }));
    }
  });
});

server.listen(8787, () => console.log('MCP calendar server on http://localhost:8787/rpc'));

agent-bridge.ts (tool definition + bridge to JSON‑RPC)

type ToolCall = { name: 'calendar.createEvent' | 'calendar.listEvents'; arguments: any };

async function callRpc(method: string, params?: any) {
  const res = await fetch('http://localhost:8787/rpc', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ jsonrpc: '2.0', id: Date.now(), method, params })
  });
  const json = await res.json();
  if (json.error) throw new Error(json.error.message);
  return json.result;
}

export const tools = [
  {
    name: 'calendar.createEvent',
    description: 'Create a calendar event (ISO8601 timestamps).',
    parameters: {
      type: 'object',
      properties: {
        title: { type: 'string' },
        start: { type: 'string', description: 'ISO8601 start' },
        end: { type: 'string', description: 'ISO8601 end' },
        attendees: { type: 'array', items: { type: 'string' } },
        notes: { type: 'string' }
      },
      required: ['title', 'start', 'end']
    }
  },
  {
    name: 'calendar.listEvents',
    description: 'List in-memory events',
    parameters: { type: 'object', properties: {} }
  }
];

export async function handleToolCall(call: ToolCall) {
  switch (call.name) {
    case 'calendar.createEvent':
      return await callRpc(call.name, call.arguments);
    case 'calendar.listEvents':
      return await callRpc(call.name);
    default:
      throw new Error('Unknown tool');
  }
}

// Example usage (pseudo‑agent loop)
async function demo() {
  const result = await handleToolCall({
    name: 'calendar.createEvent',
    arguments: {
      title: 'Product sync',
      start: '2025-11-10T15:00:00Z',
      end: '2025-11-10T15:30:00Z',
      attendees: ['dev@acme.co', 'pm@acme.co']
    }
  });
  console.log(result);
}
demo();

Output (example)


{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "id": "evt_01HZX...",
    "status": "created"
  }
}

SEO notes

Loading...