Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

MCP & agent ergonomics: token-efficiency and missing affordances

FieldValue
Date finalised2026-06-05
AuthorRômulo Febasi romulo@febasi.com.br (Claude-assisted)
ScopeHow to make Synapse’s MCP surface cheaper and easier for Claude (and other agents) to drive: token savings, missing tools/affordances, plugin/skill packaging. Grounded in the v0.5 code.
Statusdraft
InputsCode audit of src/mcp/ + src/core/mcp/; Anthropic “Writing effective tools for AI agents”, “Code execution with MCP”, “Advanced tool use”; MCP 2026 spec (structuredContent/outputSchema, resources, pagination); the v0.5 SKILL.md/LLM.md work.
Out of scopeThe semantic layer internals (ADR-008); the identity onboarding (SYN-170..173); anything requiring a protocol change to rmcp.

Executive summary

Synapse’s MCP surface is correct and safe (propose/accept is solid) but not yet optimised for token cost or agent ergonomics. Three cheap fixes pay off immediately: bound the one unbounded read (list_by_type), return structuredContent + compact JSON instead of pretty-printed text, and attach ResourceLinks to reads (entities are already exposed as resources, but tools don’t link to them). Beyond that, a small set of new affordances (a batch read, a workspace-overview digest, a recent_changes delta tool, and batch proposals) would cut the round-trips and exploratory reads that dominate an agent’s token budget. The strategic bet is the Anthropic code-execution-with-MCP pattern (intermediate data never enters context) and shipping Synapse as a one-install Claude plugin (skill + MCP + hooks).

1. Context and premisses

v0.5 ships 15 MCP tools (4 local read, 4 federation read, reindex, replay_proposal, 5 write proposals). Responses are built by mcp::helpers::json_content → serde_json::to_string_pretty wrapped as a text content block. Entities, the manifest, the server-card and recent audit are exposed as resources (synapse://entity/{type}/{id}, paginated). The propose/accept invariant (BR-12.3) is enforced in core::pending::enqueue. The freshness banner is conditional (only when a noteworthy signal exists): already well-behaved.

Assumed: agents are the primary consumer of the MCP door, and their token budget is the scarce resource. The SKILL.md/LLM.md (v0.5, in synapse-releases) already teach correct usage; this brief is about making the server cheaper, not just the docs.

2. Market scan

2.1 Anthropic: writing effective tools for agents

Core principles: avoid tool overload / overlapping tools; namespace related tools; implement response constraints (pagination, range, filtering, truncation with sane defaults) for anything that could flood context; tool descriptions are load-bearing and should be prompt-engineered.

What this means for Synapse: list_by_type violates the response-constraint principle: it takes only type + status, no limit/cursor (src/mcp/args.rs ListArgs), so a big workspace returns everything. search_knowledge and federated_search already cap with limit; list_by_type is the outlier. Fix first.

Tools may return structuredContent (machine-readable JSON conforming to an outputSchema) alongside text; clients parse it programmatically instead of the model re-reading a text blob. Results may carry ResourceLink/EmbeddedResource blocks pointing at resources the client can fetch (and cache) lazily.

What this means for Synapse: today every tool returns pretty-printed JSON as text (json_content). Two wins: (a) emit structuredContent + a tool outputSchema, and drop the pretty-print (whitespace is pure token waste); (b) since entities are already resources, have search_knowledge hits and get_entity return a ResourceLink to synapse://entity/{type}/{id} so a resource-caching client can avoid re-fetching, and the agent can defer reading the body until it’s sure it needs it.

2.3 Anthropic: code execution with MCP (the 98% pattern)

Presenting MCP servers as a code API the agent writes against: loading only the tools it needs and keeping intermediate results in the execution environment: cut token usage by up to 98% in Anthropic’s tests. The “Tool Search Tool” discovers tools on demand (~85% reduction) so the full tool catalogue isn’t loaded upfront.

What this means for Synapse: the CLI analog already exists and is the right shape: syn export --as json | jq '…' filters/aggregates outside the model’s context. The MCP door has no equivalent: an agent must pull data into context to filter it. A constrained, read-only query tool (a safe expression over the workspace JSON, or a thin jq-like projection) would let agents compute answers without the rows entering context. This is the highest-leverage bet.

3. Cross-check vs the current server

AffordanceStatus todayGap
Bounded readssearch/federated cap; list_by_type does notAdd limit + cursor
Machine-readable resultsJSON as pretty text, no outputSchemastructuredContent + compact JSON
Lazy/cacheable readsentities are resources, but tools don’t link themResourceLink on hits + get_entity
Batch readsone get_entity per callget_entities / resource multi-read
Field projectionget_entity returns the whole markdownoptional fields projection
Orientationnone (agent must list+search to learn the shape)workspace_overview digest
Deltasnone (re-reads everything each session)recent_changes {since}
Batch writesone proposal per callpropose_batch → one accept
Pre-validationupdate_status validates at accept timevalid_statuses/dry-run to cut rejects
Compute-out-of-contextCLI has `exportjq`; MCP has nothing

4. Positioning

The moat is local-first + auditable propose/accept. No SaaS competitor can match “the model proposes, the human signs off, every write is provenance-stamped and replayable” while keeping data on the laptop. Token-efficiency and agent ergonomics are table stakes that make the moat usable; they are not the moat. Lane to occupy: “the second brain agents drive cheaply and can’t silently corrupt.”

5. Recommendation

#BlockJustificationCostDefensible?
1Bound list_by_type (limit+cursor)Closes the one unbounded read; Anthropic principle #1SHygiene
2structuredContent + compact JSONToken + parse win on every read; spec-alignedMHygiene
3ResourceLink on readsLazy/cacheable reads; entities already are resourcesSLeverages existing resources
4workspace_overview digest toolKills the explore-cost; one call to orientMProduct
5recent_changes {since} deltaRecurring agents pull deltas, not the worldMProduct (audit/timeline exist)
6get_entities batch + fields projectionFewer round-trips; read only needed fieldsMHygiene
7propose_batch (one bundle, one accept)Fewer round-trips; one human sign-offMFits propose/accept
8read-only query tool (compute-out-of-context)The 98% pattern; biggest token leverLMoat-adjacent

Non-goals for now: protocol-level changes; a full code-execution sandbox; dropping any existing tool.

6. Disruptive bets

  1. Compute-out-of-context query: a safe, read-only projection/aggregation over the workspace (jq-subset or a whitelisted expression) so an agent answers “how many blocked tasks per owner” without a single row entering its context. The local-first design makes this safe (no remote data exfil) in a way a SaaS MCP cannot casually offer.
  2. Synapse as a one-install Claude plugin: .claude-plugin/plugin.json bundling the skill + the MCP server config + hooks (e.g., a SessionStart hook that runs syn doctor/syn pending list). One cp/marketplace install wires the whole loop. Agents that don’t speak MCP still get the skill.
  3. Proposal “context snapshot” as a first-class agent contract: every write tool already accepts context; lean into it so syn audit replay can re-run a proposal against a newer model and flag drift. This is an auditability feature no hosted assistant offers: sell it.
  4. recent_changes as the agent’s memory diff: a recurring agent (daily standup, weekly review) reads only what changed since its last run; pair with a server-issued cursor so the agent is stateless.

7. Ticket sketch (provisional IDs)

Sketch IDBlockSize
SYN-176list_by_type limit + cursorS
SYN-177structuredContent + outputSchema + compact JSON on all readsM
SYN-178ResourceLink to synapse://entity/... on search hits + get_entityS
SYN-179workspace_overview digest tool (counts + key/recent)M
SYN-180recent_changes {since} delta tool (over audit/timeline)M
SYN-181get_entities batch + optional fields projectionM
SYN-182propose_batch (one pending bundle, one accept)M
SYN-183read-only query tool (compute-out-of-context): spike firstL
SYN-184Synapse Claude plugin package (skill + MCP + hooks)M

8. Risk register

RiskSeverityMitigation
structuredContent not supported by all clientsLowKeep the text block too (dual emit); spec says clients ignore unknown fields
query tool = injection / DoS surfaceHighRead-only, whitelisted ops, row/time caps; spike (SYN-183) before commit
Tool sprawl (15 → 20+) dilutes the catalogueMedNamespace (synapse_*); lean on the skill + Tool Search; retire overlaps
Batch tools complicate the audit trailMedOne pending row per logical write even under propose_batch; bundle only the accept UX

9. Open decisions

  1. Adopt structuredContent now, or wait until the dominant client (Claude Code) renders it? (Recommend: dual-emit now: cost is low.)
  2. Is the query tool worth the security surface, or is syn export --as json | jq (CLI) enough and we just teach agents to shell out? (Spike SYN-183 to decide.)
  3. Namespace the tools (synapse_*) now (breaking for existing configs) or at v1.0 with the frozen MCP surface?
  4. Should workspace_overview and recent_changes be tools or resources (or both)? Resources are cacheable; tools are discoverable.

10. References