Skip to content

list_instance_tools documents 2 of the 4 tier values it returns, and its default response is 117 KB — enough to exceed a host's limit on one instance #569

Description

@serge-ivo

list_instance_tools documents 2 of the 4 tier values it returns, and its default response is 117 KB — enough to exceed a host's limit on one instance

Two small, independently-shippable contract defects on the same tool. Both measured against instance bd43f4de-ef35-4051-bdec-43f8571414a1, GET /v1/instances/:id/tools, production 2026-08-15, 104 rows.

1. A third of the rows carry an undocumented tier

The tool's description (workers/mcp/src/instance-tools/base.ts:29) says:

plus tier (base = a universal facility every agent has; connector = reaches an external system)

Measured tier distribution over the 104 rows:

tier rows documented?
connector 49 yes
standard 30 no
base 21 yes
runtime 4 no

34 of 104 rows (32.7%) carry a value the description does not define. A caller filtering on the two documented values silently drops a third of the surface — including every runtime tool, which is the set that reaches the owner's own machine.

The vocabulary is already written down, correctly, one layer below — workers/api/src/lib/builtin-tool-policy.ts:145:

/** base = always granted · standard = creator-selectable · runtime = needs a local runner · connector = external system. */
export type ToolTier = "base" | "standard" | "runtime" | "connector";

and again on ToolDef (lib/connectors/types.ts:129). So this is a description that fell behind its own type, not a missing concept. Paste the type's gloss.

2. The default response is 117 KB / 3,563 lines for one instance

Measured, same call:

chars (pretty-printed) lines
default (all 104 rows) 117,273 3,563
allowed_only: true (35 rows) 37,363
all rows, jsonSchema stripped 60,427

Raw body over HTTP is 89,281 bytes. jsonSchema is 48% of the payload, and it is present on every row including the 69 the instance may not run — a schema for a tool that is allowed: false describes inputs the caller can never send.

This exceeded the calling host's response limit in the session that produced this issue, so the tool's own most useful mode — "return EVERY tool, not just the allowed ones", which the resolver's doc comment (lib/instance-tool-policy.ts:154-156) rightly defends — is the one that does not fit.

What to do

Cheapest, and it fixes both: paste the four-value tier gloss into the description, and drop jsonSchema from rows where allowed === false (60,427 chars, comfortably under any limit, with no loss of auditable information — the verdict, reason, scope, tier, connector and writeConsent all stay).

If more is wanted: add an optional schemas: boolean (default false) so the audit read is cheap and the schema read is opt-in. Do NOT make allowed_only the default — the resolver's stated design is that "what can this agent do" is only answerable if the answer includes what it can't, and defaulting it away would quietly retire that.

Alternatives considered and rejected

  • Truncate the description strings. They are the substance of an audit — github_update_issue's description is where the "labels REPLACE" warning lives.
  • Paginate. A tool listing is a set, and a paged audit is one a caller can stop halfway through and believe.

Acceptance criteria

  • The description defines all four tier values, matching ToolTier's own gloss.
  • A test asserts every value in the ToolTier union appears in the description string — so a fifth tier cannot ship undocumented.
  • The default response for a 104-tool instance is under 64 KB.

Regression risk

Dropping jsonSchema from disallowed rows changes a response shape the console may read. store/console/src/lib/toolPolicy.ts mirrors the type — check it does not render schemas for the not-declared rows before removing the field, and make it optional in the type rather than removing it outright.

Related: #563 (the same description's scope gloss is wrong in a way that matters more), #561/#562 (the tools/list payload budget).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendBackend / Worker / API workbugSomething isn't workingdocumentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions