From 49e90d45f82828e6892b63fa62dacc6d56ce47b8 Mon Sep 17 00:00:00 2001 From: Dmytro Stanchiev Date: Tue, 28 Apr 2026 19:03:42 -0400 Subject: [PATCH] docs: expose unstable mode in mcp tools --- packages/mcp-server/src/protocol/handler.ts | 6 ++ packages/mcp-server/src/protocol/tools.ts | 15 ++++ packages/mcp-server/test/protocol.test.ts | 99 +++++++++++++++++++++ 3 files changed, 120 insertions(+) diff --git a/packages/mcp-server/src/protocol/handler.ts b/packages/mcp-server/src/protocol/handler.ts index 19dd850..f9f40df 100644 --- a/packages/mcp-server/src/protocol/handler.ts +++ b/packages/mcp-server/src/protocol/handler.ts @@ -116,6 +116,8 @@ export async function handleMcpRequest(req: Request): Promise { if (args.priceMax) params.append("priceMax", args.priceMax.toString()); if (args.cookies) params.append("cookies", args.cookies); + if (args.unstableFilter !== undefined) + params.append("unstableFilter", args.unstableFilter.toString()); console.log( `[MCP] Calling Kijiji API: ${API_BASE_URL}/kijiji?${params.toString()}`, @@ -155,6 +157,8 @@ export async function handleMcpRequest(req: Request): Promise { if (args.location) params.append("location", args.location); if (args.maxItems) params.append("maxItems", args.maxItems.toString()); + if (args.unstableFilter !== undefined) + params.append("unstableFilter", args.unstableFilter.toString()); console.log( `[MCP] Calling Facebook API: ${API_BASE_URL}/facebook?${params.toString()}`, @@ -207,6 +211,8 @@ export async function handleMcpRequest(req: Request): Promise { params.append("canadaOnly", args.canadaOnly.toString()); if (args.maxItems) params.append("maxItems", args.maxItems.toString()); + if (args.unstableFilter !== undefined) + params.append("unstableFilter", args.unstableFilter.toString()); console.log( `[MCP] Calling eBay API: ${API_BASE_URL}/ebay?${params.toString()}`, diff --git a/packages/mcp-server/src/protocol/tools.ts b/packages/mcp-server/src/protocol/tools.ts index a50c01b..91c3fa1 100644 --- a/packages/mcp-server/src/protocol/tools.ts +++ b/packages/mcp-server/src/protocol/tools.ts @@ -57,6 +57,11 @@ export const tools = [ description: "Optional: Kijiji session cookies to bypass bot detection (JSON array or 'name1=value1; name2=value2')", }, + unstableFilter: { + type: "boolean", + description: + "optional: when enabled, listings priced more than 20% below the median are moved into an `unstableResults` bucket. Changes the response shape from a plain list to an object with `results` and `unstableResults`.", + }, }, required: ["query"], }, @@ -81,6 +86,11 @@ export const tools = [ description: "Maximum number of items to return", default: 5, }, + unstableFilter: { + type: "boolean", + description: + "optional: when enabled, listings priced more than 20% below the median are moved into an `unstableResults` bucket. Changes the response shape from a plain list to an object with `results` and `unstableResults`.", + }, }, required: ["query"], }, @@ -134,6 +144,11 @@ export const tools = [ description: "Maximum number of items to return", default: 5, }, + unstableFilter: { + type: "boolean", + description: + "optional: when enabled, listings priced more than 20% below the median are moved into an `unstableResults` bucket. Changes the response shape from a plain list to an object with `results` and `unstableResults`.", + }, }, required: ["query"], }, diff --git a/packages/mcp-server/test/protocol.test.ts b/packages/mcp-server/test/protocol.test.ts index 1f2006c..f760f1c 100644 --- a/packages/mcp-server/test/protocol.test.ts +++ b/packages/mcp-server/test/protocol.test.ts @@ -54,3 +54,102 @@ describe("MCP protocol cookie inputs", () => { expect(String(calledUrl)).not.toContain("cookies="); }); }); + +describe("MCP protocol unstableFilter", () => { + beforeEach(() => { + global.fetch = mock(() => + Promise.resolve(new Response(JSON.stringify([]), { status: 200 })), + ) as typeof fetch; + }); + + afterEach(() => { + global.fetch = originalFetch; + }); + + test("all search tools should document the unstableFilter property", () => { + const toolNames = ["search_kijiji", "search_facebook", "search_ebay"]; + for (const toolName of toolNames) { + const tool = tools.find((t) => t.name === toolName); + expect(tool).toBeDefined(); + expect(tool?.inputSchema.properties).toHaveProperty("unstableFilter"); + const prop = tool?.inputSchema.properties.unstableFilter as any; + expect(prop.type).toBe("boolean"); + expect(prop.description).toContain("optional"); + expect(prop.description).toContain("20%"); + expect(prop.description).toContain("median"); + expect(prop.description).toContain("unstableResults"); + } + }); + + test("handler should forward unstableFilter=true for search_kijiji", async () => { + await handleMcpRequest( + new Request("http://localhost", { + method: "POST", + body: JSON.stringify({ + jsonrpc: "2.0", + id: 1, + method: "tools/call", + params: { + name: "search_kijiji", + arguments: { + query: "laptop", + unstableFilter: true, + }, + }, + }), + }), + ); + + const calledUrl = (global.fetch as ReturnType).mock + .calls[0]?.[0]; + expect(String(calledUrl)).toContain("unstableFilter=true"); + }); + + test("handler should forward unstableFilter=true for search_facebook", async () => { + await handleMcpRequest( + new Request("http://localhost", { + method: "POST", + body: JSON.stringify({ + jsonrpc: "2.0", + id: 1, + method: "tools/call", + params: { + name: "search_facebook", + arguments: { + query: "laptop", + unstableFilter: true, + }, + }, + }), + }), + ); + + const calledUrl = (global.fetch as ReturnType).mock + .calls[0]?.[0]; + expect(String(calledUrl)).toContain("unstableFilter=true"); + }); + + test("handler should forward unstableFilter=true for search_ebay", async () => { + await handleMcpRequest( + new Request("http://localhost", { + method: "POST", + body: JSON.stringify({ + jsonrpc: "2.0", + id: 1, + method: "tools/call", + params: { + name: "search_ebay", + arguments: { + query: "laptop", + unstableFilter: true, + }, + }, + }), + }), + ); + + const calledUrl = (global.fetch as ReturnType).mock + .calls[0]?.[0]; + expect(String(calledUrl)).toContain("unstableFilter=true"); + }); +});