Skip to content

Commit 8a603ae

Browse files
committed
Simplify tool filter validation logic and add ambiguous filter test
- Remove unnecessary validation in #matchesToolFilter - Malformed filter strings naturally fail to match - Add test case for ambiguous filter names
1 parent f93935c commit 8a603ae

File tree

2 files changed

+80
-13
lines changed

2 files changed

+80
-13
lines changed

src/client.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -840,28 +840,26 @@ export class McpdClient {
840840
* Check if a tool matches the tool filter.
841841
*
842842
* Supports two formats:
843-
* - Raw tool name: "get_current_time" (matches tool name only)
844-
* - Server-prefixed name: "time__get_current_time" (server + TOOL_SEPARATOR + tool)
843+
* - Raw tool name: "get_current_time" (matches across all servers)
844+
* - Server-prefixed: "time__get_current_time" (matches specific server + tool)
845+
*
846+
* When a filter contains "__", it's first checked as server-prefixed (exact match).
847+
* If that fails, it's checked as a raw tool name. This handles tools whose names
848+
* contain "__" (e.g., "my__special__tool").
845849
*
846850
* @param tool The tool to check.
847851
* @param tools List of tool names/patterns to match against.
848852
* @returns True if the tool matches any item in the filter.
849853
*/
850854
#matchesToolFilter(tool: AgentFunction, tools: string[]): boolean {
851855
return tools.some((filterItem) => {
852-
const separatorIndex = filterItem.indexOf(TOOL_SEPARATOR);
853-
if (separatorIndex !== -1) {
854-
const leftPart = filterItem.slice(0, separatorIndex).trim();
855-
const rightPart = filterItem
856-
.slice(separatorIndex + TOOL_SEPARATOR.length)
857-
.trim();
858-
859-
if (leftPart && rightPart && filterItem === tool.name) {
860-
return true;
861-
}
856+
if (filterItem.indexOf(TOOL_SEPARATOR) === -1) {
857+
// Match against raw tool name
858+
return filterItem === tool._toolName;
862859
}
863860

864-
return filterItem === tool._toolName;
861+
// Try prefixed match first, then fall back to raw match
862+
return filterItem === tool.name || filterItem === tool._toolName;
865863
});
866864
}
867865
}

tests/unit/client.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,75 @@ describe("McpdClient", () => {
761761
expect(prefixedFilter).toHaveLength(1);
762762
expect(prefixedFilter[0]?.name).toBe("test__my__special__tool");
763763
});
764+
765+
it("should prefer prefixed format when filter is ambiguous", async () => {
766+
mockFetch.mockResolvedValueOnce({
767+
ok: true,
768+
json: async () => ["my", "other"],
769+
});
770+
771+
mockFetch.mockResolvedValueOnce({
772+
ok: true,
773+
json: async () => ({
774+
servers: [
775+
{
776+
name: "my",
777+
status: "ok",
778+
latency: "1ms",
779+
lastChecked: "2025-10-07T15:00:00Z",
780+
lastSuccessful: "2025-10-07T15:00:00Z",
781+
},
782+
{
783+
name: "other",
784+
status: "ok",
785+
latency: "1ms",
786+
lastChecked: "2025-10-07T15:00:00Z",
787+
lastSuccessful: "2025-10-07T15:00:00Z",
788+
},
789+
],
790+
}),
791+
});
792+
793+
mockFetch.mockResolvedValueOnce({
794+
ok: true,
795+
json: async () => ({
796+
tools: [
797+
{
798+
name: "special__tool",
799+
description: "Tool from 'my' server",
800+
inputSchema: { type: "object", properties: {} },
801+
},
802+
],
803+
}),
804+
});
805+
806+
mockFetch.mockResolvedValueOnce({
807+
ok: true,
808+
json: async () => ({
809+
tools: [
810+
{
811+
name: "my__special__tool",
812+
description: "Tool from 'other' server",
813+
inputSchema: { type: "object", properties: {} },
814+
},
815+
],
816+
}),
817+
});
818+
819+
const tools = await client.getAgentTools({
820+
tools: ["my__special__tool"],
821+
});
822+
823+
expect(tools).toHaveLength(2);
824+
825+
const prefixedMatch = tools.find((t) => t._serverName === "my");
826+
expect(prefixedMatch?._toolName).toBe("special__tool");
827+
expect(prefixedMatch?.name).toBe("my__special__tool");
828+
829+
const rawMatch = tools.find((t) => t._serverName === "other");
830+
expect(rawMatch?._toolName).toBe("my__special__tool");
831+
expect(rawMatch?.name).toBe("other__my__special__tool");
832+
});
764833
});
765834

766835
describe("clearAgentToolsCache()", () => {

0 commit comments

Comments
 (0)