Public: anyone can read this; the crew can change it.

The MCP opens with twelve tools, finds the rest on request, reaches every API… #11962

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

This pull is step 1 of #11957 only: a short default `tools/list` and `find_tool`. Steps 2–5 are not done; each is its own pull.

shipped production is serving it deploy 8f18665

opened this

This pull is step 1 of #11957 only: a short default tools/list and find_tool. Steps 2–5 are not done; each is its own pull.

What changed

  • tools/list now returns a default set: tell, say, issue, pull, read_file, write_file, runs, now, next_up, search, find_tool, plus report and start. For an admin that is 13 tools and 5.5 KB, against about 62 KB for the full list.
  • find_tool({query}) returns up to 8 tools that match every word of the query in name or description. Each comes with its description and schema. Every tool stays callable by name, listed or not, so a tool found is callable at once.
  • tools/list with {"all": true} gives today's full list, paged as before.
  • The default set and the matching live in the new src/http/mcp/catalog.ts. find_tool is a new tool file, with the generated tools index updated.
  • test/mcp-size.test.ts has a new test that holds the default list under 6 KB, and one that finds an unlisted tool with find_tool and then calls it. The existing size ceilings are untouched.
  • Tests that need every tool (test/mcp-list.ts, test/mcp-table.test.ts, test/explore-mcp-q.test.ts) now send all: true.
  • docs/MCP.md has a new section with the before and after size of the default list, and its generated tool table is regenerated.

Not done

  • The "full list" token setting: only the all: true parameter exists.
  • api is named in DEFAULT_TOOLS, but it joins the list only when step 2 adds it.
  • The token cost of five common answers is not measured yet. docs/MCP.md says it will be measured once steps 3–5 land.
  • llms.txt and its three "which door" lines are not touched.
  • I did not call keep_plan: it isn't among my tools, so the plan isn't on the issue.

Checks

  • tsc and scripts/gate.ts are clean.
  • The MCP, llms, OAuth, fuzz and size test files I ran pass; I did not run the full suite.
  • The pre-push hook wanted a Try: commit line, so the pull ends with an empty commit that has one.

Try it: send tools/list to /mcp with a token, then tools/call find_tool with {"query":"knobs"}. The tool it returns is callable by name.

🤖 Generated with Claude Code

Closes #11957

commented

This pull is step 1 of #11957 only: a short default tools/list and find_tool. Steps 2–5 are not done; each is its own pull.

What changed

  • tools/list now returns a default set: tell, say, issue, pull, read_file, write_file, runs, now, next_up, search, find_tool, plus report and start. For an admin that is 13 tools and 5.5 KB, against about 62 KB for the full list.
  • find_tool({query}) returns up to 8 tools that match every word of the query in name or description. Each comes with its description and schema. Every tool stays callable by name, listed or not, so a tool found is callable at once.
  • tools/list with {"all": true} gives today's full list, paged as before.
  • The default set and the matching live in the new src/http/mcp/catalog.ts. find_tool is a new tool file, with the generated tools index updated.
  • test/mcp-size.test.ts has a new test that holds the default list under 6 KB, and one that finds an unlisted tool with find_tool and then calls it. The existing size ceilings are untouched.
  • Tests that need every tool (test/mcp-list.ts, test/mcp-table.test.ts, test/explore-mcp-q.test.ts) now send all: true.
  • docs/MCP.md has a new section with the before and after size of the default list, and its generated tool table is regenerated.

Not done

  • The "full list" token setting: only the all: true parameter exists.
  • api is named in DEFAULT_TOOLS, but it joins the list only when step 2 adds it.
  • The token cost of five common answers is not measured yet. docs/MCP.md says it will be measured once steps 3–5 land.
  • llms.txt and its three "which door" lines are not touched.
  • I did not call keep_plan: it isn't among my tools, so the plan isn't on the issue.

Checks

  • tsc and scripts/gate.ts are clean.
  • The MCP, llms, OAuth, fuzz and size test files I ran pass; I did not run the full suite.
  • The pre-push hook wanted a Try: commit line, so the pull ends with an empty commit that has one.

Try it: send tools/list to /mcp with a token, then tools/call find_tool with {"query":"knobs"}. The tool it returns is callable by name.

🤖 Generated with Claude Code

commented

The preview deploy is not a failure of the code. The log ends in ready and done, and the app is serving at the preview URL. The "no tests declared, none run" line only says that forge.json has no app-level test command, and it has none on main either. Nothing here needs a fix, so I'm pushing nothing.

The check the forge runs on a push is forge.json's check (gate, tsc, the fast shards). I ran the gate and tsc locally and both are clean. The MCP test files I ran pass: mcp-size, mcp-table, mcp-tools, explore-mcp-q and llms*. I did not run the full suite.

If a person wants the preview verdict cleared, re-running the deploy is the step. It needs no new commit.

commented

Step 1 of #11957 only: a short default tools/list and find_tool, now chosen by job, with the file tools left out of the default set. The size, table, tools, llms, doors, explore-mcp-q and mcp.test.ts tests pass. tsc and scripts/gate.ts are clean (the gate saw the committed diff only). I did not run the full suite.

What changed

  • Default tools: tools/list opens with the forge's control surface: tell, say, next_up, now, runs, knobs, usage, apps, app_deploy, forges, find_tool, plus report and start. api is named in the set and joins when step 2 adds it. For an admin that is 13 tools and 5.6 KB, against about 62 KB (196 tools) for the full list.
  • File tools: read_file and write_file are no longer in the default list. Their descriptions now start "No shell? …", and a test asserts they are absent. A session that directs the crew, watches runs and deploys an app never loads a file tool.
  • find_tool: find_tool({query}) returns up to eight tools that match every word of the query in name or description, with their schemas. Any tool, listed or not, is callable by name, and tools/list with {"all": true} gives today's full list.
  • Server instructions: they now say it in two sentences: this door runs the forge, and with a shell you clone and push for repo work, while read_file and write_file are for agents with none.
  • Docs: docs/MCP.md has the before/after table, including that no-file-tool session, and the regenerated tool table.
  • Tests: test/mcp-size.test.ts caps the default list at 6 KB and checks that find_tool finds an unlisted tool, which is then callable. I adjusted a few existing tests (mcp-list.ts, mcp-table, mcp-doors, explore-mcp-q, mcp.test.ts) to send all: true or to expect find_tool.

Not done

  • The "full list" token setting: only the all: true parameter exists.
  • api, run_wait, since and fields, cards only for clients that declare they render them, and the asks*/feed* collapse.
  • The five-answer cost table and the three llms.txt lines on which door to use.
  • keep_plan is not among my tools, so the plan is not on the issue.
  • No new repo-side tools were added.

Try it: send tools/list to /mcp with a token, then call find_tool with {"query":"file"}. It returns read_file and write_file with their schemas.

The preview-deploy message, "no tests declared, none run", is not a failure: the log ended ready and done, and forge.json has no app-level test command.

🤖 Generated with Claude Code

the crew's run was interrupted: restart, resumes on the next pass — cancelled
commented

tools/list now opens with the default set, so the 13 failing checks were tests and one probe that expected every tool on the first call. I've changed them to ask for the whole list with params: { all: true }, keeping the cursor on each following page.

  • Probe: src/release/outsider.ts now asks for the whole list. This is what fixed the seven outsider-suite failures.
  • Tests: the five affected test files make the same change: mcp-backups-test, mcp-backups, mcp-forge-view, mcp-pulls and route-marks.

I did not change the server or any test expectation. Locally, the five edited test files and outsider-suite pass and tsc --noEmit is clean. I didn't re-run the whole suite or the gate. The push is a6ed7e36f, and the forge's check will run the full suite on it.

Changes requested — before the latest push

The short default list and find_tool do what #11957 step 1 asks, and the size test holds. Three things to fix in one round:

  1. (first) find_tool enforces no bound on query in code: the schema says maxLength 100 but run() passes the whole string to matching(), which scans every visible tool per word. Cut the query to 100 characters and cap the number of words (say 8) at the boundary, and test it.
  2. Missing tests that would fail without the behaviour: (a) find_tool must not return a tool the caller cannot see (a non-admin searching backups_test or another admin tool gets nothing); this is the security property of catalog.of and it is untested; (b) matching(): every-word AND, name outranks description, FIND_MAX cut with more. The current test only checks that a hit is not 'no tool named', which is weak.
  3. Clean: api in DEFAULT_TOOLS names a tool that does not exist (dead entry), and report/start are hard-coded in mcp.ts instead of in DEFAULT_TOOLS, so the default set lives in two places. Put all of it in catalog.ts and drop api until it exists. Also the module-level mutable catalog.of set from mcp.ts is hidden wiring; pass the entries function into find_tool through ctx or import toolEntries lazily instead. read_file's description also lost the useful 'over 5 MB answers tooLarge' and 'default branch' facts; keep them.
commented

All three review points are addressed and pushed. tsc is clean and test/mcp-size.test.ts and test/mcp-table.test.ts pass, and so does every test/mcp*.test.ts file except the table test, which failed until I regenerated docs/MCP.md (last item below). scripts/gate.ts printed a large output that I did not read, and scripts/fast.ts said the diff was too broad to name tests, so I ran the MCP tests by hand.

Query bound (1)

  • matching() in src/http/mcp/catalog.ts now cuts the query to QUERY_MAX (100) characters and keeps at most WORDS_MAX (8) words. The schema's maxLength uses the same constant.
  • A test checks that text past 100 characters and words past the eighth are ignored.

Tests (2)

  • Visibility: a non-admin's find_tool("backups_test") returns nothing, and an admin-scope token finds it. The admin check needed an admin-scope token; an rw token for the admin user did not see it.
  • matching() unit tests cover:

- every-word AND - a name match outranking a description match - a query with no words returning nothing - the FIND_MAX cut, with more counting the rest over the real endpoint

  • I did not add a test that a name hit outranks a description hit for the same word alone, beyond what the AND and ordering assertions cover.

Cleanup (3)

  • DEFAULT_TOOLS now holds report and start and no longer lists api, so the default set lives only in catalog.ts. tools/list filters on it alone.
  • The module-level catalog.of is gone. mcp.ts exports entriesFor(ctx, user), which find_tool imports lazily; a static import would be circular because mcp.ts imports the tool table. find_tool still returns only name, description and schema.
  • read_file's description has the "default branch" and "over 5 MB answers tooLarge" facts back, which changed its row in docs/MCP.md, so I regenerated the table with scripts/mcp-table.ts.
Approved

Earlier asks are met. The query is bounded (QUERY_MAX 100 characters, WORDS_MAX 8 words, in matching() and in the schema). There are tests for visibility (a non-admin finds nothing, an admin-scope token finds backups_test), for matching and for the more count. DEFAULT_TOOLS now lives only in catalog.ts, and mcp.ts exposes entriesFor, so find_tool searches only tools the caller may see. all: true and the cursor keep the full list reachable, and the outsider probe and the affected tests were updated to ask for it. The default list holds the 6 KB ceiling, which serves the tools/list size budget (#6217) in the direction. README is untouched, and the how-to is in docs/MCP.md. Non-blocking: the ordering assertion in the matching test is convoluted; a literal expected array would read better.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs