{"version":3,"sources":["../src/connectors/mcpb.ts","../src/connectors/build.ts"],"names":["path","mkdtemp","tmpdir","writeFile","mkdir","stat","rm","spawn"],"mappings":"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","file":"connectors-build.cjs","sourcesContent":["// MCPB (Claude Desktop \"Extensions\" bundle) manifest + proxy generation.\n//\n// PURE — no filesystem, no child_process — so it's trivially testable. The\n// `writeMcpbBundle` Node helper (./build) layers fs + the official mcpb CLI on\n// top of these.\n//\n// The hard fact MCPB forces on you: it is STDIO-ONLY. The manifest's\n// `server.type` is one of `node` / `python` / `binary` / `uv` — there is no\n// `type: \"http\"`. So to bundle a REMOTE MCP server (what fancy-* apps almost\n// always are) you ship a thin `node` server whose `mcp_config` runs\n// `npx -y mcp-remote <url>`, bridging stdio→HTTP. The manifest validator still\n// requires `entry_point`, so an (otherwise unused) proxy stub is emitted too.\n//\n// Future-proof: when MCPB grows a real `type: \"http\"`, drop the proxy and point\n// straight at the URL — the call site here doesn't change.\n\n/** The MCPB manifest schema version this helper emits. */\nexport const MCPB_MANIFEST_VERSION = \"0.2\";\n\n/** Minimum Node the mcp-remote proxy needs on the user's machine. */\nexport const MCPB_MIN_NODE = \">=18.0.0\";\n\n/** A tool advertised in the bundle manifest (display-only metadata). */\nexport interface McpbTool {\n  name: string;\n  description?: string;\n}\n\n/** Inputs for {@link buildMcpbManifest} / `writeMcpbBundle`. */\nexport interface McpbManifestInput {\n  /** Machine name, e.g. `\"decksmith\"` (lowercase, no spaces). */\n  name: string;\n  /** Human display name, e.g. `\"Decksmith\"`. Defaults to `name`. */\n  display_name?: string;\n  /** Bundle version, e.g. `\"0.2.0\"`. */\n  version: string;\n  /** Short one-line description. */\n  description: string;\n  /** Optional longer description shown on the extension's detail view. */\n  long_description?: string;\n  author: { name: string; url?: string; email?: string };\n  homepage?: string;\n  documentation?: string;\n  support?: string;\n  /** The remote MCP endpoint the bundle proxies to. */\n  mcpUrl: string;\n  /** Advertised tools (display metadata only). */\n  tools?: McpbTool[];\n  keywords?: string[];\n  license?: string;\n  /** Entry-point path inside the bundle. Defaults to `\"server/proxy.js\"`. */\n  entryPoint?: string;\n}\n\n/** The default entry-point path the proxy stub is written to. */\nexport const DEFAULT_MCPB_ENTRY_POINT = \"server/proxy.js\";\n\n/**\n * Build the full MCPB `manifest.json` object for a remote MCP server, wrapping\n * it with `npx -y mcp-remote <url>` (stdio→HTTP). Returns a plain object ready\n * to `JSON.stringify`.\n */\nexport function buildMcpbManifest(\n  input: McpbManifestInput,\n): Record<string, unknown> {\n  const entryPoint = input.entryPoint ?? DEFAULT_MCPB_ENTRY_POINT;\n  return {\n    manifest_version: MCPB_MANIFEST_VERSION,\n    name: input.name,\n    display_name: input.display_name ?? input.name,\n    version: input.version,\n    description: input.description,\n    ...(input.long_description\n      ? { long_description: input.long_description }\n      : {}),\n    author: input.author,\n    ...(input.homepage ? { homepage: input.homepage } : {}),\n    ...(input.documentation ? { documentation: input.documentation } : {}),\n    ...(input.support ? { support: input.support } : {}),\n    server: {\n      type: \"node\",\n      entry_point: entryPoint,\n      mcp_config: {\n        command: \"npx\",\n        args: [\"-y\", \"mcp-remote\", input.mcpUrl],\n      },\n    },\n    tools: input.tools ?? [],\n    tools_generated: false,\n    prompts_generated: false,\n    ...(input.keywords ? { keywords: input.keywords } : {}),\n    license: input.license ?? \"MIT\",\n    compatibility: {\n      claude_desktop: \">=0.10.0\",\n      platforms: [\"darwin\", \"win32\", \"linux\"],\n      runtimes: { node: MCPB_MIN_NODE },\n    },\n  };\n}\n\n/**\n * The `server/proxy.js` stub. MCPB requires an `entry_point` file even though\n * `mcp_config.command` overrides it; if it ever DOES run, it spawns\n * `npx -y mcp-remote <url>` itself so the bundle still works.\n */\nexport function buildMcpbProxyStub(mcpUrl: string): string {\n  // JSON.stringify gives us a safely-quoted JS string literal for the URL.\n  const urlLiteral = JSON.stringify(mcpUrl);\n  return `#!/usr/bin/env node\n// MCPB proxy shim (generated by @particle-academy/agent-integrations).\n//\n// MCPB (Claude Desktop Extensions) only supports local stdio servers, but this\n// MCP server is a remote HTTP endpoint. The manifest's \\`mcp_config\\` invokes\n// \\`npx -y mcp-remote <url>\\` to bridge the gap — this file is the entry_point\n// fallback the manifest validator requires. If you're seeing this run,\n// mcp_config wasn't honored; spawn mcp-remote directly so the bundle still works.\n\nconst { spawn } = require(\"node:child_process\");\n\nconst url = ${urlLiteral};\nconst child = spawn(\"npx\", [\"-y\", \"mcp-remote\", url], { stdio: \"inherit\" });\n\nchild.on(\"exit\", (code) => process.exit(code ?? 0));\nprocess.on(\"SIGINT\", () => child.kill(\"SIGINT\"));\nprocess.on(\"SIGTERM\", () => child.kill(\"SIGTERM\"));\n`;\n}\n","// Node-only build helper: generate + pack a `.mcpb` bundle for a remote MCP\n// server. Imported from `@particle-academy/agent-integrations/connectors/build`\n// at BUILD time (a CI step / a `scripts/build-mcpb.mjs`), never from browser\n// code — it touches fs + shells out to the official mcpb CLI.\n\nimport { spawn } from \"node:child_process\";\nimport { mkdtemp, writeFile, mkdir, rm, stat } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport {\n  buildMcpbManifest,\n  buildMcpbProxyStub,\n  DEFAULT_MCPB_ENTRY_POINT,\n  type McpbManifestInput,\n} from \"./mcpb\";\n\nexport type { McpbManifestInput, McpbTool } from \"./mcpb\";\n\nexport interface WriteMcpbBundleOptions {\n  /** Where to write the packed `.mcpb` (absolute or cwd-relative). */\n  outFile: string;\n  /** The manifest inputs (server name, version, mcpUrl, tools, …). */\n  manifest: McpbManifestInput;\n  /**\n   * The mcpb CLI to shell out to. Default: `[\"npx\", \"-y\", \"@anthropic-ai/mcpb\"]`.\n   * Pass a locally-installed binary path (string) or argv (array) to avoid the\n   * npx network fetch.\n   */\n  mcpbBin?: string | string[];\n  /** Run `mcpb validate` before packing. Default true. */\n  validate?: boolean;\n  /** Keep the temp work dir instead of removing it (debugging). Default false. */\n  keepWorkDir?: boolean;\n  /** Working directory the CLI runs in. Default `process.cwd()`. */\n  cwd?: string;\n}\n\nexport interface WriteMcpbBundleResult {\n  /** Absolute path to the written `.mcpb`. */\n  outFile: string;\n  /** Size of the written bundle in bytes. */\n  bytes: number;\n  /** The manifest object that was packed. */\n  manifest: Record<string, unknown>;\n  /** The work dir used (returned even after cleanup, for logging). */\n  workDir: string;\n}\n\n/**\n * Generate a `manifest.json` + `server/proxy.js` for a remote MCP server, then\n * validate and pack them into a `.mcpb` using the official `@anthropic-ai/mcpb`\n * CLI. Returns the output path + size.\n *\n * ```ts\n * import { writeMcpbBundle } from \"@particle-academy/agent-integrations/connectors/build\";\n *\n * await writeMcpbBundle({\n *   outFile: \"public/decksmith.mcpb\",\n *   manifest: {\n *     name: \"decksmith\",\n *     display_name: \"Decksmith\",\n *     version: \"0.2.0\",\n *     description: \"Agent-driven slide deck builder.\",\n *     author: { name: \"Particle Academy\", url: \"https://decksmith.dev\" },\n *     mcpUrl: \"https://decksmith.dev/mcp\",\n *     tools: [{ name: \"start_session\", description: \"…\" }],\n *   },\n * });\n * ```\n */\nexport async function writeMcpbBundle(\n  opts: WriteMcpbBundleOptions,\n): Promise<WriteMcpbBundleResult> {\n  const cwd = opts.cwd ?? process.cwd();\n  const outFile = path.resolve(cwd, opts.outFile);\n  const validate = opts.validate ?? true;\n  const entryPoint = opts.manifest.entryPoint ?? DEFAULT_MCPB_ENTRY_POINT;\n\n  const manifest = buildMcpbManifest(opts.manifest);\n  const proxy = buildMcpbProxyStub(opts.manifest.mcpUrl);\n\n  const workDir = await mkdtemp(path.join(tmpdir(), \"fai-mcpb-\"));\n  try {\n    // Lay out the bundle source: manifest.json + the entry-point stub.\n    await writeFile(\n      path.join(workDir, \"manifest.json\"),\n      JSON.stringify(manifest, null, 2),\n      \"utf8\",\n    );\n    const entryAbs = path.join(workDir, entryPoint);\n    await mkdir(path.dirname(entryAbs), { recursive: true });\n    await writeFile(entryAbs, proxy, \"utf8\");\n\n    // Ensure the output dir exists.\n    await mkdir(path.dirname(outFile), { recursive: true });\n\n    const bin = normalizeBin(opts.mcpbBin);\n    if (validate) {\n      await run(bin, [\"validate\", \"manifest.json\"], workDir);\n    }\n    await run(bin, [\"pack\", workDir, outFile], cwd);\n\n    const bytes = (await stat(outFile)).size;\n    return { outFile, bytes, manifest, workDir };\n  } finally {\n    if (!opts.keepWorkDir) {\n      await rm(workDir, { recursive: true, force: true }).catch(() => {});\n    }\n  }\n}\n\nfunction normalizeBin(bin: string | string[] | undefined): string[] {\n  if (!bin) return [\"npx\", \"-y\", \"@anthropic-ai/mcpb\"];\n  return Array.isArray(bin) ? bin : [bin];\n}\n\n/** Spawn `[cmd, ...args]`, inheriting stdio, rejecting on a non-zero exit. */\nfunction run(bin: string[], args: string[], cwd: string): Promise<void> {\n  const [cmd, ...binArgs] = bin;\n  const argv = [...binArgs, ...args];\n  return new Promise((resolve, reject) => {\n    const child = spawn(cmd, argv, {\n      cwd,\n      stdio: \"inherit\",\n      shell: process.platform === \"win32\", // npx resolves via .cmd on Windows\n    });\n    child.on(\"error\", reject);\n    child.on(\"exit\", (code) => {\n      if (code === 0) resolve();\n      else\n        reject(\n          new Error(`${cmd} ${argv.join(\" \")} exited with code ${code ?? \"null\"}`),\n        );\n    });\n  });\n}\n"]}