InterviewKata
AI engineering · Module 16 of 21 · Level 4: Build AI features

Building agents and MCP servers

In Module 07 you watched the agent loop from the outside. Now you write it: about twenty lines of code, a few well-described tools, and the limits that keep it safe. Then you turn your own system into an MCP server, so every agent from Module 10 can use it.

1. The idea

An agent is a capable new assistant on a short leash. They have a brain (the model), hands (the tools you hand them), a way of working (loop: look, act, check, repeat until done), and a leash: a budget, a list of what they may touch, and someone to ask before anything risky.

In code, those four parts are:

  1. Brain: a model API call with a clear system prompt (Modules 05 and 14).
  2. Hands: tools, each a name, a description and an input schema, backed by your function (Module 06).
  3. Loop: call the model; if it asks for tools, run them and send the results back; repeat until it answers.
  4. Leash: a maximum number of turns, a token or cost budget, read-only tools by default, approval for risky actions, and logs of every step.

Start with the simplest thing that works. Anthropic's advice in Building effective agents is to use a single call or a fixed workflow when the steps are predictable, and a full agent only when they aren't.

2. How it works

The loop you write. The model decides; your code executes and enforces the limits.

Here is the whole loop with the Claude API. The other providers' versions have the same shape.

import anthropic

client = anthropic.Anthropic()                       # reads ANTHROPIC_API_KEY

def run_agent(task, max_turns=10):
    messages = [{"role": "user", "content": task}]
    for turn in range(max_turns):                    # leash: turn budget
        reply = client.messages.create(
            model="claude-sonnet-5-5", max_tokens=2048,
            system=SYSTEM_PROMPT, tools=TOOLS, messages=messages,
        )
        messages.append({"role": "assistant", "content": reply.content})
        if reply.stop_reason != "tool_use":          # no tool requested: done
            return next(b.text for b in reply.content if b.type == "text")
        results = []
        for block in reply.content:
            if block.type == "tool_use":
                output = run_tool(block.name, block.input)   # your code, your checks
                results.append({"type": "tool_result", "tool_use_id": block.id,
                                "content": output})
        messages.append({"role": "user", "content": results})
    raise RuntimeError("Turn budget exhausted")      # stop, don't loop forever

3. Try it yourself

The leash: turn budgets

A task needs a certain number of tool calls. Some runs go wrong and repeat themselves. See what the budget does.

10

Write an MCP server tool

Fill in one tool and get a working MCP server in Python (official SDK, v2). Any MCP client, including all five coding tools from Module 10, can then call it.

4. Why it matters at work

  1. Design tools for the model, not for your API. Fewer, task-shaped tools ("get_order_status") beat thin wrappers over every endpoint. Clear names, descriptions with examples, and short, useful outputs.
  2. Return errors the model can act on. "Order A-1042 not found; order numbers look like A-1234" lets it recover. A stack trace doesn't.
  3. Read-only first. Add tools that change things only when needed, and put approval in front of anything irreversible (sending, paying, deleting).
  4. Treat tool output as untrusted. A web page or ticket can contain instructions aimed at your agent (prompt injection, Module 18). Your code, not the prompt, enforces permissions.
  5. Log every turn: the model's request, the tool input and output, tokens and time. You'll need it to debug and to evaluate (Modules 17 and 19).
  6. Use an SDK once the basics are clear. SDKs give you the loop plus context management, sessions, subagents, tracing and permission handling.
MCP server or plain tools?If only your own app's agent uses a tool, a plain function is enough. Make it an MCP server when several agents or tools should share it: your coding assistant, a colleague's, and your own product.

5. Agent SDKs and protocols

Checked against vendor documentation, October 2026.

SDKInstallWhat it gives you
Claude Agent SDKpip install claude-agent-sdkThe same agent harness as Claude Code: built-in file and shell tools, hooks, subagents, MCP, permissions, sessions, skills
OpenAI Agents SDKpip install openai-agentsAgents, handoffs between agents, guardrails, sessions, tracing
Agent Development Kit (ADK)see docsGoogle's open-source framework for agents and multi-agent systems; model-agnostic
Antigravity SDKpip install google-antigravityThe Antigravity agent runtime in Python: custom tools, MCP, policies and approvals, subagents
MCP SDKsuv add "mcp[cli]"Build MCP servers (and clients) in Python, TypeScript and other languages

MCP and A2A: tools vs teammates

MCP connects an agent to tools and data. A2A (Agent2Agent, a Linux Foundation project, v1.0 in March 2026) lets agents from different vendors find each other and hand off tasks.

6. Remember it

Memory hook: "Brain, hands, loop, leash"Every agent is a model that thinks, tools that act, a loop that repeats, and limits that keep it safe. Leave out the leash and it isn't ready to ship.
How this hook works: what “Brain, hands, loop, leash” means

What the slogan means, word by word

“Brain”
The model and its system prompt. It decides what to do next, but can't do anything by itself.
“hands”
The tools: name, description, schema, and your function behind them. They are the only way the agent affects the world.
“loop”
Call, run requested tools, return results, repeat, until the model answers without asking for a tool.
“leash”
Turn and cost budgets, least-privilege tools, approval for risky actions, and logs. Enforced in your code.

Why this picture fits: the four words are also the four places to look when an agent misbehaves: a bad decision (brain), a confusing tool (hands), a run that never ends (loop), or an action it shouldn't have taken (leash).

The story → the concept

The assistantThe agent
Their judgementThe model + system prompt
The keys and logins you give themTools (and MCP servers)
Working until the job is doneThe while-tool-use loop
"Ask me before spending over £100"Approval for risky tools
"Stop by 5pm either way"max_turns, token budget
Their notebook of what they didLogs and traces
Calling another firm's assistantA2A

Watch it on an example

  1. Brain: "Where is order A-1042?" → the model decides it needs the order status.
  2. Hands: it calls get_order_status(order_id="A-1042"); your function queries the database read-only.
  3. Loop: the result goes back; the model answers "Out for delivery, arriving today."
  4. Leash: when a customer asks for a refund, the issue_refund tool waits for a human to approve.

The trap it saves you from

Shipping the brain, hands and loop without the leash: an agent that loops forever, spends without limit, or acts on instructions hidden in a web page.

It still works when…

You use an SDK: it provides the loop, and you still choose the brain, design the hands and set the leash (allowed tools, permission mode, budgets).

7. Common mistakes

No turn or cost limitA confused agent can call tools forever. Always cap turns and tokens, and stop with a clear error.
Permissions in the prompt"Never delete records" in the system prompt is a request, not a control. Don't give the agent a delete tool, or check in code.
Too many thin toolsFifty endpoint wrappers confuse the model and fill its context. Offer a few tools shaped around tasks.
Printing to stdout in a stdio MCP serverstdout carries the protocol messages; a stray print corrupts them. Log to stderr.
An agent where a workflow would doIf the steps are always the same, a fixed sequence of calls is cheaper, faster and easier to test.

8. Hands-on lab (roadmap week 18)

  1. Write the loop yourself with two read-only tools (for example: search notes, read a note). Cap it at 8 turns and log every step.
  2. Break it on purpose: a tool that errors, a vague tool description, a task that can't be done. Watch how the agent reacts and improve the tool messages.
  3. Rebuild it with an SDK (Claude Agent SDK or OpenAI Agents SDK) and compare: what did the SDK add for free?
  4. Build an MCP server exposing one tool from your own system, test it with the MCP Inspector, then connect it to your coding tool.
  5. Add the leash: one tool that changes something, gated by an approval step.

9. Self-check quiz

When does the agent loop finish normally?

With the Claude API, stop_reason is no longer "tool_use"; the model has given its answer.

Where should "the agent may not delete records" be enforced?

Prompts can be ignored or overridden by injected text. Code can't.

Where should a stdio MCP server write its logs?

stdout carries the JSON-RPC messages between client and server.

Your agent needs to hand a task to another company's agent. Which protocol fits?

MCP connects agents to tools and data; A2A connects agents to other agents.

10. Go deeper

ResourceTimeWhy
Building effective agents (Anthropic)30 minWorkflows vs agents, and when to use which.
Writing effective tools for agents (Anthropic)25 minHow to design, test and improve tools.
Build an MCP server (modelcontextprotocol.io)45 minThe official tutorial, in several languages.
Agent SDK overview (Claude) and Agents SDK (OpenAI)1 hThe two SDKs in the code tabs above.
A2A protocol20 minAgent Cards and how agents hand off tasks.