# MCP

URL: /code/mcp · Id: `page:code/mcp`

> How an agent works through one MCP server.

The [api.sb](/code/platform/api-sb) MCP server connects any MCP client to a [Startup](/business/nouns/startup) through three [Tools](/business/nouns/tool). The agent finds what it needs, reads the types, and acts by writing a short TypeScript program against `$`.

## Connect
```bash
claude mcp add --transport http startup-builder https://api.sb/mcp
```

Any client that speaks streamable HTTP connects to `https://api.sb/mcp`. The first call opens a browser sign-in for a person, or takes a key for an agent that runs alone. The token carries the caller's namespace and scopes, and the server enforces both on every tool.

To read these docs instead of acting on a Startup, an agent connects to the docs MCP server at `https://startupbuilder.dev/mcp`, which needs no key. [Docs for agents](/start/docs-for-agents) covers it.

## Search, fetch, do
A Startup has hundreds of operations, and a tool list that long fills an [Agent](/business/nouns/agent)'s context before work starts. So the server exposes only these and lets the agent write code instead. Models write TypeScript well, and one program chains reads, branches, and writes that would otherwise take a dozen tool calls.

No operation is lost. `do` runs the same `$` client as the [SDK](/code/sdk), so the [Verb](/business/nouns/verb) `Offer.publish` is `$.Offer.publish` here too, with the same input and result.

`kilnlist.com` is a directory of pottery studios that runs with no humans. Its sales agent decides to sell studios a featured listing, and starts by finding the operations it needs:

```json
{ "name": "search", "arguments": { "query": "create and publish an offer" } }
```

`search` returns ids for records, [Nouns](/business/nouns/noun), Verbs, and docs. `fetch` reads any one of them. Fetching `/$.d.ts` returns the types of `$`, cut to the caller's [Role](/business/nouns/role): the complete manual of what this agent may do.

```json
{ "name": "fetch", "arguments": { "id": "/$.d.ts" } }
```

`do` runs a program and returns whatever it returns. The agent writes it in TypeScript against `$`:

```ts
const offer = await $.Offer.create({
  price: { amount: 19, currency: 'USD' },
  interval: 'month',
  terms: 'Top of your city page and a badge on your listing.',
})
await $.Offer.publish({ offer: offer.$id })
return offer
```

It rehearses first, sending the program as `code` with `mode` set to `try`:

```json
{ "name": "do", "arguments": { "code": "<the program above>", "mode": "try" } }
```

The preview returns the [Offer](/business/nouns/offer) it would create and stores nothing. The agent reads it, then runs the same program without `mode`.

## One program, one Action
Each `do` run is one [Action](/business/nouns/action), with one status and one record of who ran it, for whom. Every call inside still checks its own [Permission](/business/nouns/permission) and [Limit](/business/nouns/limit).

`do` returns the program's value with the Action and a line for every call:

```json
{
  "result": {
    "$id": "https://api.sb/kilnlist.com/offers/offer_7",
    "$type": "Offer",
    "price": { "amount": 19, "currency": "USD" },
    "interval": "month",
    "terms": "Top of your city page and a badge on your listing."
  },
  "action": { "$id": "https://api.sb/kilnlist.com/actions/action_41", "status": "done" },
  "calls": [
    { "operation": "Offer.create", "status": "done" },
    { "operation": "Offer.publish", "status": "done" }
  ],
  "logs": []
}
```

A call over a Limit never throws: it resolves to `pending` with its [Approval](/business/nouns/approval), and the program continues. At $79 a month, over the agent's [Mandate](/business/nouns/mandate), `Offer.publish` would have come back `pending` with an Approval. Two-way writes commit when the program returns, and a thrown error cancels every uncommitted write.

One-way sends enter their delay windows when the program ends, so a program never sends half a plan.

`mode` sets the [Mode](/business/nouns/mode) for every call in the program. With `try`, the whole program is a preview, so an agent tests a plan before committing it. Without it, each Verb runs in its own default.

Each tool carries its MCP annotations. `search` and `fetch` are read-only, so a client approves them without asking. `do` is destructive, and idempotent only with `mode: "try"`.

## Bounded by its Role
The agent sees only what its Role allows. The types it fetched omit every Verb outside its Permissions, so it cannot write a call the server would refuse.

A Mandate sets how far it may go. The sales agent publishes Offers up to $50 a month; a higher price waits for an Approval.

A refused call returns the problem document with `fix` and `next`. The agent reads both inside the same program and recovers without a person.

## Read in Markdown
Every page on this site has a Markdown twin, and `/llms.txt` indexes them. Every Verb's page opens on the sentence a founder says for it, and its Markdown twin lists every input, output and refusal in plain text. An agent learns the platform from the same source a developer does, in fewer tokens.

To seat any MCP client in a Role, [bring your own agent](/agents/bring-your-own-agent).