{"record":{"id":"77c3988f714689bf","repo":"different-ai/openwork","slug":"mcp-tool-execution","errorCode":"MCP_TOOL_EXECUTION","errorMessage":"No suitable tool was available for the requested probe","messagePattern":"No suitable tool was available for the requested probe","errorType":"exception","errorClass":"ProbeFailure","httpStatus":null,"severity":"error","filePath":"packages/enterprise-mcp-mock-server/src/testing/probe.ts","lineNumber":870,"sourceCode":"      if (missing.length > 0 || unexpected.length > 0) {\n        throw new ProbeFailure(\n          \"MCP_TOOL_DISCOVERY\",\n          \"profile_fixture_mismatch\",\n          `Catalog does not match pinned profile fixture ${profile.fixtureVersion}`,\n        )\n      }\n    }\n    recordPassed(phases, \"MCP_TOOL_DISCOVERY\", startedAt, `Retrieved ${toolNames.size} unique tools with bounded pagination`)\n\n    const fault = activeFault\n    const shouldCall = options.callTool !== undefined || mode === \"safe-read\" || fault?.phase === \"PROVIDER_AUTHORIZATION\" || fault?.phase === \"PROVIDER_EXECUTION\"\n    if (shouldCall) {\n      const selected = options.callTool\n        ? { name: options.callTool.name, arguments: options.callTool.arguments }\n        : (() => {\n            const mutationRequired = fault?.effect === \"commit-then-disconnect\"\n            const tool = discoveredTools.find((candidate) => candidate.kind === (mutationRequired ? \"mutation\" : \"read\"))\n            if (!tool) throw new ProbeFailure(\"MCP_TOOL_EXECUTION\", \"mcp_tool\", \"No suitable tool was available for the requested probe\")\n            return { name: tool.name, arguments: defaultArguments(tool.inputSchema) }\n          })()\n      const selectedTool = profile.tools.find((tool) => tool.name === selected.name)\n      if (mode === \"safe-read\" && selectedTool?.kind !== \"read\") {\n        throw new ProbeFailure(\"CONFIGURATION\", \"configuration\", \"safe-read mode accepts only a declared read-only tool\")\n      }\n      startedAt = Date.now()\n      let toolResponse: Response\n      try {\n        toolResponse = await fetchStep(mcpUrl, {\n          method: \"POST\",\n          headers: sessionHeaders,\n          body: JSON.stringify({ jsonrpc: \"2.0\", id: 100, method: \"tools/call\", params: selected }),\n        }, \"MCP_TOOL_EXECUTION\", overallDeadline)\n      } catch {\n        throw new ProbeFailure(\n          selectedTool?.kind === \"mutation\" ? \"PROVIDER_EXECUTION\" : \"MCP_TOOL_EXECUTION\",\n          selectedTool?.kind === \"mutation\" ? \"mutation_indeterminate\" : \"mcp_tool\",","sourceCodeStart":852,"sourceCodeEnd":888,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/packages/enterprise-mcp-mock-server/src/testing/probe.ts#L852-L888","documentation":"When the probe should execute a tool call, it auto-selects the first discovered tool of the required kind: a mutation tool for commit-then-disconnect faults, otherwise a read tool. If the discovered catalog contains no tool of that kind, the probe throws MCP_TOOL_EXECUTION / mcp_tool.","triggerScenarios":"probeEnterpriseMcpMockServer with shouldCall true, no options.callTool override, and discoveredTools contains no candidate whose kind matches the requested (\"mutation\" for commit-then-disconnect faults, otherwise \"read\").","commonSituations":"Profile only defines read tools while the fault scenario needs a mutation tool; all tools failed schema validation earlier so discoveredTools is empty; custom callTool name not present in the profile.","solutions":["Add a tool of the required kind (mutation for commit-then-disconnect, otherwise read) to the profile fixture.","Pass options.callTool explicitly with a name and arguments matching a registered tool.","Fix earlier discovery failures (invalid schemas) so tools actually land in discoveredTools.","Verify the server's advertised tool kinds match the fixture kinds."],"exampleFix":"// before: read-only profile used with a commit-then-disconnect fault\nconst profile = { tools: [{ name: \"get_docs\", kind: \"read\" }] };\n// after: include a mutation tool\nconst profile = { tools: [{ name: \"get_docs\", kind: \"read\" }, { name: \"create_doc\", kind: \"mutation\" }] };","handlingStrategy":"validation","validationCode":"const mutationRequired = fault?.effect === \"commit-then-disconnect\";\nconst kindNeeded = mutationRequired ? \"mutation\" : \"read\";\nif (!options.callTool && !profile.tools.some((t) => t.kind === kindNeeded)) {\n  throw new Error(`Profile lacks a '${kindNeeded}' tool required by this probe mode`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await probeEnterpriseMcpMockServer(options);\n} catch (e) {\n  if (e instanceof ProbeFailure && e.code === \"MCP_TOOL_EXECUTION\" && e.reason === \"mcp_tool\") {\n    // add the required tool kind to the fixture or pass options.callTool\n  } else throw e;\n}","preventionTips":["Ensure every fixture includes at least one read and one mutation tool.","Pass options.callTool explicitly when a specific tool is required.","Fix discovery failures first — tools rejected for schema never reach discoveredTools."],"tags":["mcp","tool-execution","fixture-coverage"],"backgroundTag":"required-tool-missing","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}