[FEATURE] Expose the resolved MCP tool catalogue to plugins: add `inputSchema`/`outputSchema` to `$.tool.list()`

Status Open
Reported on v2.1.246
Maintainer reply None cached
Activity 0 comments · opened Aug 27, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Problem Statement

Use case

We build a security product that inventories and governs MCP servers on managed developer
endpoints. For each configured MCP server we need its declared tool surface — names,
descriptions, inputSchema — to inventory what an endpoint can reach, and to validate
tools/call arguments against the schema the server declared.

Scope: we are not asking for anything not already resident in the Claude Code process, and not
asking to read user conversation content.

Why hooks are not sufficient

Hooks fire on tools/call, so we see only the tools someone happened to invoke, by name, with no
schema. A server can expose forty tools and we see the three that were used.

Proposed Solution

Asks, in priority order

  1. Add inputSchema and outputSchema to $.tool.list(). The data is already resident; this

is a field addition, and the one change that unblocks schema validation.

  1. Ship tengu_plugin_hooks_modules — or provide any supported way for a plugin to read the

resolved MCP tool catalogue. The flag is not in the served payload at all, so the seam is
unreachable, not merely disabled.

  1. Lift or make configurable the 300-char description truncation, or return the untruncated

description on a catalogue-oriented call. Truncation that is fine for prompt-building is lossy
for inventory.

  1. Provide a non-interactive path. Inventory collection is not an interactive activity;

requiring a bound interactive session rules out the scanning context entirely.

  1. Lower priority: a stable, documented way to read the catalogue without parsing the private

transcript format.

Alternative Solutions

What we do today, and why we would rather not

Our fallback parses the session transcript (~/.claude/projects/<slug>/<session>.jsonl), whose
deferred_tools_delta attachment lists every MCP tool name on connect — complete, including
never-invoked tools, but names only, with . irreversibly sanitized to _. That is
unsatisfactory for both sides: it is a private format with no stability contract (its shape
changed between 2.1.246 and 2.1.247), and it means a security agent reads files containing user
conversation content
just to obtain a tool list. A supported catalogue API would let us stop
touching those files — which we think is the strongest reason to do this.

Priority

High - Significant impact on productivity

Feature Category

MCP server integration

Use Case Example

_No response_

Additional Context

What we measured (Claude Code 2.1.247)

  • A plugin's hooks/hooks.json may declare modules: ["./register.js"]; Claude Code loads it

into a node:vm and passes a capability object of ~32 ops, including $.tool.list().

  • $.tool.list() returns exactly {name, description, mcp} — **no inputSchema, no

outputSchema** — and description is hard-truncated at 300 characters (a 616-char
description came back cut mid-word, no ellipsis).

  • The seam is gated on the GrowthBook flag tengu_plugin_hooks_modules, which is **absent from

the served feature payload entirely** (556 features fetched) — not off for this user, but not
shipped to this client population.

  • $.tool.describe is referenced in the bundle but is undefined at runtime.
  • $.tool.list() refuses to run headlessly: *"not available in this mode: no interactive session

is bound in this process (a -p run or the SDK)"*.

  • The schema is in the process: Claude Code's own /mcp panel renders both Description:

and Parameters: per tool. So omitting inputSchema from $.tool.list() is an API-shape
choice, not a data-availability limit.

Happy to test a build behind a flag.

Appendix — verbatim measurements (Claude Code 2.1.247)

| Observation | Detail |
|---|---|
| Plugin module seam | hooks/hooks.jsonmodules: ["./register.js"], loaded into a node:vm, called with a capability object of ~32 ops including $.tool.list() |
| $.tool.list() shape | {name, description, mcp} — no inputSchema, no outputSchema |
| Description truncation | Hard cut at 300 chars; a 616-char description returned cut mid-word, no ellipsis |
| Gating flag | tengu_plugin_hooks_modules — absent from the served feature payload (556 features fetched); not present-and-false |
| $.tool.describe | Referenced in the bundle, undefined at runtime |
| Headless behaviour | $.tool.list(): "not available in this mode: no interactive session is bound in this process (a -p run or the SDK)" |
| Data is resident | /mcp panel renders Description: and Parameters: per tool |
| Transcript fallback | ~/.claude/projects/<slug>/<session>.jsonl, deferred_tools_delta attachment, written on connect; complete tool-name list incl. never-invoked tools; names only; ._, irreversible; shape changed between 2.1.246 and 2.1.247 |

View original on GitHub ↗