moeru-ai/airi · error · Error
MCP tools are not available in this runtime.
Error message
MCP tools are not available in this runtime.
What it means
stage-ui ships default MCP tool schemas via mcp(), but the default runtime is createUnavailableMcpToolRuntime(), whose listTools throws this. A concrete runtime (e.g. Electron main over IPC) is expected to build real tools with createMcpTools(runtime) and register them through useLlmToolsStore to override the defaults. Inside createMcpTools the throw is caught and '' is returned to the model, so the raw error mainly reaches direct runtime callers and tests.
Source
Thrown at packages/stage-ui/src/tools/mcp.ts:137
isError: true,
content: [{ type: 'text', text: errorMessageFromValue(error) }],
}
}
},
// NOTICE: `arguments` is z.string() (JSON) because z.unknown() produces `{}` (no `type` key)
// and z.record() emits `propertyNames`, both rejected by OpenAI.
parameters: z.object({
name: z.string().describe('Tool name in "<serverName>::<toolName>" format'),
arguments: z.string().describe('JSON object of tool arguments, e.g. {"query":"hello","limit":10}'),
}).strict(),
}),
]
}
function createUnavailableMcpToolRuntime(): McpToolRuntime {
return {
async listTools() {
throw new Error('MCP tools are not available in this runtime.')
},
async callTool() {
throw new Error('MCP tools are not available in this runtime.')
},
}
}
/**
* Builds the default stage-ui MCP tool set without depending on runtime singletons.
*
* Use when:
* - Shared code needs the MCP tool schema before a concrete runtime registers live implementations
*
* Expects:
* - Runtime-specific callers override these tools through `useLlmToolsStore`
*
* Returns:
* - MCP tool definitions with an unavailable-runtime fallbackView on GitHub (pinned to 677329427f)
Solutions
- In runtime bootstrap, implement McpToolRuntime (listTools/callTool) and register createMcpTools(runtime) via useLlmToolsStore so it overrides the defaults.
- If the runtime cannot support MCP, exclude the default mcp() tools from the tool list instead of shipping them.
- In tests, pass a stub runtime to createMcpTools rather than calling mcp().
Example fix
// before
const tools = await mcp() // default unavailable runtime
// after
const runtime: McpToolRuntime = electronMcpRuntime // real bridge
const tools = await Promise.all(createMcpTools(runtime))
await useLlmToolsStore().setTools('mcp', tools) Defensive patterns
Strategy: validation
Validate before calling
const mcpSupported = isStageTamagotchi() // or your runtime capability flag const tools = mcpSupported ? await Promise.all(createMcpTools(runtime)) : [] // do not register the unavailable defaults
Try / catch
try {
return await runtime.listTools()
}
catch (e) {
if (errorMessageFrom(e)?.includes('not available in this runtime'))
return [] // treat as zero MCP tools
throw e
} Prevention
- Never register mcp() defaults in runtimes without a bridge.
- Probe runtime capabilities at bootstrap and filter the tool list accordingly.
- Keep MCP behind a runtime flag in shared code.
When it happens
Trigger: The LLM invokes builtIn_mcpListTools while only the default mcp() tool set is registered — stage-web or a test environment where no runtime wired an McpToolRuntime bridge.
Common situations: Running the shared toolset in a new runtime integration before implementing the bridge; unit tests importing the default tools; MCP enabled in web where it is Electron-only.
Related errors
- Plugin host debug bridge is not available in this runtime.
- mutexAcquireTimeout must be a positive finite number
- initScreenCaptureForMain must be called before calling initS
- timeout must be a positive finite number
- Source with id ${request.sourceId} not found.
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/5585331b20322344.
Report an issue: GitHub.