Blog
MCP9 min read

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.

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, and the setup lines are in Summer Engine now comes as an MCP and a 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 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):

Client3.x4.0Change
npm server, client loads every tool147,36664,74756% less
Hosted server, client loads every tool43,06212,91570% less
npm server, Claude Code7,5015,93821% less
npm server, Codex CLI13,16113,161none

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:

{ "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 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:

SwitchDefaultOperations
Make and buildOn120
Spend creditsOn51
PublishOn, but Summer Games still asks the owner today8
Prices and live changesOn, but Summer Games still asks you today9
Delete for goodOff, asks you18
Contact peopleOff, asks you5

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 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) 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.

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

Frequently asked questions

What is Summer MCP and CLI 4.0?

It is how AI agents use Summer Engine. Every part of Summer is one operation with a plain name such as store.publish or assets.generate_3d. Agents reach the operations through the hosted MCP at https://mcp.summerengine.com/mcp, the local npm MCP, or the summer CLI in a terminal. The current npm release is summer-engine 4.2.0.

Why not list every operation as its own MCP tool?

A client that loads every tool pays for all of them before the agent reads a word. The hosted MCP lists 20 tools for everyday jobs, and summer_search finds any other operation on Summer's servers from plain words and returns its exact input. In our tests this cut the first model call by 70% on the hosted server for clients that load every tool. Clients that already defer tools, such as Claude Code and Codex, gained little.

What do dry runs and idempotency keys do?

A dry run checks a change and describes it, often with before and after and the credits it would use, and changes nothing. An idempotency key makes a retry of a change on Summer's servers safe. The same key with the same input within 24 hours returns the first answer again and never does the work twice. Publishing and price changes require a key.

Can my agent publish or change prices without asking me?

Not today. Agent permissions in Summer Studio show their defaults, and changing them comes soon. Until Summer Games follows saved permissions, an agent's publish asks the game's owner, and price, A/B test and member changes ask you. Your agent gives you an approval link, and nothing changes until you approve.

How did you test Summer 4.0 against 3.x?

We ran 168 agent sessions in Claude Code and Codex CLI, across four setups, seven real tasks and three runs each. 4.0 matched a tuned 3.x setup on success, and no run claimed a change was live while it waited for approval. Account and engine answers were fixtures, so the test did not touch a real account or a running engine.

Do the old 3.x tool names still work?

Yes, for all of 4.x. summer_call accepts any 3.x tool name and runs the operation that replaced it. Engine tools keep their 3.x names. To get the full 3.x tool list back, run the local server with --surface v3.

  • MCP
  • CLI
  • AI Agents
  • Engineering
  • Summer Engine