fix(loader): name the MCP tool a load failure belongs to #11
No reviewers
Labels
No labels
area/engine
clarity/clear
enhancement
security
size/M
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
basepeak-ai/gptscript!11
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/mcp-load-error-tool-name"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The problem
An MCP load failure cannot say which tool it belongs to.
mcp.(*Local).Loadreports the server key, and the one-server-per-toolconfiguration bpai generates always keys it
"default". So a program carryingseveral MCP tools produces the same sentence whichever one failed:
processMCPhast.Namein hand at the wrap site and drops it.Downstream, that forces a caller to treat every candidate as the culprit. In
bpai,
markMCPOAuthWallHitmarks every unconnected oauth-mode MCP tool on theagent when a load 401s, because it genuinely cannot narrow. An agent carrying a
stale-API-key MCP server alongside an unrelated unconnected oauth-mode server
marks the oauth one every turn; the user connects and the run still fails.
The change
Append the tool name to the existing wrap:
Appended, not interpolated, so
error loading MCP toolsis still a prefix.Consumers match that text rather than an error type (the failure crosses the
sdkserver boundary as a string), and both shapes have to keep matching across a
pin bump in either direction so a rollback does not silently stop recognising
it. bpai's matcher uses
strings.Contains, and a test case for the new shapelands alongside the pin bump there.
An unnamed tool (inline MCP, no
Name) keeps the plain wrap rather thanproducing
... for : ....Tests
pkg/loader/mcp_error_test.go, drivingprocessMCPagainst a failing loader:error loading MCP toolsprefixsurvives, and the cause stays unwrappable (
errors.Is)Plus one end-to-end case through
ProgramFromSource, which closes the link theothers assume rather than prove: that the name a caller puts on a
ToolDefsurvives the SDK's
"#!GPTSCRIPT" + JSONserialization and the parse back intotypes.Tool. Dropped anywhere on that path, the wrap would still compile andstill read plausibly while naming nothing, and a caller narrowing on the name
would silently never match. Mutation-checked: inverting the name guard fails all
three.
go test ./pkg/loader/is clean.pkg/loader/githubfails on unmodifiedmainin this environment too (it fetches from raw.githubusercontent.com); unrelated.
Follow-up in bpai
Bumping the pin and narrowing
markMCPOAuthWallHitto the named tool is aseparate PR there.
CI note:
test (ubuntu-22.04)andvalidate-docsfail on this PR for a reason that predates it.make tidycannot resolvebasepeak-ai/broadcaster, a private module, because the runner has no credentials:Both jobs fail identically on every recent commit in this repo, merged ones included (runs #197/#198 on
7738a4c, #192/#193 on the PR before it).check-labelfails on everypull_requestevent for the same structural reason it passed on push.Locally,
go test ./pkg/loader/is clean.pkg/loader/githubfails on unmodifiedmainhere too — it fetches from raw.githubusercontent.com.