{"record":{"id":"6e55a2849949e81d","repo":"decolua/9router","slug":"unknown-local-plugin-name","errorCode":null,"errorMessage":"Unknown local plugin: ${name}","messagePattern":"Unknown local plugin: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/lib/mcp/stdioSseBridge.js","lineNumber":115,"sourceCode":"  } catch { return line; }\n}\nconst getStore = () => {\n  if (!globalThis[G_KEY]) globalThis[G_KEY] = new Map();\n  return globalThis[G_KEY];\n};\n\n// Only preset stdio plugins may spawn. No user-defined commands (RCE prevention).\nfunction findPlugin(name) {\n  return LOCAL_STDIO_PLUGINS.find((p) => p.name === name) || null;\n}\n\nfunction getOrSpawn(name) {\n  const store = getStore();\n  let entry = store.get(name);\n  if (entry?.proc && !entry.proc.killed && entry.proc.exitCode === null) return entry;\n\n  const plugin = findPlugin(name);\n  if (!plugin) throw new Error(`Unknown local plugin: ${name}`);\n\n  const proc = spawn(plugin.command, plugin.args, { stdio: [\"pipe\", \"pipe\", \"pipe\"], env: process.env });\n  entry = { proc, sessions: new Map(), buffer: \"\" };\n  store.set(name, entry);\n\n  // Parse newline-delimited JSON-RPC from child stdout, broadcast to all sessions.\n  proc.stdout.on(\"data\", (chunk) => {\n    entry.buffer += chunk.toString(\"utf8\");\n    let idx;\n    while ((idx = entry.buffer.indexOf(\"\\n\")) >= 0) {\n      const raw = entry.buffer.slice(0, idx).trim();\n      entry.buffer = entry.buffer.slice(idx + 1);\n      if (!raw) continue;\n      const line = filterFrame(raw);\n      for (const send of entry.sessions.values()) {\n        try { send(`event: message\\ndata: ${line}\\n\\n`); } catch { /* ignore broken pipe */ }\n      }\n    }","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/mcp/stdioSseBridge.js#L97-L133","documentation":"getOrSpawn resolves a local (stdio) MCP plugin by name from the plugin registry and spawns a child process bridge for it. If no plugin with that name is registered, it throws — the bridge cannot know what command to run.","triggerScenarios":"Requesting a stdio→SSE bridge via getOrSpawn/entry with a plugin name that is absent from the configured local plugin list (typo, plugin removed from config, plugin only defined as remote/HTTP, or config not loaded).","commonSituations":"Typo in the MCP server name in client config (e.g. \"filesystems\" vs \"filesystem\"); the plugin was uninstalled or removed from the MCP config but the client still references it; the plugin is a remote/SSE server, not a local stdio one, so findPlugin (local-only) never sees it.","solutions":["Check the exact plugin name in your MCP client config against the names in the app's local plugin registry/config and fix the typo.","Install or re-add the missing local plugin to the MCP configuration, then retry.","If the server is remote (HTTP/SSE), connect to it directly instead of through the stdio bridge.","Verify the config file the bridge loads actually contains the plugin (the registry may be loaded from a different profile/path)."],"exampleFix":"// before: mcp config references unknown plugin\n{ \"mcpServers\": { \"puppetter\": { \"command\": \"npx\", \"args\": [\"-y\", \"puppeteer\"] } } }\n// after: corrected name matching the registry\n{ \"mcpServers\": { \"puppeteer\": { \"command\": \"npx\", \"args\": [\"-y\", \"puppeteer\"] } } }","handlingStrategy":"validation","validationCode":"const registry = listLocalPlugins(); // whatever the bridge exposes\nif (!registry.some(p => p.name === requestedName)) {\n  return { error: `Local MCP plugin \"${requestedName}\" is not configured` };\n}\nconst entry = getOrSpawn(requestedName);","typeGuard":null,"tryCatchPattern":"let entry;\ntry {\n  entry = getOrSpawn(name);\n} catch (err) {\n  if (err.message.startsWith(\"Unknown local plugin:\")) {\n    return res.status(404).json({ error: `Unknown MCP server \"${name}\"; check mcp config` });\n  }\n  throw err;\n}","preventionTips":["Copy MCP server names from the config file rather than typing them.","Keep client MCP config and the app's local plugin registry in sync after add/remove operations.","Remember the bridge only handles local stdio plugins — remote SSE servers need a different connection path."],"tags":["mcp","configuration","plugin-not-found"],"backgroundTag":"unknown-plugin-name","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}