Next-Gen App & Browser Testing Cloud
Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

Model Context Protocol replaces one-off LLM integrations with a single open standard. This guide covers MCP architecture, the STDIO and Streamable HTTP transports, the Python and TypeScript SDK trade-off, and the environment setup for both.

Piyusha Podutwar
Author

Anubhav Singhmaar
Reviewer
Last Updated on: August 26, 2026
Software teams have spent years stitching AI models to external tools through fragile, one-off integrations: custom wrappers, hardcoded endpoints, and brittle middleware that breaks the moment an API version changes. Every new tool meant starting that process over from scratch. The engineering debt quietly piled up, and the promise of truly intelligent, connected AI systems stayed just out of reach.
Model Context Protocol changes that equation entirely. Rather than building a separate bridge for every service your AI needs to talk to, MCP provides a single standardized, open protocol that works across tools, platforms, and models. Write the integration once, and any MCP-compatible AI system can use it today and as your stack evolves tomorrow.
TL;DR
The current state of LLM integration is a complete mess. The rush to create AI-powered features has resulted in an abundance of unique, one-time "glue code."
Consider this: you must create custom integration code each time you want an LLM to communicate with a new database, access a new API, or perform a new function. This strategy is:
The solution to this chaos is MCP. By offering a single, open-protocol standard for all LLM interactions, it tackles these crucial scaling, maintenance, and security issues. Having a reliable, standard interface to connect all the LLM models to your systems is not only handy but also vital in a world where new models are released every other week.
MCP is fundamentally an open-source protocol intended to provide a standardized, simplified interface for integrating AI models with external systems. Consider it as a set of guidelines and a common language that your external systems and the LLM agree to use.
Consider the MCP as an AI application's USB-C port. MCP offers an established approach for connecting AI applications to external systems, much like USB-C offers a standardized way to connect electronic devices. If you want the wider context on where the protocol sits alongside agent frameworks, TestMu AI covers that ground in MCP and AI agents.
| Feature | Traditional API Integration | MCP Integration |
|---|---|---|
| Prompt Complexity | Very High: Requires embedding extensive, raw API documentation, endpoints, and authentication workflows directly into a system prompt. It forces the LLM to learn how to construct valid HTTP requests and handle custom error parsing per endpoint through natural language instructions. | Low: The model only ingests semantic tool names and descriptions. It leverages an automated schema discovery handshake via JSON-RPC 2.0 (tools/list), which programmatically communicates input parameters and type requirements, drastically reducing system prompt token overhead. |
| Model Brittle | Extremely High: Any minor structural modification to a downstream REST API payload or parameter name breaks the LLM reasoning loop. This results in silent execution failures that require manual prompt updates and complete regression re-evaluations. | Low: Upstream drift is isolated within the specific MCP server wrapper logic. The interface exposed to the LLM remains immutable. QA only needs to verify the updated server handler code, while the host-side orchestration prompt contract stays stable. |
| Parameter Validation & Safety | Ad-hoc / Non-existent: Relies entirely on loose prompt constraints or post-processing regular expression blocks to intercept outputs. There are no rigid safety rails to prevent the model from fabricating or hallucinating invalid parameter fields. | Rigid / Deterministic: Utilizes type-safe runtime interception via validation engines like Zod (TypeScript) or Pydantic (Python). Malformed payloads are blocked and rejected programmatically at the communication boundary before code runs, ensuring exact parameter conformity. |
| Scalability & Interoperability | Low: Creates custom, hardwired bridge solutions. A prompt-engineered connector built for one specific LLM framework or orchestration agent cannot easily adapt to another without a total rewrite of its prompt logic. | High: Operates as a reusable, open standard. By decoupling the AI client from tool execution via standard transport layers (STDIO or SSE), a verified server is instantly plug-and-play across any compliant host platform (e.g., Cursor, Claude Desktop, VS Code). |
| Developer & QA DX | Poor: Engineers spend excessive test and debug cycles troubleshooting flaky, non-deterministic edge cases caused by the model formatting string arguments incorrectly or confusing input fields. | Excellent: QA can deterministically intercept, log, and audit the raw JSON-RPC traffic. This abstraction allows developers to focus on standard software engineering principles (strict type definitions, semantic docstrings) while simplifying bug isolation between model reasoning and code execution. |
Talking about a protocol is good; building one is better. This guide is a technical tutorial designed to get you from zero to a working MCP server. We will not be building a theoretical "hello world" scenario. We're going to create a functional, real-world integration: A Weather MCP Server.
We'll focus on the entire developer lifecycle: from initial project setup and defining the core MCP logic to testing and deploying the server. This is your first step toward building truly connected, robust AI systems. Let's get started.
The architecture behind MCP is made to be flexible, scalable and adaptive to various LLM environments and applications. Fundamentally, MCP uses a client-server architecture that enables large language models to safely access external tools and context without hardwired integrations. MCP is centered around three primary components at a higher level.

Figure 1: MCP Architecture
1. MCP Host
The top-level runtime: a desktop app, IDE plugin, or agent framework where the AI lives. The Host owns the user session, manages connection lifecycles, and controls which servers are reachable. It is the authorization gatekeeper and your first point of integration testing.
2. Client
A scoped, one-to-one connection to a single MCP Server living inside the Host. Clients handle protocol mechanics: handshakes, capability negotiation, request/response pairing, and transport-level error handling.
3. Server
A runtime process that exposes Tools, Resources, and Prompts via the MCP interface. The server operates independently and does not inherently know which specific LLM model is invoking it. While MCP was originally designed as a stateful protocol requiring an initialization handshake, its state behaviour depends entirely on how it is deployed:
For an in-depth breakdown of how the protocol balances stateful sessions with cloud scaling architectures, see the Model Context Protocol blog post Exploring the Future of MCP Transports.
The most crucial idea in MCP is the MCP primitives. They specify what the clients and servers can offer each other. These primitives define the range of actions that can be implemented and the types of contextual information that can be shared with AI applications.

Figure 2: The MCP Primitives
For the complete core implementation details on executable actions and template contexts, see the Model Context Protocol documentation on Understanding MCP servers.
If you want to see how those primitives get used once a server is running, TestMu AI has a companion piece on MCP servers for test automation.
One of the most consequential decisions when building an MCP server is choosing how it communicates. Before any tool is called or any resource is fetched, the client and server need a shared channel to exchange JSON-RPC messages. The Model Context Protocol formalizes this through its transport layer, a pluggable mechanism that handles connection setup, message serialization, and lifecycle management without touching your application logic.
MCP currently defines two production-ready transport mechanisms: Standard Input/Output (STDIO) and Streamable HTTP (which incorporates Server-Sent Events as an optional streaming layer). There is also a legacy HTTP+SSE design that has since been deprecated but may still appear in older server implementations. Knowing what each transport does, where it performs best, and what it costs operationally is what separates a well-architected MCP deployment from one that causes friction at scale.
The transport layer in MCP has a narrowly defined job: convert outgoing MCP objects into the JSON-RPC 2.0 wire format, move them across the connection, and convert incoming bytes back into typed messages. It does not interpret those messages; that is the server's responsibility. The transport ensures just the delivery.
Every MCP message belongs to one of three categories, regardless of which transport carries it:
This separation of concerns is what makes transports interchangeable. You can write your MCP server logic once and expose it over STDIO, Streamable HTTP, or both, and the application code does not change.
STDIO is the simplest transport in the MCP ecosystem and currently the most widely deployed.
How It Works
When a host application wants to talk to an MCP server over STDIO, it spawns the server as a child process. From that point, the two processes communicate entirely through standard streams: the client writes JSON-RPC messages to the server's stdin, and the server writes responses back to stdout.
Key Features of STDIO
Limitations to Know
For more information on how code verification and deployment signing work for local systems, see Microsoft's documentation on ClickOnce and Authenticode.
When to Choose STDIO
When your MCP server needs to run on the internet rather than on a developer's local machine, HTTP/SSE is the transport you reach for. MCP's HTTP transport has gone through two versions. The original design (HTTP+SSE) is now deprecated due to its complexity. Its replacement, Streamable HTTP, is the current standard and what all new implementations should use.
How It Works
Streamable HTTP uses a single URL that handles all communication in both directions. The client sends requests via HTTP POST. The server replies with either a plain JSON response for quick, simple results or opens an SSE stream for long-running tasks that produce multiple messages.
The client can also establish a persistent SSE channel via HTTP GET, over which the server pushes real-time notifications and updates without being explicitly polled. If a connection drops mid-task, the client reconnects and sends the last event ID it received. The server replays anything missed, so the task picks up where it left off rather than restarting from scratch.
Key Features
Limitations
When to Use It
Note:
| Dimension | STDIO | Streamable HTTP |
|---|---|---|
| Server location | Same machine as client | Anywhere, local or remote |
| Concurrent clients | One per process | Many, simultaneously |
| Network required | No | Yes |
| TLS / HTTPS | Not applicable | Required in production |
| Authentication | OS user permissions | Must be implemented explicitly |
| Latency | Near-zero (in-process pipes) | Network round-trip + HTTP overhead |
| Session state | Tied to process lifetime | Explicit session IDs across requests |
| Resumability | Not applicable | Last-Event-ID replay |
| Infrastructure needed | None | Server runtime, certs, auth, networking |
| Best suited for | Developer tools, CLIs, IDEs | Cloud services, SaaS, shared servers |
Transport selection in MCP is less about technical capability and more about where your server lives and who connects to it. STDIO is the right default for local developer tooling: zero infrastructure, zero configuration, zero network exposure. Streamable HTTP is the right foundation for anything that runs as a persistent, network-accessible service: scalable, resumable, and compatible with every piece of HTTP infrastructure your organisation already operates.
Understanding what happens between the moment a user asks an AI a question and the moment a result comes back requires looking at how MCP actually moves messages. Every interaction, whether the model is calling a tool, reading a file, or fetching data from an API, follows a structured sequence. Every MCP session moves through three distinct phases: handshake, discovery, and operation. These happen in order and cannot be skipped.
Before any tool gets called or any data gets read, the client and server must introduce themselves. The client sends an initialize request carrying its protocol version and a list of capabilities it supports. The server responds with the protocol version it will use for the session and its own set of capabilities, which tools it exposes, whether it supports resource subscriptions, and so on. If the two sides cannot agree on a compatible protocol version, the connection is dropped immediately.
Once the server responds, the client sends an initialized notification to confirm that it is ready. Only after this exchange is complete can either side send anything else. Requests sent before initialization is confirmed are rejected.

With the session open, the client asks the server what it can do. This typically means sending a tools/list request to get a catalogue of available tools, a resources/list request to see what data is accessible, and a prompts/list request to find reusable templates. The server responds to each with a structured list. The AI model uses this information to decide which tools are relevant to the user's request.
Once the model knows what tools are available, it can invoke them. A tool call is a tools/call request that names the tool and passes the required arguments. The server executes the operation and returns the result. This is the core loop: the model calls tools, gets results, reasons about them, and calls more tools as needed.
The server's response echoes the same id so the client can match it back to the original request, important in asynchronous environments where multiple calls may be in flight at once.
Not every message requires a reply. Notifications are one-way messages, they carry no id field and expect no response. Servers use them to push updates to the client without being asked: a progress update on a long-running task, an alert that the tool list has changed, or a log message. The client can also send notifications to the server, such as signalling that it is cancelling an in-progress request.
When the session is done, the connection is closed cleanly. For STDIO, the client closes the server's input stream and waits for the process to exit. For HTTP-based transports, closing the connection is sufficient, no special protocol message is needed.
Selecting an SDK for your Model Context Protocol (MCP) server involves evaluating the ecosystem, performance profile, and long-term maintenance overhead of the integration. While the protocol is transport-agnostic, the implementation path usually splits between Python and TypeScript based on the specific architectural needs of the project.
The Python SDK for MCP is a high-level framework designed for rapid development of Model Context Protocol servers. With the introduction of FastMCP, the SDK has moved toward a "convention-over-configuration" approach, allowing developers to convert Python functions into MCP tools with minimal boilerplate.
Key Strengths
Limitations
When to Use
The TypeScript SDK is a robust, type-safe implementation of the Model Context Protocol built for the Node.js environment. It is designed to handle enterprise-level integrations where architecture, scale, and contract-rigidity are the primary concerns.
Key Strengths
Limitations
When to Use
The same trade-off shows up when you decide whether an AI agent should reach your tooling through a protocol server or a command line at all, which TestMu AI compares in MCP vs CLI.
Before writing any MCP server code, your environment needs to be correctly set up. This section covers what to install, how to initialise your project, and how to configure your project files for both Python and TypeScript.
To begin building, ensure your local environment meets these baseline specifications:
1. TypeScript MCP Project Structure
Create a clean and testable structure from the beginning.
weather-mcp-ts/
|-- package.json
|-- tsconfig.json
|-- src/
|-- index.ts2. Project Initialization
3. Configuring package.json
This file acts as the single source of truth for your server's metadata and execution commands. The single most important setting is "type": "module". The MCP SDK is ESM-only, omitting this causes ERR_REQUIRE_ESM errors.
Example: package.json
{
"name": "weather-mcp-ts",
"version": "1.0.0",
"description": "A simple MCP server built with TypeScript",
"type": "module",
"bin": {
"weather-mcp-ts": "./build/index.js"
},
"scripts": {
"build": "tsc && chmod 755 build/index.js",
"start": "node build/index.js",
"dev": "tsc --watch"
},
"files": [
"build"
],
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"zod": "^3.0.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "^5.0.0"
}
}Important package.json fields: type: module enables ESM imports; bin allows the package to be executed as a command; build compiles TypeScript to JavaScript; files controls what gets packaged if published.
Note on cross-platform compatibility: The chmod 755 command in the build script is Unix/macOS only and will fail on Windows with an error. There are two ways to handle this, depending on the use case:
Option 1: Use the shx package for cross-platform compatibility. Install it with npm install -D shx and update the build script to:
"build": "tsc && shx chmod 755 build/index.js"Option 2: Skip chmod entirely if you are not publishing this server as a CLI binary on Unix systems. The permission flag is only necessary when the built file needs to be executed directly as a standalone command from the terminal. If you are running it via node build/index.js, it is not required.
4. Configure tsconfig.json
This configuration compiles source files from src into build, uses modern JavaScript output, and enables strict type checking.
Example: tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}1. Python MCP Project Structure
weather-mcp-python/
|-- pyproject.toml
|-- uv.lock
|-- .venv/
|-- weather.py2. Configuring a Virtual Environment for Python
When building an MCP server in Python, it is best practice to isolate project dependencies inside a virtual environment. A virtual environment keeps the MCP SDK, HTTP clients, and other packages separate from your global Python installation.
Option 1: Using uv Virtual Environment
Create the project:
uv init weather-mcp-python
cd weather-mcp-pythonCreate the virtual environment:
uv venvThis creates a local .venv directory containing the isolated Python interpreter and installed packages for this project.
Activate the virtual environment:
# macOS or Linux
source .venv/bin/activate
# Windows PowerShell
.venv\Scripts\Activate.ps1
# Windows Command Prompt
.venv\Scripts\activate.batInstall MCP dependencies:
uv add "mcp[cli]" httpxThis installs the Python MCP SDK with CLI helpers and httpx for HTTP requests. uv also updates pyproject.toml and the lock file.
Example: pyproject.toml
[project]
name = "weather-mcp-python"
version = "0.1.0"
description = "A simple MCP server built with Python"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"mcp[cli]>=1.2.0",
"httpx>=0.27.0"
]
[project.scripts]
weather-mcp-python = "weather:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"Option 2: Using Python's Built-in venv
mkdir weather-mcp-python
cd weather-mcp-python
# macOS or Linux
python3 -m venv .venv
source .venv/bin/activate
# Windows
python -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install "mcp[cli]" httpxIf you use plain venv and pip instead of uv, you can store dependencies in requirements.txt.
pip freeze > requirements.txt
# Later, another developer can install dependencies with:
pip install -r requirements.txtNote on dependency management: pip freeze captures all installed packages, including transitive dependencies with pinned versions, which produces a bloated requirements.txt that is difficult to maintain. There are cleaner approaches depending on your workflow:
Option 1: Maintain a lean requirements.txt manually by listing only your direct dependencies without pinned versions unless stability demands it:
mcp[cli]>=1.2.0
httpx>=0.27.0Option 2: Use pip-compile from the pip-tools package for reproducible lockfiles. It separates direct dependencies from resolved transitive ones, giving you both clarity and reproducibility:
pip install pip-tools
pip-compile requirements.inOption 3: Use uv, which is the modern best practice for Python dependency management. It generates a clean lockfile automatically while keeping your direct dependencies readable and separate.
For developers inheriting this project, a requirements.txt produced by pip freeze with hundreds of pinned transitive entries is a maintenance burden. List what you need, let the tooling resolve the rest.
You now have the four decisions that shape every MCP server, made before a single tool is written. Which primitives you expose determines who controls invocation. Which transport you pick determines where the server can live and how many clients it serves. Which SDK you choose determines how much boilerplate stands between a function and a registered tool. And a correctly configured project is what keeps ERR_REQUIRE_ESM and a Windows-only chmod out of your first run.
From here, the build itself is the short part. Register a tool, run the MCP Inspector against the server in isolation, and only then connect it to a host. Debugging a schema mismatch inside a chat client is far harder than catching it in the Inspector, which is why the tool belongs in your prerequisites rather than your troubleshooting steps.
A working reference beats a specification when you are checking your own implementation. The TestMu AI MCP Server is a production Streamable HTTP server with OAuth that you can connect to your own IDE and inspect, covering HyperExecute, automation test triage and debug, SmartUI visual diff analysis, and accessibility. Read the TestMu AI MCP Server documentation for the tool list and per-client configuration, or sign up for free and point your client at it to watch a real JSON-RPC session run end to end.
Author
Piyusha Podutwar is a Senior Software Engineer at DPS with over 12 years of experience in mainframe application and system programming. She has authored 20+ technical tutorials for TestMu AI on API testing, Agile, DevOps automation, software testing, automation testing, and digital transformation. She is skilled in Assembler, COBOL, DB2, and JCL, and has led large-scale modernization and migration projects across banking, finance, retail, and insurance domains. A Certified Scrum Master, Piyusha previously worked with IBM, TCS, BMC Software, and T-Systems.
Reviewer
Anubhav Singhmaar is an AI Product Manager at TestMu AI driving Kane CLI, the command-line tool that brings browser automation to the terminal, turning natural-language flows into runs in a real Chrome browser that return pass or fail with shareable proof. He owns the roadmap and prioritization and works with engineering to ship developer-facing features. Before TestMu AI, he spent over four years at Sprinklr owning enterprise voice AI across APAC and EMEA. A mechanical engineer turned product manager, he grounds guidance in real QA workflows.
Did you find this page helpful?
More Related Blogs
TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance