# What Is an MCP Server? How One Tool Call Travels

> What an MCP server is, from zero: how one AI agent tool call travels from client to server and back, and when to use stdio or Streamable HTTP transport.

URL: https://www.matthewswong.com/en/learn/ai-agents-mcp/what-is-mcp-how-a-tool-call-travels/

AI agents and MCP · Lesson 1 of 4 · Reviewed on 17 October 2026 · Checked against MCP specification 2026-07-28 · By Matthews Wong (https://www.matthewswong.com/en/about/)

> An MCP server is a program or web service that offers tools and data to an AI application over the Model Context Protocol. The model asks for a tool, the host checks the call, its MCP client sends a JSON-RPC tools/call, and the result comes back as text in the model's context. stdio carries local servers; Streamable HTTP carries remote ones.

## You will be able to

- Name the host, the client and the server in an MCP setup, and say which one decides whether a tool runs.
- Follow one tool call from the model's request to the result in its context, message by message.
- Choose stdio or Streamable HTTP for a server, and know what each one exposes.

## One MCP tool call, from request to result

The client lists the server's tools, the model asks for one call, the host checks it, the client sends tools/call, and the result returns to the model's context as text.

1. **Meet the parts.** The host is the AI app, such as Claude Code. It runs one MCP client per server. The server offers tools; the model sees only their names, schemas and results.
2. **Discover the tools.** First the client asks the server for tools/list. Each tool comes back with a name, a description and an input schema, which the host shows to the model.

   ```
   tools/list → name · description · inputSchema
   ```
3. **The model asks.** From the user's request and those descriptions, the model asks for one call: a tool name plus arguments. It cannot run anything itself; it can only ask.

   ```
   tool: search_issues · arguments: query=crash
   ```

   *Predict:* The model has asked for a call. What happens before anything reaches the server? (The server runs it at once / The host checks its rules or asks you)
4. **The host decides.** The host checks the call against its permission rules, or asks you. The MCP spec says a human should always be able to deny a tool invocation.

   ```
   Claude Code checks deny, then ask, then allow
   ```
5. **One JSON-RPC request.** The client sends a JSON-RPC tools/call. Since spec 2026-07-28 there is no handshake first: every request carries its own protocol version in _meta.

   ```
   method: tools/call · _meta: protocolVersion 2026-07-28
   ```

   *Predict:* The server answers. How does the model receive the text in that result? (As checked, trusted fact / As more text in its context / As a command the host must run)
6. **Back into context.** The server returns content, usually text, plus isError if the tool failed. The client hands it to the model as more context; nothing checked that it is true.

   ```
   resultType: complete · content: text · isError: false
   ```

## What is an MCP server, in plain words?

The Model Context Protocol (MCP) is an open standard for connecting AI applications to outside tools and data. An MCP server is the side that offers them: a small program on your machine, or a web service, that lists the tools it has and runs one when asked. Typical servers wrap an issue tracker, a database, a cloud API or a folder of files.

The specification names three roles. The host is the AI application, such as Claude Code or a desktop chat app. The host creates one client per server, and each client talks to exactly one server. The host keeps the whole conversation and enforces consent; by design a server receives only what it needs and should not be able to see into other servers.

A server can offer three kinds of things. Tools are functions the model may ask to run. Resources are context and data, each addressed by a URI. Prompts are templated messages a user picks. This lesson follows a tool call, because tools are where an agent stops reading and starts acting.

## How does one tool call travel from the model to the server and back?

The model never talks to a server. It asks the host for a call by naming a tool and its arguments; the host decides whether that call may run, and only then does its MCP client send a JSON-RPC request to the server. The result travels back the same way and lands in the model's context as text.

Discovery comes first. The client sends tools/list and receives each tool's name, description and input schema. The description is what the model reads to decide when a tool fits, which is why a vague or hostile description changes what an agent does. The spec adds that clients must treat tool annotations, such as a read-only hint, as untrusted unless they come from a trusted server.

The call itself is a tools/call request with the tool name and arguments. Since the 2026-07-28 revision MCP is stateless: there is no initialize handshake and no protocol session, and every request carries its protocol version and client capabilities in a _meta field. Servers built for 2025 revisions still expect the handshake, and clients detect which kind they are talking to.

The reply is a result with a content array, usually text, and isError set to true when the tool ran but failed, for example on a date in the wrong format. An unknown tool or a malformed request is a protocol error instead. Either way the client passes the outcome to the model, which reads it as input; nothing on the way checked that it is true.

## stdio or Streamable HTTP: which transport carries the call?

The transport is how the messages move; the messages themselves are the same. With stdio, the host launches the server as a child process on your machine and they exchange one JSON-RPC message per line over its standard input and output. With Streamable HTTP, the server is an independent service, and each message is an HTTP POST to a single endpoint.

stdio suits local tools: there is no port and no network listener. The server runs with your user's privileges, so trusting the command you launch matters. The spec says a stdio server must write nothing but MCP messages to stdout, and may log to stderr.

Streamable HTTP suits shared or remote servers. The reply is either one JSON object or a stream of events for that one request. Because the server is reachable over a network, the spec requires it to validate the Origin header, says a local server should bind only to 127.0.0.1, and says every connection should be authenticated. The older HTTP+SSE transport is deprecated.

## The real config behind this lesson

`app/components/blogs/KubernetesMcpServerReadOnlyToolsets.tsx:327-332`

```javascript
const config = process.argv[2];
const server = spawn(
  "npx",
  ["-y", "kubernetes-mcp-server@0.0.67", "--config", config],
  { stdio: ["pipe", "pipe", "inherit"] },
);
```

The audit script printed in this site's Kubernetes MCP article is a tiny MCP client, and this is the stdio transport in six lines: the client launches the server as a child process and owns its stdin and stdout. stderr is inherited, so the server's logs reach the terminal without mixing into the message stream. The version is pinned, because a server you launch is code you run.

`app/components/blogs/KubernetesMcpServerReadOnlyToolsets.tsx:351-356`

```javascript
send({ jsonrpc: "2.0", id: 1, method: "initialize",
  params: { protocolVersion: "2025-06-18", capabilities: {}, clientInfo: { name: "audit", version: "1" } } });
setTimeout(() => {
  send({ jsonrpc: "2.0", method: "notifications/initialized" });
  send({ jsonrpc: "2.0", id: 2, method: "tools/list" });
}, 3000);
```

The same script's messages speak the 2025-era protocol: an initialize request, the initialized notification, then tools/list, which suited the server version the article tested. Under the 2026-07-28 revision the handshake is gone. A client can send tools/list straight away with its version in _meta, and a client that also supports older servers should probe with server/discover first.

## What breaks

- **A stdio server that prints to stdout.** A stray console.log in a stdio server lands in the message stream, and the client fails to parse it as JSON-RPC. The spec says a stdio server must write only valid MCP messages to stdout. Send every log line to stderr.
- **Trusting a tool description you never read.** The model picks tools from their descriptions. A description that claims more than the tool does, or tells the model what to do next, steers the agent. Read a server's tools/list output before you connect it to anything real.
- **Mixing protocol eras.** A 2025 tutorial opens every connection with initialize and keeps an Mcp-Session-Id header. The 2026-07-28 revision removed both, so old snippets in a new SDK, or the reverse, fail in confusing ways. Check which revision your client and server speak first.
- **A local HTTP server open to the network.** A Streamable HTTP server bound to 0.0.0.0 with no authentication answers other machines too, and without Origin checks a web page can reach it through DNS rebinding. Bind to 127.0.0.1 and require a token.

### The two standard MCP transports

| Transport | Where the server runs | How messages move | What to guard |
| --- | --- | --- | --- |
| stdio | A child process the host launches on your machine | One JSON-RPC message per line on stdin and stdout | The command you launch runs with your privileges |
| Streamable HTTP | An independent service, local or remote | One HTTP POST per message; the reply is JSON or an event stream | Anyone who can reach the endpoint: check Origin, require auth |

## Try it yourself

You need a terminal and Node.js 22.19 or newer, which the MCP Inspector requires. No account and no API key. The Inspector is the protocol's reference debugging client, so you watch real messages with no AI model in the loop.

1. Make a small practice folder for the filesystem reference server to serve.

   ```bash
   mkdir -p ~/mcp-practice && echo hello > ~/mcp-practice/note.txt
   ```
2. Ask the server for its tool list over stdio. The Inspector launches the server as a child process, exactly as a host would.

   ```bash
   npx -y @modelcontextprotocol/inspector --cli npx @modelcontextprotocol/server-filesystem ~/mcp-practice --method tools/list
   ```
3. Find list_directory in the output and read its description and input schema. That text is all a model would know about the tool.
4. Call the tool. The content in the result is the text an agent would read back into its context.

   ```bash
   npx -y @modelcontextprotocol/inspector --cli npx @modelcontextprotocol/server-filesystem ~/mcp-practice --method tools/call --tool-name list_directory --tool-arg path=$HOME/mcp-practice
   ```
5. Open the web Inspector on the same server to see the exchange as JSON-RPC messages, one request and one response at a time.

   ```bash
   npx -y @modelcontextprotocol/inspector npx @modelcontextprotocol/server-filesystem ~/mcp-practice
   ```

## Quick quiz

1. **In an MCP setup, which part decides whether a tool call is allowed to run?**
   A. The MCP server
   B. The host application, such as Claude Code
   C. The model
   Answer: B. The host enforces security policy and consent, and the spec says a human should be able to deny any tool invocation. The model only asks; the server only runs what reaches it.

2. **Which transport launches the server as a child process on your machine?**
   A. stdio
   B. Streamable HTTP
   C. HTTP+SSE
   Answer: A. With stdio the host starts the server and exchanges one JSON-RPC message per line over its standard streams. Streamable HTTP talks to an independent service, and HTTP+SSE is deprecated.

3. **Under the 2026-07-28 spec, what must a client send before its first tools/call?**
   A. An initialize request
   B. A session ID it got from the server
   C. Nothing: each request carries its version in _meta
   Answer: C. The handshake and protocol sessions were removed in 2026-07-28. A client may call server/discover first, and should when it also supports older servers, but nothing is required.

## Think it through

- **Why can a badly written tool description make an agent misbehave even when the tool's code is fine?** The model chooses tools and arguments only from their names, descriptions and schemas. A description that overstates what a tool does, or carries instructions, steers that choice before any code runs.
- **A tool ran, but the date argument was in the wrong format. Does the client get a JSON-RPC error?** No. That is a tool execution error: a normal result with isError set to true and a message in content, which the model can read and correct. JSON-RPC errors are for protocol problems, such as an unknown tool or a malformed request.
- **Why does a stdio server write its logs to stderr and not stdout?** stdout carries the JSON-RPC messages, one per line, and the spec says a stdio server must write nothing else there. Anything extra corrupts the stream; stderr is free for logs.

## Go deeper

- [MCP Explained: What the Model Context Protocol Actually Solves](https://www.matthewswong.com/en/blog/mcp-model-context-protocol-explained/)
- [MCP Transports: stdio vs Streamable HTTP](https://www.matthewswong.com/en/blog/mcp-transports-stdio-vs-http/)
- [MCP Primitives: Tools, Resources, and Prompts](https://www.matthewswong.com/en/blog/mcp-tools-resources-prompts-primitives/)
- [MCP 2026-07-28 Spec Migration: Stateless Guide for Servers](https://www.matthewswong.com/en/blog/mcp-2026-07-28-stateless-spec-migration/)

## Sources

- [MCP specification 2026-07-28: architecture (hosts, clients, servers)](https://modelcontextprotocol.io/specification/2026-07-28/architecture)
- [MCP specification 2026-07-28: tools, tools/list and tools/call](https://modelcontextprotocol.io/specification/2026-07-28/server/tools)
- [MCP specification 2026-07-28: transports (stdio, Streamable HTTP)](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports)
- [MCP specification 2026-07-28: key changes since 2025-11-25](https://modelcontextprotocol.io/specification/2026-07-28/changelog)
- [MCP docs: the MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector)
- [Filesystem reference server: tools and allowed directories](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem)

---

- HTML version: https://www.matthewswong.com/en/learn/ai-agents-mcp/what-is-mcp-how-a-tool-call-travels/
- Bahasa Indonesia: https://www.matthewswong.com/id/learn/ai-agents-mcp/what-is-mcp-how-a-tool-call-travels/
- Site index for agents: https://www.matthewswong.com/llms.txt
- Sitemap: https://www.matthewswong.com/sitemap.xml
- API description (OpenAPI): https://www.matthewswong.com/openapi.json
