Building agents
Frontend
The browser. HTML, CSS and JavaScript — it draws the page and collects the clicks.
Backend
A program on a server, listening continuously for requests. Yours will be Python.
You open a URL. The browser sends a request. The server sends back HTML, CSS and JavaScript. The browser interprets that and shows you a page.
Right-click any page and choose View Page Source. That is the frontend code, exactly as the backend handed it over.
| What it carries | What the server does | |
|---|---|---|
GET |
a path, and parameters in the URL | sends back a page, or data |
POST |
a body — a form, a ticker you typed | whatever it was written to do, then replies |
Opening a page is a GET. Clicking submit is usually a POST.
The frontend and the backend can be the same computer — your container, or your own laptop with Python on it.
localhost
127.0.0.1 is the loopback address. The browser asks the machine it is already running on, and the request never reaches a network.
Ports
One machine runs many programs listening at once. The port number tells the operating system which of them gets the request.
You write the app as a .py file. FastAPI is the usual Python library for one, and uvicorn starts it listening: uvicorn app:app --host 0.0.0.0 --port 8000.
GET; submitting the form logs a POST.Claude calls a single-page HTML app an artifact.
Get free accounts at Replit and Lovable and build the same app with their tools. Then try something more ambitious (you may run out of credits on the free tier).
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY
SYSTEM = "Classify the complaint: damage, delay, billing, or other. One word."
resp = client.messages.create(
model="claude-sonnet-5",
max_tokens=500,
system=SYSTEM,
messages=[{"role": "user", "content": "The unit arrived cracked."}],
)
print(resp.content[0].text)from openai import OpenAI
client = OpenAI( # reads OPENAI_API_KEY
base_url="https://openrouter.ai/api/v1",
)
resp = client.chat.completions.create(
model="nvidia/nemotron-3.5-lightning:free",
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": "The unit arrived cracked."},
],
)
print(resp.choices[0].message.content)The system prompt is a message here, not a separate argument. A different library, a different response shape, and the model is a string you can change. Fifty free requests a day.
Anthropic
Both carry the word damage. The envelope differs, which is why one prints resp.content[0].text and the other resp.choices[0].message.content. stop_reason and finish_reason are how the app knows whether the model finished or wants to use a tool.
Anthropic
platform.claude.com → API keys → Create key. Pay per token, so set a spending limit on it.
Store it as ANTHROPIC_API_KEY.
OpenRouter
openrouter.ai → Keys → Create key. Sign in with Google or create an account with username and password, no card. One key reaches every provider it carries.
Store it as OPENAI_API_KEY. The OpenAI library looks for that name only.
The keys are only shown once. Copy each into a file called env.txt, one NAME=value per line, and upload it to your container from the Files tab. Then tell Claude: my keys are in env.txt.
We need to tell Claude what provider we want (Anthropic, OpenAI, …), what model we want, and what the system prompt should be. Claude can do everything else.
You can tell Claude to do these things. You are not expected to write the code yourself.
The chatbot
Text in, text out. The app does the same thing with every reply it gets
The agent
The reply can be a request to run something. The app runs it, sends the result back, and asks the model what to do next
An agent is an app that takes actions at the discretion of a model.
Sent in the same request, alongside messages. The description is what the model reads when deciding whether to call it.
Your code runs the query and calls again, with a tool_result block carrying the same id, and the whole conversation behind it.
| Where the code is | Example | |
|---|---|---|
| Built in | in the harness | read a file, run a command, fetch a page |
| Yours | a function you wrote | look up a customer in your system |
| Someone else’s | an MCP server | the Northwind database, EIA, FRED |
All three arrive at the model the same way: a name, a description, and a parameter schema.
Pre-built code for the harness, and a set of tools that come with it. The Claude Agent SDK, the OpenAI Agents SDK, LangChain.
Read Write Edit
Glob Grep Bash
WebSearch WebFetch Task
The built-ins in the Claude Agent SDK. You choose which to include: tools=[] includes none, and naming a few includes only those. If we use the Claude Agent SDK, we get the Claude Code harness.
Tools written by somebody else, running on a server somebody else operates. Thousands of MCP servers exist already.
What you add
A URL, in the agent’s configuration
What arrives
A name, a description and an input schema for every tool the server publishes
What stays there
The code, and the credential it uses to reach the service
To the model these are more entries in the same tool list. What differs is whose machine runs them.
A name, a description and typed arguments — the three parts every tool has — written as a Python function. The SDK turns the decorator into the JSON it sends the model.
fred.kerryback.com/mcp, as its only source of data.MGMT 803 · Rice Business