Skip to content

Commit fc7f226

Browse files
committed
fix(tui): normalize harness namespace prefix in runner dispatch
Strip a single leading <segment>. prefix on registry miss and retry the lookup, so harness-namespaced calls such as default.mcp__linear__list_releases dispatch through the gate. Miss paths keep the exact reconnecting and unknown-tool strings with the original name.
1 parent 095d240 commit fc7f226

1 file changed

Lines changed: 34 additions & 0 deletions

File tree

‎src/tui/dynamic-tool-runner.test.ts‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,40 @@ describe("activated-but-unmounted registry miss", () => {
222222
});
223223
});
224224

225+
describe("harness namespace prefix", () => {
226+
test("a default.-prefixed call dispatches the registered bare tool", async () => {
227+
const runner = createDynamicToolRunner([
228+
stringTool("read_file", "core"),
229+
stringTool("mcp__acme__do", "blind-result"),
230+
]);
231+
const advertised = new Set(["read_file", "mcp__acme__do"]);
232+
runner.setCallGate((name) => advertised.has(name));
233+
234+
const result = await runner.run(
235+
{ id: "1", name: "default.mcp__acme__do", arguments: {} },
236+
new AbortController().signal,
237+
);
238+
239+
expect(result.isError).toBeUndefined();
240+
expect(result.content).toBe("blind-result");
241+
});
242+
243+
test("a prefixed miss keeps the exact unknown tool string with the original name", async () => {
244+
const runner = createDynamicToolRunner([stringTool("read_file", "core")]);
245+
runner.setCallGate((name) => name === "read_file", {
246+
isActivated: () => false,
247+
});
248+
249+
const result = await runner.run(
250+
{ id: "1", name: "default.mcp__gone__tool", arguments: {} },
251+
new AbortController().signal,
252+
);
253+
254+
expect(result.isError).toBe(true);
255+
expect(result.content).toBe("unknown tool: default.mcp__gone__tool");
256+
});
257+
});
258+
225259
describe("terminal control stripping", () => {
226260
test("strips escape sequences from any tool's result, including MCP", async () => {
227261
const payload = "before\x1b]52;c;ZXZpbA==\x07\x1b[31mred\x1b[0m\x07after";

0 commit comments

Comments
 (0)