Back to Blog
AI & Automation8 min read

MCP Server Development: Wiring an AI Agent into Systems You Already Run

By Waseem Ahmad — Full Stack Developer & AI Engineer ·

TL;DR

  • MCP is a JSON-RPC 2.0 protocol that lets any compatible AI client discover and call tools your server exposes — one server, many clients, no per-model rewrites.
  • Pick stdio when the client launches your process locally; pick Streamable HTTP when the server is remote or needs to serve more than one caller.
  • Tool schema descriptions live in the context window on every single call — a bloated tool list is a direct token tax before any reasoning happens.
  • Tool poisoning is a real supply-chain risk: malicious instructions can be embedded in tool descriptions, and models follow them without user awareness.
  • The 2026-07-28 spec release made remote MCP servers stateless ordinary HTTP — simpler to deploy, but it changes how you think about session state.

MCP solves a genuine connectivity problem: how to give large language models reliable, standardized access to external tools and data sources without writing one-off integrations for every combination of model and service. If you have already built REST endpoints for a CRM, a database, or an internal reporting system, an MCP server is the translation layer that makes those endpoints callable by an AI agent — without touching the underlying system or writing model-specific adapter code.

This is not a getting-started tutorial. It is the guide I wish existed when I was deciding which transport to use, how to structure tools, and where the thing would break under production load. I will cover server versus client roles, the two live transports, tool design trade-offs, and the security problems that do not appear in the official docs.

What an MCP Server Actually Does

An MCP server speaks JSON-RPC 2.0 over one of two transports — stdio for local processes and Streamable HTTP for remote deployments — and it advertises three server-side capabilities: tools the model can call, resources the host application can read, and prompts the user can invoke deliberately. The protocol does not care about your business logic. It cares about discovery, invocation, and a typed response.

The client side is whoever calls your server: Claude Desktop, Cursor, Claude Code, an n8n workflow, or your own agent loop. Because the major AI clients now speak the same protocol, one well-built server works across multiple assistants, IDEs, and internal agent frameworks without per-vendor rewrites. That portability is the actual value proposition.

Tools, resources, and prompts serve different purposes. Tools are function calls the agent decides to invoke. Resources are readable data the host can pull into context. Prompts are user-initiated templates. In practice, most servers you will build are tool-heavy; resources and prompts matter more for data-retrieval and UI-facing scenarios.

Which Transport Should You Use?

The mental model is: stdio is for a local process relationship, Streamable HTTP is for a remote service relationship, and legacy SSE is for migration. The table below maps the practical consequences of each choice.

Dimension stdio Streamable HTTP HTTP+SSE (deprecated)
Process model Client spawns server as child process Server runs independently, client connects Client connects to running server
Multi-client No — one client, one process Yes — stateless, any number of callers Yes, but sticky sessions required
Auth required No — OS process boundary is the security boundary Yes — TLS, tokens, OAuth Yes
Deployment complexity Low — ship a binary or script Medium — normal HTTP infrastructure Medium, plus sticky-session routing
Build new servers on this? Yes Yes No — deprecated March 2025
Scaling Not applicable — local only Horizontal behind a standard load balancer Hard — load balancer had to parse JSON-RPC to route

stdio is the simplest transport and, today, the most widely deployed. The client spawns the MCP server as a child process and communicates through the operating system's standard input and output streams. One protocol rule catches people: stdout is protocol traffic, not a logging stream. A stray console.log to stdout corrupts the message framing. Log to stderr or a file.

For remote servers, a remote MCP server is now no different from any other HTTP workload, making it easy to host and operate one on any infrastructure that developers and organizations already use for their APIs and services. The 2026-07-28 specification is what made this clean: it makes the transport stateless, removing protocol-level sessions and the Mcp-Session-Id header, so that the same request can be answered by any server instance behind ordinary HTTP infrastructure.

That statefulness removal has a real cost if you built against the earlier spec. Any per-session in-memory state you held on the server now needs to live in an external store. The old design was the reason load balancers had to parse JSON-RPC bodies to route, sticky sessions blocked autoscaling, and a single server restart blew up every in-flight session. Stateless is better operationally; it just moves the state problem to you.

Is Tool Design the Real Problem?

Yes, and it is where most production servers go wrong. The protocol makes it trivially easy to expose dozens of tools. That ease creates a cost that compounds silently.

Every tool ships with a description, a parameter schema, and return-type metadata, all of which sit in the prompt on every single request. Every MCP tool call serializes the full tool schema into the context window. Expose 90 tools, and you're spending significant context on schema overhead before a single token of agent reasoning happens. The official GitHub MCP server is the canonical illustration: it charges approximately 42,000 tokens before any work begins.

The fix is discipline at design time, not a protocol feature. GitHub Copilot cut its tool count from 40 to 13 and saw measurable benchmark improvements. Block rebuilt its Linear MCP server three times, going from 30+ tools to just 2. If you are reaching for tool number fifteen on a single server, stop and ask whether you have a tool problem or a server decomposition problem.

A few rules that hold up in practice:

  • Write tool descriptions for the model, not for humans. The description is a prompt fragment — treat it as one.
  • Return only what the next reasoning step needs. A tool that returns a 200-field object when the agent needs one field burns tokens on every call.
  • Configure toolset filtering aggressively. Only expose the groups your agent actually needs.
  • Monitor p99 latency per individual tool, not per server. A server averaging 200ms can hide a single tool consistently running at 800ms, silently consuming your chain's entire budget.

The context-window arithmetic is worth understanding in detail — I went deeper on it in Designing MCP Tools That Don't Blow Up the Context Window. And if token cost is a concern at scale, the broader picture is in LLM Cost Optimization: Caching, Routing, and the Token Waste Hiding in Your Prompts.

The Security Problems the Docs Understate

Two distinct threat categories apply to MCP servers, and they work through different channels.

The first is prompt injection through tool outputs: your tool returns data that contains malicious instructions, the model follows them. The mitigation is treating tool outputs as untrusted input, the same discipline you apply to user input in any web application.

The second is tool poisoning, and it is harder to defend against. Prompt injection is an input-validation problem: the user typed something the application was not ready for. Tool poisoning is a supply-chain problem: the server-side metadata an agent depends on for capability discovery has been authored by someone the agent never agreed to trust. The MCP tool description field is an unsanitized attack surface: a malicious or compromised MCP server can embed arbitrary instructions in what appears to be help text, and AI agents will follow those instructions without user awareness.

This is not theoretical. The MCPTox benchmark, which evaluated 45 live MCP servers across 20 large language models, measured an average tool-poisoning attack success rate of 36.5%, with the highest rate reaching 72.8% against a single model. A poisoned tool description ships inside a package, a configuration file, or a remote MCP server, and it works on every single invocation, silently, across every session, for every user, until somebody notices.

The practical controls: treat tool descriptions and outputs as untrusted input, and inspect the full schema before you approve a server. Put the tool list through a human approval step, and show the full tool call rather than a friendly summary. Keep sensitive servers isolated from general-purpose ones so a poisoned tool cannot reach across without further safeguards. On authorization, MCP servers are now treated as OAuth 2.0 resource servers, and the guidance has settled on OAuth 2.1, PKCE, and tokens bound to a specific audience. Also worth noting: a valid token proves identity. It does not prove the agent may call this tool, the user authorized this action, or the requested amount is within policy. Build tool-level authorization separately from token-level authentication.

What This Looks Like in a Real Project

The project I can point to directly is Biz365 AI, a business intelligence platform where the agent layer needed reliable, scoped access to structured internal data. The work involved defining clear tool boundaries so the agent could query data without being handed a general-purpose database cursor — which would have been both a security problem and a context-window problem.

The pattern that held up: each tool does one thing, returns a typed and trimmed response, and writes nothing into the return value that the model does not need for the next step. Error messages are structured, not raw stack traces — a raw exception from a database driver leaks schema information and gives the model noise rather than signal.

MCP is the tool-connectivity layer. It does not replace orchestration, RAG retrieval, or workflow automation. MCP is a protocol for AI tool access, not a general-purpose API standard. Your REST and GraphQL APIs still serve human clients and traditional services. MCP wraps those APIs to make them accessible to LLMs. The existing APIs do not go away; you are adding a protocol adapter, not replacing infrastructure. If your agent also needs vector retrieval, that is a separate decision — covered in pgvector vs Pinecone: When the Cheap Option Is the Right One.

If you are mapping this work for your own system, the scoping details and engagement structure are on the MCP development service page. Most engagements start around $5K; smaller well-scoped work is considered case-by-case.

FAQ

Do I need MCP if I already have a REST API my agent calls directly?

Not necessarily. A direct HTTP tool call works fine in OpenAI function-calling or Claude tool-use without MCP. MCP becomes worth the overhead when you want the same tool server to work across multiple clients — Claude Desktop, Cursor, your own agent loop — without writing per-client adapters. If you have one client and one model provider, evaluate whether the abstraction pays for itself before committing.

Should I start with stdio or Streamable HTTP?

Use stdio when a single client launches your server as a local subprocess, use Streamable HTTP for anything remote or multi-client, and do not write a new HTTP+SSE server at all — that transport was deprecated in the 2025-03-26 MCP spec. If the server will eventually need to serve multiple users or run as a hosted service, start with Streamable HTTP even if it feels like more setup. Migrating transport later is more disruptive than getting the plumbing right initially.

How many tools is too many on one server?

There is no hard cutoff, but the cost is measurable. Every tool description adds tokens to every call. As a working heuristic: if your server has more than ten or twelve tools, audit whether all of them need to be active for the same agent workflow. Group by domain, expose only the group the workflow needs, and monitor per-tool latency and context contribution separately. MCP itself is not the problem — it is a key protocol for agentic solutions. The problem is tool design.

Is tool poisoning a concern for an internal server I wrote myself?

For a server you wrote and fully control, the risk is lower. But if you are pulling in third-party MCP servers alongside your own, treat them the way you treat third-party npm packages. A malicious MCP server or tool can appear legitimate during installation but later change its behavior. For example, a tool described as harmless could be updated to collect confidential data or perform unauthorized actions. Pin versions, review source, and watch for upstream changes.

What does the 2026-07-28 spec change mean for servers I have already built?

The 2026-07-28 release delivers a stateless core that scales on ordinary HTTP infrastructure, extensions including server-rendered UIs through MCP Apps and long-running work through the Tasks extension, and authorization that aligns more closely with OAuth and OpenID Connect deployments. If your existing server holds per-session state in memory, that assumption breaks under stateless HTTP. If you are on stdio, the practical impact is minimal for now — the transport unification work is on the roadmap but not yet shipped.

mcpai agentstool designmodel context protocolllm infrastructure

Hire me for similar projects

Looking for a developer who can build what you just read about? Let's talk.

Get in Touch