From 147ba69968b84fbb4e235e4c37d7827cd046d93e Mon Sep 17 00:00:00 2001 From: Marco Sadjadi Date: Thu, 28 May 2026 21:39:11 +0200 Subject: [PATCH] fix(runner): alias params/input to args so tool implementations don't ReferenceError Auth chain finally landed but tool calls crashed in the wetter server with "Error: params is not defined". The MCP SDK passes the validated tool args as a single parameter; our template names that parameter `args` but the model frequently writes `params.location` / `input.x` because that's how OpenAPI and JSON-RPC reference docs read. Two-sided fix: - render.ts wraps every implementation with `const params = args; const input = args;` inside the try block. Whichever alias the model picked, the variable resolves to the same validated object. - SYSTEM_PROMPT now states the variable name EXPLICITLY ("variable named EXACTLY `args`, e.g. args.location") so new generations stop drifting on that detail. Existing wetter runner needs a rebuild to pick up the alias shim. --- apps/generator/src/lib/render.ts | 9 +++++++++ packages/llm/src/index.ts | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/generator/src/lib/render.ts b/apps/generator/src/lib/render.ts index 179a104..9705179 100644 --- a/apps/generator/src/lib/render.ts +++ b/apps/generator/src/lib/render.ts @@ -38,6 +38,15 @@ function renderTool(tool: ToolSpec): string { inputSchema: ${schemaShape}, }, async (args) => { + // The MCP SDK passes the validated tool arguments as the single + // parameter. Models trained on OpenAPI / JSON-RPC examples reach + // for "params" instead of "args", and "input" shows up too — bind + // every common alias to the same object so the generated body + // works whichever name the model picked. Without this the runner + // crashes with "ReferenceError: params is not defined" at the + // first tool call (verified in prod with the wetter server). + const params = args; + const input = args; try { ${tool.implementation} } catch (err) { diff --git a/packages/llm/src/index.ts b/packages/llm/src/index.ts index 1c2c546..a62f155 100644 --- a/packages/llm/src/index.ts +++ b/packages/llm/src/index.ts @@ -15,7 +15,7 @@ Output ONE JSON object (no markdown, no prose, no code fences) with this exact s "inputSchema": { "param_name": { "type": "string|number|boolean|array|object", "description": "short", "required": true } }, - "implementation": "async TS body, return { content: [{ type:'text', text:'...' }] }; secrets via process.env; HTTP via globalThis.fetch with AbortSignal.timeout(10000); try/catch -> { content:[{type:'text',text:'Error: ...'}], isError:true }; no eval/Function/child_process; no imports." + "implementation": "async TS body. The tool's validated arguments arrive in the variable named EXACTLY `args` (e.g. args.location, args.query). Return { content: [{ type:'text', text:'...' }] }. Secrets via process.env. HTTP via globalThis.fetch with AbortSignal.timeout(10000). Wrap external calls in try/catch and return { content:[{type:'text',text:'Error: ...'}], isError:true } on failure. No eval/Function/child_process. No import statements." } ], "resources": [],