AI agents and the Model Context Protocol (MCP)
What an AI agent is - tool calling, planning, the loop and its guardrails - and the Model Context Protocol from hosts and servers down to the JSON-RPC messages, with real example messages, how to write and connect a server, and the two agent patterns {{brand}} uses.
In short
An AI agent is a language model that works in a loop: it reads a goal, chooses a tool, looks at the result and decides the next step, until the job is done or a limit stops it. The Model Context Protocol (MCP) is the open standard that lets any agent - Claude Code, GitHub Copilot, Cursor - use any program's tools through one kind of connection. {{brand}} uses agents in two ways: an MCP server in its command-line tool lets coding agents run suites, read failures and file bugs, and inside the product a sentence becomes a typed plan that a person confirms before anything runs.
After this lesson you can Explain what an agent is and draw its loop; read and write MCP messages - initialize, tools/list, tools/call - by hand; build a small MCP server and connect it to an agent; and design the guardrails that keep an agent useful without making it dangerous.
Words you need
- AI agent A model with tools in a loop: it plans a step, calls a tool, reads the result and repeats until the goal is met or a limit stops it.
- Tool calling Also called function calling. The model answers with a structured request - a tool name and JSON arguments described by a JSON Schema (a JSON description of the allowed fields and types) - instead of text. Your code runs the tool; the model never runs anything itself.
- Guardrail A rule outside the model that limits what an agent can do: scopes, allow-lists, budgets. The strongest kind is a human in the loop: a person reads and confirms a step before it changes anything.
- Prompt injection Text the agent reads - a web page, a card title, an API answer - that tries to give it new orders.
- MCP The Model Context Protocol: an open standard for connecting AI applications to tools and data, built on JSON-RPC 2.0.
- Host and client The host is the AI application a person uses - Claude Code, VS Code with GitHub Copilot, Cursor. It owns the model and decides what the model may call. Inside it, one client per server speaks MCP on the host's behalf.
- Server A program that offers tools, resources or prompts over MCP, such as a filesystem server or a GitHub server.
- Tool, resource, prompt The three things a server offers: tools the model calls, resources the application attaches as context, prompts the person picks as templates.
- JSON-RPC 2.0 A tiny message format: a request has an id, a method and params; a response has the same id and a result or an error; a notification has no id.
- Transport How the messages travel: stdio - the standard input and output of a child process - or Streamable HTTP.
- Idempotency key A label made from what a change is, so asking twice does the change once and the second answer is the first result.
- Context window The amount of text a model can read at once. Tool lists, history and tool results all share it, and every token costs money and attention.
How an AI agent works
A chat assistant answers one question. A workflow runs steps a programmer fixed in advance. An agent decides its own next step, in a loop, choosing from the tools it was given. That freedom is what makes agents useful - and what makes guardrails necessary.
- 1. Goal A person gives a goal, and the host gives the model a list of tools, each with a name, a description and a JSON schema of its arguments.
- 2. Plan The model decides what to do first. Some agents write a whole plan up front; most decide one step at a time.
- 3. Act The model answers with a tool call - a name and arguments - not with text. It runs nothing itself.
- 4. Guard The host checks the call: is the tool allowed, does it change something, must a person confirm it?
- 5. Observe The host runs the tool and hands the result back to the model as new input.
- 6. Repeat or stop The loop goes on until the model gives a final answer - or a step budget, a time limit or a person stops it.
These three pieces belong to one exchange. OpenAI and Google use other field names for the same idea: a list of tools, a request to call one with arguments, and a result tied to the call by an id.
Planning, loops and guardrails
Agents plan in a few well-known styles. Knowing their names helps you read any agent framework and answer design questions.
A model is not a security boundary: it can misunderstand, loop, or be talked into things by text it reads. So every limit that matters lives outside the model, in code the model cannot change.
The lethal trifecta An agent that reads private data, reads untrusted text and can send data out can be tricked into leaking that data - the pattern Simon Willison named the lethal trifecta. Example: an agent that reads your email (private data), opens web pages (untrusted text) and can send mail (send out): a hidden sentence on a page can make it forward your inbox. Prompt injection has no complete fix today, so design so that at least one of the three legs is missing or tightly bounded.
The Model Context Protocol
Before MCP, every AI application wrote its own connector for every tool: M applications times N tools.
MCP turns that into M plus N: each application is a client once, each tool a server once.
The idea comes from the Language Server Protocol, which did the same for code editors and programming languages. Anthropic published MCP as an open standard in November 2024, and most AI applications and coding tools now support it.
What a server offers: three kinds of thing, each controlled by a different party.
What a client offers: abilities the host lends to a server, if the person allows it.
Tools are what agents use most Most servers - {{brand}}'s included - offer only tools. A tool is a typed function with a description; the model reads the description to decide when to call it, so write it like documentation for a careful colleague.
JSON-RPC 2.0: the messages underneath
Every MCP message is a JSON-RPC 2.0 object, and there are only three shapes. A request carries an id and expects exactly one response with the same id. A notification has no id and is never answered. A response carries either a result or an error, never both.
The id ties an answer to its question Requests may be answered out of order - a slow tool call does not block a quick one. The id is how both sides match them, so a server answers each id exactly once, and the sender never reuses an id within a session.
Transports: stdio and Streamable HTTP
- Start The host starts the server as a child process, with the command, arguments and environment from its settings.
- Talk The host writes one JSON-RPC message per line to the server's standard input; the server answers one message per line on standard output. A message never holds a raw line break, so one line is one message.
- Log Anything meant for a person - logs, warnings - goes to standard error. The host may show it; it never reads it as protocol.
- Stop The host closes standard input. The server finishes and exits, and is stopped by force only if it does not.
Standard output belongs to the protocol One stray print - a banner, a debug line, a library's warning - lands in the middle of the message stream and breaks the connection. A stdio server must send every line meant for a person to standard error, from the very first line of its start-up.
- POST to one endpoint The client POSTs each JSON-RPC message to one endpoint (for example /mcp) with a Bearer token and the header Accept: application/json, text/event-stream.
- Plain answer or a stream The server answers with plain JSON, or opens a stream of server-sent events - one-way pushes from server to client over a single HTTP response - when it needs to send progress first.
- A session id, maybe A session id header may tie requests together. The stateless revision drops it, so any copy of the server can answer.
- No token: 401 Without a valid token the server answers 401 and points to its protected-resource metadata, which names the authorisation server.
- OAuth 2.1 sign-in The client sends the person through an OAuth 2.1 sign-in with PKCE, gets a token meant for this server only, and retries the request.
An OAuth resource server is a service that accepts tokens issued by someone else - the authorisation server - and checks them. That separation is why a shared MCP service never handles passwords.
The handshake, capability negotiation and a tool call
- 1. initialize The client sends its newest protocol version, its capabilities and its name.
- 2. The answer The server answers with the version it will speak - the same one, or another it supports - plus its own capabilities, its name and optional instructions for the model.
- 3. initialized The client sends the notification notifications/initialized. Normal work may begin.
- 4. tools/list The server lists each tool's name, description and inputSchema; a cursor pages a long list.
- 5. tools/call The client sends a tool name and arguments; the result holds content for the model and, in newer revisions, structuredContent for programs.
- 6. Along the way A long call may send notifications/progress; either side may send notifications/cancelled. In the handshake era, ping also checks that the other side is still there (the 2026 revision has no ping).
The rule is simple: neither side uses a feature the other did not declare. A server that declared only tools is never asked for resources; a client that did not declare sampling is never asked to lend its model. Version negotiation works the same way: the client offers its newest version; a server that cannot speak it answers with one it can, and the client decides whether to stay.
Tools in depth: schemas, hints and two kinds of failure
Hints are not guarantees Annotations help a host decide what to ask the person to confirm, but a host must not trust them from a server it does not trust. The real protection lives in the server: a read-only tool must simply have no way to write.
Every tool costs context The model reads every tool description and every result. Each one fills the context window and costs tokens, so a server with 200 thin tools wastes the budget and confuses the model. Offer few tools, keep results small and say when text was cut, and let the host show which tools were called.
MCP separates two kinds of failure. A protocol error - an unknown method, a malformed request, an unknown tool - is a JSON-RPC error, and the host handles it. A tool error - the city does not exist, a permission is missing - is a normal result with isError: true, so the model reads the sentence and can correct itself.
The 2026 revision: no handshake
The handshake has a cost: the server must remember each connection, which makes it hard to run many copies of it behind a load balancer. The 2026-07-28 revision makes MCP stateless. There is no initialize and no session id, and ping no longer exists. Every request carries its protocol version and the client's capabilities in _meta, and a server/discover request tells a client what the server offers.
- Handshake era initialize, then a connection that both sides remember.; Simple negotiation, once; Capabilities declared one time; The server must remember each connection; Hard to run behind a load balancer
- Per-request era (2026-07-28) Every request carries its version and capabilities.; Any copy of the server can answer; Lists such as tools/list carry a cache lifetime; Bigger requests; Hosts move to the new revision at different speeds
See the specification's changelog for the exact wording of what changed in each revision.
Two eras in one server A client of one era fails against a server of the other, and hosts move to new revisions at different speeds. {{brand}}'s server answers both eras in one process and decides per request: a request that carries its version in _meta is answered on its own; an initialize opens the older handshake.
The options in the market
- REST API and a token The agent calls your public API directly, for example with curl.; Nothing new to build; Works for any agent that can make HTTP calls; The agent must learn the API from documentation; Every call is free-form and hard to limit to safe ones; Answers are not marked as data
- Function calling inside one app Tools written into one AI application's code, for one model vendor.; Tight and fast; No extra process; Works in that one app only; Written again for every vendor and host
- An MCP server One server any MCP host can start and use.; One server for Claude Code, Copilot, Cursor and the rest; Typed tools with schemas; The server decides what is offered at all; A program to ship, version and support; Hosts differ in details; The protocol is still moving
- Computer use: the agent drives the UI The model looks at screenshots and clicks like a person.; No integration at all; Slow and brittle; Sees everything on the screen; Very hard to bound
- A command-line tool in a shell The agent runs commands and reads their printed output.; Simple, scriptable; The agent needs a shell, a very wide permission; It parses text written for people; No schema
- Suggest only The AI answers; the person does the work.; No risk at all; The person does every click; The AI cannot save real time
- Act directly with the person's rights The agent does what it understood, straight away.; Fewest clicks; One injected sentence can act; Mistakes land before anyone sees them; Hard to review or undo
- The model writes code or SQL that runs Model output is executed.; Very flexible; Executing model output is the most dangerous pattern; Needs a sandbox and a reviewer
- Typed plan, confirmed, run by normal commands The model proposes steps from a fixed catalog; a person confirms; the product's own commands run them.; Every value visible before it runs; Same permissions, limits and audit as a click; Undo for what a step created or changed; Only what the catalog offers; One more click
What {{brand}} chose, and why
{{brand}} uses two agent patterns: an MCP server for the coding agents people bring, and a typed plan for the AI built into the product.
- One server, every host: Claude Code, GitHub Copilot and Cursor all speak MCP, so one server serves them all.
- stdio, on the developer's machine: the agent, the access token and the suites it runs from that machine all stay there; nothing new is opened on the internet.
- Tools only: each tool wraps calls to the public API that an access token could already make, so the server adds no new power - it only shapes answers for a model.
- Read-only by default: changes, and runs from the machine, are switched on by the person who starts the command - never by the agent.
- Written by hand: the protocol part of a tools-only server is small, and writing it gave full control over every byte on standard output.
- The model only proposes steps from a fixed catalog; a person reads every value and confirms.
- Each step runs the same command a click sends, with that person's permissions, plan limits and audit.
- What a step created or changed can be undone, and nothing in the catalog deletes.
The trade-off accepted A hand-written server means following each protocol revision with tests. stdio keeps the agent, the credential and the runs on the developer's machine; a service shared by cloud agents would use Streamable HTTP with OAuth instead. And every confirmation costs a click - accepted, because an AI change nobody read is the expensive kind.
When another option is right: a service used by agents in the cloud should offer Streamable HTTP with OAuth; a prototype should start from the official SDK; a server whose agents mostly read documents should offer resources as well as tools.
Where {{brand}} uses MCP: the command-line server
{{brand}}'s command-line tool has an mcp command. A coding agent's host starts it as a child process and speaks MCP over stdio; a person never types into it. Which tools exist depends on how the person started it: reads are always there, runs from the developer's machine and changes are switched on separately, and a tool that is not allowed is not even listed, so the model is not tempted. It is refused if called anyway.
- get_suite_run The agent reads the failed run and the step that failed.
- Ask for the choices It asks the server which boards take bugs and who a ticket can be given to. Ids come only from earlier answers of the server, never from text the agent read.
- file_bug The agent sends ids it was given earlier and a severity. It sends no free text; the server writes the record from what it measured, so nothing the agent read can land on it.
- A safe retry Every change carries an idempotency key built from what the change is, so a retry after a timeout returns the first result.
A credential made for one task can be given an even smaller set of tools than a personal token.
Propose, confirm, execute: a safe pattern for an in-app agent
Inside {{brand}}, a person can type what they want done - "create a task Fix the login redirect, high priority, due Friday" - and get a plan instead of an action. This is the propose, confirm, execute pattern, and it reuses every check the product already has. The rest of this section is the pattern itself, with a generic example.
- 1. Propose from a fixed catalog The model that chooses the steps sees only the catalog of typed actions (each with a JSON schema), the sentence, where the person is and the date - no workspace data. A second, narrower call may read the record on screen, but only to write a few text fields the action marked as writable from a record. Its reply schema holds only those fields, and the person reads them in the preview before confirming.
- 2. Validate as the caller Each value is read against its schema, and every name is resolved by the owning module as the person. A record they may not open is simply not found.
- 3. Preview The preview shows every value and where it came from - typed by the person, written by the AI, taken from the record or screen the person is on, a default, or made by an earlier step - and flags a value the person edited.
- 4. Confirm The server keeps the plan that was shown, so what runs is what was previewed.
- 5. Execute and record Each step runs the product's normal command, like a click, and is recorded with who confirmed it. A person can take back what a step created or changed, for a limited time, unless somebody changed it since. A step that only runs a check cannot be undone, so the person reads exactly what it will send before confirming.
How to write an MCP server
- Pick the transport stdio for tools on the user's machine; Streamable HTTP with OAuth for a shared service.
- Choose the tools Start from the jobs an agent must do, not from your list of API endpoints. A few well-described tools beat many thin ones, because every description is read by the model on every request.
- Write the schemas Every argument typed and bounded, additionalProperties: false, ids as ids. No argument should take a URL, a path, a host or a secret unless that is the whole point of the tool.
- Describe like documentation Say what the tool does, what it needs, whether it changes anything and which permission it uses.
- Return data, marked as data Keep results small and structured; cut long text and say that it was cut.
- Fail usefully A tool error is a result with isError: true and one sentence the model can act on.
- Make changes safe to retry Give each change an idempotency key made from what the change is - never from a clock or a random number.
- Test without a model Drive the server with the MCP Inspector, or pipe JSON lines into it and read the lines that come back.
- Official SDK TypeScript, Python, C#, Java, Go and more.; Least code; Follows protocol changes; HTTP transport and OAuth included; A dependency to vet and keep updated; Less control over exactly what is written
- Hand-written JSON-RPC A small loop that reads lines and answers them.; No new dependency in a tool customers install; Full control of every byte on standard output; Full control over which protocol revisions you answer, and how; Every protocol change is yours to follow; More tests to write
- A higher-level framework For example FastMCP in Python: decorators turn functions into tools.; Fastest start; One more layer between you and the protocol
Security: when the text an agent reads is hostile
An MCP server hands somebody else's model text that people and systems wrote - card titles, step names, the answers of an API under test. Any of it can carry prompt injection. Defending an agent means listing what can go wrong and putting a limit outside the model against each threat.
Bound what an obeying agent could do You cannot make hostile text safe to obey, so assume the agent will obey it one day. Then ask: with these tools and this token, what is the worst it could do? If the answer is too much, remove a tool, narrow a scope or add a confirmation.
Connect an agent to an MCP server, step by step
- Install the server's command Put the server's program on the PATH of the machine where the agent runs.
- Make a narrow credential Create a token with the fewest scopes the task needs - reading only, to start - and an expiry.
- Keep the secret out of files Put the token in the host's secret store or in the environment it starts servers with - never among the arguments, and never in a file you commit.
- Add the server entry In the host's settings, add the server: a name, the command, its arguments and its environment.
- Check the connection Reload the host and look at the server's status and its list of tools.
- Ask a read-only question first For example: which suites failed today? Read the tool calls the host shows you.
- Widen on purpose Allow writes, or name hosts for runs, only when a task needs them - and narrow again afterwards.
Hosts change their settings files The file names and keys above are how these hosts work as this lesson is written. Check the host's own documentation when an entry does not load - the shape of command, args and env stays the same everywhere.
Try it yourself: build and connect a tiny MCP server
- Make a project Create a folder, run npm init, mark the package as an ES module and install the SDK and zod.
- Write the server Copy the minimal SDK server above into server.js - it is plain JavaScript.
- Talk to it by hand Pipe an initialize line, the initialized notification, a tools/list line and a tools/call line into it, and read the lines it answers. You should see the weather tool listed and a forecast for Baku.
- Inspect it Start the MCP Inspector: it lists the tools and lets you call them from a web page.
- Connect a host Add the server to your agent host, ask about the weather in Baku and watch the tool call appear.
- Break it on purpose Add a console.log at start-up and run the host again: it shows a parse error or marks the server as failed - then change it to console.error.
On Windows PowerShell The printf one-liner needs a POSIX shell. In PowerShell, run the commands in Git Bash or WSL, or put the four JSON lines in a file and pipe it in with Get-Content messages.jsonl | node server.js. The inspector command works in any shell.
Common mistakes
- Printing to standard output in a stdio server: one log line breaks the protocol. Send everything meant for people to standard error.
- A full-power token for the agent: give it only the scopes the task needs, with an expiry, and one token per agent.
- Trusting what tools return: a card title or an API answer is data. Never let it widen what the agent may do.
- Tools that take a URL, a path or a command: they turn one injected sentence into a request anywhere. Take ids and named choices instead.
- Changes without an idempotency key: timeouts and loops retry, and every retry makes a duplicate.
- No budget and no confirmation: an agent without a step limit and without a human check on irreversible changes will one day surprise you.
Interview questions
- What is an AI agent, and how is it different from a chatbot? An agent is a model with tools in a loop: it chooses a tool, reads the result and decides the next step until the goal is met. A chatbot answers one message; a workflow follows steps a programmer fixed; an agent picks its own steps.
- How does tool calling work? The application sends the model a list of tools with JSON schemas. The model answers with a tool name and arguments instead of text, the application runs the tool and sends the result back, and the loop continues. The model never executes anything itself.
- What problem does MCP solve? Without a standard, M AI applications need M times N connectors for N tools. With MCP each application implements a client once and each tool a server once, so any host can use any server - the same idea as the Language Server Protocol.
- Explain host, client and server, and what a server offers. The host is the AI application the person uses and owns the model. It creates one client per configured server, and each client keeps one connection to a server. A server offers tools (functions the model decides to call), resources (data the application attaches as context) and prompts (templates the person picks).
- What happens in the initialize handshake? The client sends its newest protocol version, its capabilities and its name; the server answers with the version it will speak, its capabilities and optional instructions. The client then sends notifications/initialized, and neither side uses a feature the other did not declare. The 2026-07-28 revision removes the handshake and puts version and capabilities on every request.
- When do you choose stdio and when Streamable HTTP? stdio when the server runs on the user's machine: the host starts it, and secrets stay in that machine's environment. Streamable HTTP with OAuth when the server is a shared or remote service used by many people or cloud agents.
- How do you report a failure from a tool? A failure the model should see - a missing record, a missing permission - is a normal result with isError: true and a clear sentence. A broken request, an unknown method or an unknown tool is a JSON-RPC error that the host handles.
- How do you defend an agent against prompt injection? You cannot make hostile text safe, so you limit the damage. Give the agent a least-privilege token, make reads the default, let a person allow-list hosts, mark tool output as data, add budgets and idempotency, and require confirmation for changes. Then ask: if it obeys one hostile sentence, what is the worst outcome?
- What is the lethal trifecta and how do you avoid it? An agent that reads private data, reads untrusted text and can send data out can be tricked into leaking. You cannot filter injection reliably, so remove or tightly bound one leg: for example no tool that takes an address, or no access to private data.
- ReAct or plan-and-execute? ReAct decides one step at a time and suits exploring, such as debugging. Plan-and-execute writes the steps first and suits known tools, re-planning when a step fails. When a mistake costs, a typed plan that a person reviews is safer than either.
Related
- /help/technology/ai-safety
- /help/technology/ai-models
- /help/technology/access