Building an MCP server: structure and a Pakistani example
MCP سرور بنانا: ساخت اور ایک پاکستانی مثال
40 min read
Three ways to see it
MCP servers can be written in many languages, but the official SDKs from Anthropic in late 2024 onwards prioritise TypeScript and Python. Both speak the same protocol. Pick the language your team already uses. A TypeScript server starts with one package install: npm install @modelcontextprotocol/sdk. A Python server starts with: pip install mcp. From there the structure is mechanical. You import the server class, you declare tools and their input schemas, you write a handler function for each tool, you wire stdin and stdout as the transport, and you start the loop. The transport is usually standard input and output streams, because the model client launches the server as a child process and talks to it that way.
The Pakistani example to ground this. We will design an MCP server called 'fbr-ntn' that exposes a single tool, verify_ntn. The server keeps a small SQLite cache of recent lookups for rate-limit reasons. When Claude calls the tool, the handler first checks the cache, then if it is a cache miss, makes a real call to FBR's Online Verification endpoint, stores the response, and returns it to the model. The whole server is around eighty lines of TypeScript. The interesting work is not the code; it is the design decisions hidden in the eighty lines.
Decision one: where does the FBR API key live? Not in code. Not in the model context. The server reads it from an environment variable on startup. The model never sees it; the model only knows the tool exists. Decision two: what does the tool description say? Not 'verifies NTN' but 'Verifies whether an FBR NTN is currently an active taxpayer. Returns active or inactive plus the year of last filing. Use only when the user explicitly asks for verification of a Pakistani business identity. Do not use for personal CNIC lookups.' The negative example matters as much as the positive. Decision three: error handling. If FBR returns 429 the handler implements exponential backoff before bubbling up; if FBR returns 5xx the handler returns a clear MCP error so the model can decide whether to retry or apologise.
Quick check
Quick check: what makes modern AI different from a rule-based program?
The why-tree
Why-tree level one: why a server at all rather than calling FBR directly from the model? Because the model cannot keep secrets. Anything you put in its context can leak in its output. An MCP server keeps the API key in a place the model never sees. The model only sees the door, never the key.
Try this with Claude
AI-edge prompt to try with Claude or ChatGPT: 'Generate a minimal TypeScript MCP server for the verify_ntn tool described in this lesson. Include in-line comments in Urdu explaining each decision: where the key lives, why exponential backoff, what the test fixture looks like. Use the official @modelcontextprotocol/sdk. Do not invent fields that FBR does not return.' Run the output and fix every hallucinated import.
Sources
Sources and further reading. MCP specification (modelcontextprotocol.io). Official TypeScript SDK (github.com/modelcontextprotocol/typescript-sdk). Official Python SDK (github.com/modelcontextprotocol/python-sdk). Example servers (github.com/modelcontextprotocol/servers). Anthropic docs, 'Build your first MCP server' (docs.anthropic.com). FBR Online Verification Services (fbr.gov.pk). PDPA-2023 text (na.gov.pk).