# Designing an MCP Server for AI Agents

> How we went about designing an MCP server for AI agents in Summer MCP and CLI 4.0. One catalog, plain names, dry runs, retry keys and a 168-run eval.

- URL: https://www.summerengine.com/blog/designing-an-mcp-server-for-ai-agents
- Published: 2026-10-16T00:00:00.000Z
- Author: Summer Team
- Tags: MCP, CLI, AI Agents, Engineering, Summer Engine

Summer MCP and CLI 4.0 are out (npm `summer-engine` 4.2.0). Summer Engine is a game engine that AI agents drive, with a store, Summer Games, where the games go live. Every part of it is now one typed operation that your agent finds in plain words and checks with a dry run. This post is about designing an MCP server for AI agents: what we chose, why, what a 168-run eval showed, and where it falls short.

The tour of 4.0 is in [Summer 4.0, the game engine for AI agents](/blog/game-engine-for-ai-agents), and the setup lines are in [Summer Engine now comes as an MCP and a CLI](/blog/summer-mcp-and-cli).

## Why did we start over with one API?

Summer 3.x grew one tool at a time. Signed in, the last 3.x build listed 217 tools. Some tools mixed a read with a change. Asked to change a price on 3.x, one agent re-submitted the whole store page in 5 of 6 runs, because that tool happened to take a price too.

So 4.0 starts from one catalog. Each operation is declared once: a permanent name, a summary, one effect (read, write, spend, publish, change what players see, or delete), an input and output schema, and at least one example that a test checks against the input. The hosted MCP, the npm MCP, the CLI and the approval cards in Summer Studio are views of that catalog. A view adds no behavior, so a fix to an operation is a fix everywhere.

The catalog holds 320 operations: 229 run on Summer's servers and 91 on your computer, most of them in the Summer Engine editor. Each lives next to the code that runs it, and all pass one public contract schema. We share the contract, not the code, because the contract changes rarely and the operations change daily. The [operations reference](https://docs.summerengine.com/mcp/operations) is generated from the same catalog.

## How did we choose the names?

We asked the models first. Two fresh model runs got four tasks, such as a weekend sale, with only a one-line description of Summer, and were asked how they would most want to reach it.

Both asked for an MCP server with typed tools, plus a CLI that mirrors it. One wrote names like `games.list`, `analytics.summary`, `store.publish` and `jobs.wait`; the other wrote `store_publish`. Both asked for dry runs, retry keys, job ids, structured errors, scoped permissions and an audit log.

So every name is `area.action`; only `whoami` stands alone. The area is a word a person uses, such as `pricing`, and the action is usually a verb. A read and a change are never one operation. A name is permanent, so a new meaning gets a new name.

On MCP, `store.get_listing` is the tool `summer_store_get_listing`, because some clients reject dots in tool names. In a terminal it is `summer store get-listing`. Two exceptions: engine tools kept their 3.x names, such as `summer_add_node`, and makers kept `summer_tool_<name>`. 78% of the 3,141 tool mentions in our skills library name engine and file tools, so a rename would churn most skills for no gain.

## Why search and call instead of 320 tools?

The hosted MCP lists 20 tools: 18 everyday operations, plus `summer_search` and `summer_call`. `summer_search` takes the job in plain words and returns the matching operations with their exact input schema, so the next call needs no second lookup. `summer_call` runs any operation by name, with the same input checks, dry runs and approvals as its own tool. Its MCP hints state the worst case, so clients ask before it runs.

Input tokens on the first model call, measured once per client (with no Summer server, about 2,700, or 13,161 in Codex CLI):

| Client | 3.x | 4.0 | Change |
| --- | --- | --- | --- |
| npm server, client loads every tool | 147,366 | 64,747 | 56% less |
| Hosted server, client loads every tool | 43,062 | 12,915 | 70% less |
| npm server, Claude Code | 7,501 | 5,938 | 21% less |
| npm server, Codex CLI | 13,161 | 13,161 | none |

Claude Code and Codex already defer MCP tools, so they gain little or nothing. The 4.0 npm list still has 106 tools, because most of them are engine tools. Against 3.x with short descriptions and the engine toolset picked by hand, 4.0 saved 8%, and a hand-picked cloud-only 3.x toolset was smaller than 4.0. The gain over tuned 3.x is never picking toolsets by hand.

This only works if search is good, and in 4.0.0 it was not. "Publish my game" missed `store.publish`. Agents in our eval searched with keywords, so they still found the right operation 50 of 55 times, but people type sentences. A test holds 35 real phrases, such as "lower my price", and all pass. It is live on the hosted server and in 4.2.0.

## What does every answer look like?

Every operation answers one shape, on every surface:

```json
{ "ok": true, "status": "done", "result": { "items": [] } }
{ "ok": true, "status": "running", "job": { "id": "gen:<id>", "state": "running" } }
{ "ok": true, "status": "needs_approval",
  "approval": { "id": "apr_<id>", "url": "https://www.summerengine.com/studio/approvals/apr_<id>" },
  "job": { "id": "apr:<id>", "state": "awaiting_approval" } }
{ "ok": false, "error": { "code": "no_credits", "message": "Not enough credits for this call.",
  "next": { "url": "https://www.summerengine.com/studio/credits", "label": "Add credits" }, "retry": "no" } }
```

- **Waiting for a person is a status, not an error.** `needs_approval` tells the agent to hand you a link and wait, not to retry.
- **Slow cloud work never blocks.** Anything that can take more than about 20 seconds answers `running` with a job id, and `jobs.wait` waits up to 50 seconds at a time. An engine export still blocks, by default up to 15 minutes.
- **Errors come from a closed list of 18 codes.** Each has a plain message, at most one `next` step (an operation, a link, or a sentence to tell you) and a `retry` hint: `no`, `safe`, `same_key`, or `after` a wait. One step, not a list, so the agent does not have to choose. `invalid_input` names the failed field in `details.path`.

A last fix before 4.0.0 split the cloud failure that always said "sign in" into `not_signed_in`, `forbidden`, `unavailable` and `outcome_unknown`. The last means a change may have run: retry only with the same key, or check first. [How Summer answers](https://docs.summerengine.com/api-reference/mcp) lists every code.

## How do dry runs and retry keys work?

Every operation that changes something takes `dryRun: true`. Summer checks the call and describes it, and nothing changes, is spent or is sent. The preview gives the approval a call needs, the estimated credits for generation, and before and after for publishing, live changes and deletes. The types enforce it: a spend operation cannot be defined without a cost estimate, and one that publishes, changes what players see or deletes cannot be defined without a preview.

Every change on Summer's servers also takes an `idempotencyKey`. The same key with the same input within 24 hours returns the first answer, marked `replayed`, and never does the work twice. The same key with different input is an `idempotency_conflict`. Publishing, releasing and the five price and sale changes require a key. Generation keeps it optional, because "the same prompt again" is often what you want. Engine edits on your computer have no retry key.

## What may an agent do without asking?

Both blind-test runs asked for scoped permissions. Most operations that change something belong to one of six switches in Summer Studio under **Settings > Agent permissions**:

| Switch | Default | Operations |
| --- | --- | --- |
| Make and build | On | 120 |
| Spend credits | On | 51 |
| Publish | On, but Summer Games still asks the owner today | 8 |
| Prices and live changes | On, but Summer Games still asks you today | 9 |
| Delete for good | Off, asks you | 18 |
| Contact people | Off, asks you | 5 |

The 104 reads never ask. Five operations always ask, such as auto top-up settings, and an agent can never turn a switch on by itself. The defaults trust the agent, and the approval card is the fallback.

When something asks, the answer is `needs_approval` with a link, and an open Studio tab shows a card too. The request is bound to its exact input. If the value changed since the agent asked, it ends `stale` instead of overwriting. **Agent activity** lists what your agents did, with Undo for prices, sales, member roles, team names and the analytics event limit.

What is live today: the switches show their defaults, and changing them is not available yet. Summer Games runs its own check on agent changes, and that check does not yet follow saved permissions. Until it does, an agent's publish always asks the game's owner, and price, A/B test and member changes always ask you. The [agent permissions guide](https://docs.summerengine.com/mcp/permissions) has the details.

The approval lives on Summer's side, not in the prompt or the client, and `summer_call` passes the same checks as a direct tool. For terminal agents, `npx -y summer-engine@latest setup claude-code --cli --allow-rules --yes` adds allow rules for read commands and for dry runs of spend commands. Everything else still asks.

## How did we test 4.0 against 3.x?

Right after 4.0.0 shipped, we ran 168 agent sessions: two clients (Claude Code and Codex CLI), four setups, seven tasks, three runs each. The setups were 3.x in full, 3.x tuned with short descriptions and toolsets picked per task, 4.0, and 4.0 with the old names too. The tasks were real asks, from "How did my game do this week?" (the numbers in [Grow](/blog/grow-your-game-in-summer-studio)) to a price change, a publish and fixing an error on play. The npm server was real; the hosted server was a stand-in with the real catalog and search. Account and engine answers were fixtures with the real shapes.

- **Success was the same.** 4.0 passed 21 of 21 in both clients. So did tuned 3.x.
- **No false claims.** In all 168 runs, no agent said a change was live while it waited for approval. On 4.0, price, invite and publish gave the approval link 18 of 18 times.
- **The right operation.** On 4.0, every price change used `pricing.set_base` and every invite made an approval card. Our 3.x setup could not invite.
- **More first-try mistakes.** 4.0 had 4 bad calls where tuned 3.x had none, such as `name` instead of `op` and a `limit` over the maximum. Each was fixed on the next call, and 4.2.0 also accepts `name`.
- **Upgrades hid the gain.** While installed skills were older than 4.0, the old names stayed listed. That gave back about half the token saving, and Claude Code picked the old tools. 4.2.0 refreshes the skills on first start.

Three of our five pass rules held. The 50% token rule held only for clients that load every tool, and "no more bad calls than tuned 3.x" failed narrowly. The tasks were too easy to tell setups apart on success, three runs per cell is a small sample, and no editor client such as Cursor ran; the "loads every tool" rows count what such a client would load.

## What did we learn designing an MCP server for AI agents?

- **Ask a model with little context first.** It named the operations the way agents look for them.
- **Test search with the sentences people type,** not keywords.
- **Ship the switch with the gate.** We showed the switches before Summer Games could follow them.

## What comes next?

- A harder eval with real accounts and a running engine.
- An HTTP API and a typed SDK from the same catalog, for agents that script hundreds of calls. Specified, not built.
- A tool list that follows use: once there is enough 4.0 data, the 18 direct operations are re-picked each month by how many people call each one. Telemetry records the operation name, never its arguments or results.

To try it, follow the [MCP setup guide](https://docs.summerengine.com/mcp/setup).

Tell your agent "Install Summer Engine and let's make a game."

---

## Machine-readable resources

- Site index for agents: https://www.summerengine.com/llms.txt
- Full inlined content: https://www.summerengine.com/llms-full.txt
- Porting catalog: https://www.summerengine.com/llms-porting.txt
- Structured catalog: https://www.summerengine.com/agent-catalog.json
- Sitemap: https://www.summerengine.com/sitemap.xml
- Developer resources: https://www.summerengine.com/docs