Pull requests / #3135

#3135 serve: a bare MCP tool name runs the one tool that offers it, and an unoffered name becomes an error (#3113)

open · @ctr-137 · 0 Kommentare · Auf GitHub

Server & APIModels & quantsDocumentationWindows

Beschreibung

Issue: #3113 (duplicate #3112; the second half of #3075)

## Summary

The MCP servers load, the server window lists their tools, and the chat still never runs one. The reproduced cause:
the model writes the tool's **bare** name (`list_directory`), while Strata offers the namespaced route
(`filesystem__list_directory`). `run_with_mcp` treated every name that is not in `mcp_names` as one of the request's
own tools, returned it as an OpenAI `tool_calls` delta - and the web chat has no handler for `tool_calls`. Nothing
ran, and nothing was shown.

Against the real `npx -y @modelcontextprotocol/server-filesystem`, with the 14 tools in the prompt:

| the model wrote | what happened |
| --- | --- |
| `<function=list_directory>` | no `strata_mcp` events, a client `tool_calls` delta named `list_directory`, nothing ran |
| `<function=filesystem__list_directory>` | `start` / `call` / `result`, the tool ran |

That is the "backend loaded 14 tools, the Web UI never uses them" report in #3113.

## What changed

- `run_with_mcp` now takes the request's own tool names (`own_names`). A call to one of those goes back to the
  client exactly as before - the request's tools still win a name clash.
- A call with a name the request did not declare is resolved against the MCP tools this request offered: if exactly
  one offered tool has that bare name, it runs under its namespaced route.
- If two servers offer the name, or no offered tool has it, the model gets an `error:` result naming the full
  `<server>__<tool>` routes, so it can correct itself; the chat page shows the block. Before, the call disappeared.
- The `tool_start`/`tool_args`/`tool_call` events of an MCP call are still kept off the client stream, and the
  continuation prompt names the route that actually ran, so the call and its result agree.
- `docs/DETAILS.md`: one bullet under "Tools from MCP servers".

Only requests with `"strata_mcp": true` (the chat page's opt-in) take this path. The default API path is unchanged:
a request that declares no MCP opt-in still returns tool calls to its client exactly as before.

## How this was checked

`python -m unittest serve.test_mcp` - **29 tests, OK**, four of them new:

- a bare `echo` runs `fake__echo`, with `start`/`call`/`result`, no client tool call, and the result in the next
  prompt;
- an unoffered `nope` becomes an `error:` result naming `fake__echo`, and the model gets a second round;
- a bare `echo` offered by two servers is an error naming both routes (no guessing);
- a request that declares its own `echo` keeps it: the client answers, not the MCP server.

The full `serve` suite: **852 tests; the only error is `test_winjob.TestWinJob`** (a Windows `tasklist` call
returning `None` here), the same one as on unmodified `main` (848 tests). `test_keepawake` is timing-flaky under the
full run and passes alone; neither is related to this change. No new skips.

## What I left alone

Three neighbouring MCP failure modes are real and worth their own PRs, but are not this change:

- `serve/web/app.js:407-417`: one failed `GET /mcp` disables MCP tools for the life of the tab (no retry unless a
  server is literally `starting`). This can produce the same symptom as #3113.
- `serve/server.py`: the hard-coded `svc.mcp.wait(10)` in `_openai` omits a still-starting server from the first chat.
- `serve/mcp.py` `HttpTransport._post`: `http.client.IncompleteRead` is not caught, so a truncated HTTP answer can
  leave the server on "Starting" instead of "Failed".

Images returned by MCP tools (#2130) and the 10 s start wait are untouched as well.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Mehr auf der Site

Links zu Install, Modellen, Releases.