@particle-academy/agent-integrations 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2816,6 +2816,342 @@ function attachSseRelay(server, options) {
2816
2816
  return transport;
2817
2817
  }
2818
2818
 
2819
+ // src/connectors/targets.ts
2820
+ var CLAUDE_CONNECTORS_URL = "https://claude.ai/settings/connectors";
2821
+ function encodeBase64Json(value) {
2822
+ const json = JSON.stringify(value);
2823
+ if (typeof btoa === "function") {
2824
+ return btoa(unescape(encodeURIComponent(json)));
2825
+ }
2826
+ return Buffer.from(json, "utf8").toString("base64");
2827
+ }
2828
+ function buildCursorDeeplink(server) {
2829
+ const config = encodeBase64Json({ url: server.url });
2830
+ return `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(
2831
+ server.name
2832
+ )}&config=${config}`;
2833
+ }
2834
+ function buildVscodeDeeplink(server, opts = {}) {
2835
+ const scheme = opts.insiders ? "vscode-insiders" : "vscode";
2836
+ const payload = encodeURIComponent(
2837
+ JSON.stringify({ name: server.name, url: server.url })
2838
+ );
2839
+ return `${scheme}://mcp/install?${payload}`;
2840
+ }
2841
+ function slugifyServerName(name) {
2842
+ const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
2843
+ return slug || "mcp-server";
2844
+ }
2845
+ function buildManualConfig(server) {
2846
+ return {
2847
+ mcpServers: {
2848
+ [slugifyServerName(server.name)]: {
2849
+ command: "npx",
2850
+ args: ["-y", "mcp-remote", server.url]
2851
+ }
2852
+ }
2853
+ };
2854
+ }
2855
+ function buildManualConfigSnippet(server) {
2856
+ return JSON.stringify(buildManualConfig(server), null, 2);
2857
+ }
2858
+ var CONNECTOR_TARGETS = {
2859
+ "claude-web": {
2860
+ id: "claude-web",
2861
+ label: "Add to Claude",
2862
+ mechanism: "copy-open",
2863
+ hint: "Copy the MCP URL and open Claude's Connectors page \u2014 click 'Add custom connector' and paste."
2864
+ },
2865
+ "claude-desktop": {
2866
+ id: "claude-desktop",
2867
+ label: "Claude Desktop",
2868
+ mechanism: "download",
2869
+ hint: "Download a .mcpb bundle and double-click it to install in Claude Desktop."
2870
+ },
2871
+ cursor: {
2872
+ id: "cursor",
2873
+ label: "Add to Cursor",
2874
+ mechanism: "deeplink",
2875
+ hint: "Open Cursor with this MCP server pre-filled \u2014 confirm to install."
2876
+ },
2877
+ vscode: {
2878
+ id: "vscode",
2879
+ label: "Add to VS Code",
2880
+ mechanism: "deeplink",
2881
+ hint: "Open VS Code with this MCP server pre-filled \u2014 confirm to install."
2882
+ },
2883
+ manual: {
2884
+ id: "manual",
2885
+ label: "Manual setup",
2886
+ mechanism: "snippet",
2887
+ hint: "Show a config snippet to paste into any stdio MCP client."
2888
+ }
2889
+ };
2890
+ function connectorHref(client, server, opts = {}) {
2891
+ switch (client) {
2892
+ case "cursor":
2893
+ return buildCursorDeeplink(server);
2894
+ case "vscode":
2895
+ return buildVscodeDeeplink(server, opts);
2896
+ default:
2897
+ return null;
2898
+ }
2899
+ }
2900
+ function ClaudeMark(props) {
2901
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2 L 14 10 L 22 12 L 14 14 L 12 22 L 10 14 L 2 12 L 10 10 Z" }) });
2902
+ }
2903
+ function CursorMark(props) {
2904
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 3 L 20 11 L 12 13 L 9 21 Z" }) });
2905
+ }
2906
+ function VscodeMark(props) {
2907
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 2 L 22 4.5 V 19.5 L 17 22 L 6.5 13.2 L 3 16 L 1.5 15 V 9 L 3 8 L 6.5 10.8 Z M 17 6.5 L 10 12 L 17 17.5 Z" }) });
2908
+ }
2909
+ function DesktopMark(props) {
2910
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 4 H 21 A 1 1 0 0 1 22 5 V 16 A 1 1 0 0 1 21 17 H 14 V 19 H 16 V 21 H 8 V 19 H 10 V 17 H 3 A 1 1 0 0 1 2 16 V 5 A 1 1 0 0 1 3 4 Z" }) });
2911
+ }
2912
+ function WrenchMark(props) {
2913
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 4 a 5 5 0 0 1 -6.5 6.5 L 6 19 l -3 -3 l 8.5 -8.5 A 5 5 0 0 1 17 1 l -2.5 2.5 l 1.5 3 l 3 1.5 Z" }) });
2914
+ }
2915
+ var CONNECTOR_GLYPHS = {
2916
+ "claude-web": ClaudeMark,
2917
+ "claude-desktop": DesktopMark,
2918
+ cursor: CursorMark,
2919
+ vscode: VscodeMark,
2920
+ manual: WrenchMark
2921
+ };
2922
+ var DEFAULT_CLIENTS = [
2923
+ "claude-web",
2924
+ "cursor",
2925
+ "vscode",
2926
+ "manual"
2927
+ ];
2928
+ function ConnectorButtons({
2929
+ serverName,
2930
+ mcpUrl,
2931
+ clients,
2932
+ mcpbDownloadUrl,
2933
+ claudeConnectorsUrl = CLAUDE_CONNECTORS_URL,
2934
+ vscodeInsiders,
2935
+ onCopy,
2936
+ onAction,
2937
+ labels,
2938
+ className,
2939
+ style
2940
+ }) {
2941
+ const server = { name: serverName, url: mcpUrl };
2942
+ const [copied, setCopied] = react.useState(null);
2943
+ const [manualOpen, setManualOpen] = react.useState(false);
2944
+ const manualId = react.useId();
2945
+ const list = (clients ?? defaultClients(mcpbDownloadUrl)).filter(
2946
+ (c) => c === "claude-desktop" ? !!mcpbDownloadUrl : true
2947
+ );
2948
+ const flashCopied = (target) => {
2949
+ setCopied(target);
2950
+ window.setTimeout(() => setCopied((c) => c === target ? null : c), 2e3);
2951
+ };
2952
+ const copy = async (value, target) => {
2953
+ try {
2954
+ await navigator.clipboard?.writeText(value);
2955
+ flashCopied(target);
2956
+ onCopy?.(target);
2957
+ } catch {
2958
+ }
2959
+ };
2960
+ const labelFor = (c) => labels?.[c] ?? CONNECTOR_TARGETS[c].label;
2961
+ return /* @__PURE__ */ jsxRuntime.jsx(
2962
+ "div",
2963
+ {
2964
+ className: ["fai-connect", className].filter(Boolean).join(" "),
2965
+ style,
2966
+ children: list.map((client) => {
2967
+ const meta = CONNECTOR_TARGETS[client];
2968
+ const Glyph = CONNECTOR_GLYPHS[client];
2969
+ const base = `fai-connect__btn fai-connect__btn--${client}`;
2970
+ const href = connectorHref(client, server, { insiders: vscodeInsiders });
2971
+ if (href) {
2972
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2973
+ "a",
2974
+ {
2975
+ href,
2976
+ className: base,
2977
+ title: meta.hint,
2978
+ onClick: () => onAction?.(client),
2979
+ children: [
2980
+ /* @__PURE__ */ jsxRuntime.jsx(Glyph, { className: "fai-connect__glyph" }),
2981
+ labelFor(client)
2982
+ ]
2983
+ },
2984
+ client
2985
+ );
2986
+ }
2987
+ if (client === "claude-desktop") {
2988
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2989
+ "a",
2990
+ {
2991
+ href: mcpbDownloadUrl,
2992
+ download: true,
2993
+ className: base,
2994
+ title: meta.hint,
2995
+ onClick: () => onAction?.(client),
2996
+ children: [
2997
+ /* @__PURE__ */ jsxRuntime.jsx(Glyph, { className: "fai-connect__glyph" }),
2998
+ labelFor(client)
2999
+ ]
3000
+ },
3001
+ client
3002
+ );
3003
+ }
3004
+ if (client === "claude-web") {
3005
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3006
+ "button",
3007
+ {
3008
+ type: "button",
3009
+ className: base,
3010
+ title: meta.hint,
3011
+ onClick: () => {
3012
+ void copy(mcpUrl, client);
3013
+ window.open(
3014
+ claudeConnectorsUrl,
3015
+ "_blank",
3016
+ "noopener,noreferrer"
3017
+ );
3018
+ onAction?.(client);
3019
+ },
3020
+ children: [
3021
+ /* @__PURE__ */ jsxRuntime.jsx(Glyph, { className: "fai-connect__glyph" }),
3022
+ copied === client ? "Copied \u2014 paste in Claude" : labelFor(client)
3023
+ ]
3024
+ },
3025
+ client
3026
+ );
3027
+ }
3028
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fai-connect__manual-wrap", children: [
3029
+ /* @__PURE__ */ jsxRuntime.jsxs(
3030
+ "button",
3031
+ {
3032
+ type: "button",
3033
+ className: base,
3034
+ title: meta.hint,
3035
+ "aria-expanded": manualOpen,
3036
+ "aria-controls": manualId,
3037
+ onClick: () => {
3038
+ setManualOpen((o) => !o);
3039
+ onAction?.(client);
3040
+ },
3041
+ children: [
3042
+ /* @__PURE__ */ jsxRuntime.jsx(Glyph, { className: "fai-connect__glyph" }),
3043
+ labelFor(client)
3044
+ ]
3045
+ }
3046
+ ),
3047
+ manualOpen && /* @__PURE__ */ jsxRuntime.jsx(
3048
+ ManualPopover,
3049
+ {
3050
+ id: manualId,
3051
+ snippet: buildManualConfigSnippet(server),
3052
+ copied: copied === client,
3053
+ onCopy: () => copy(buildManualConfigSnippet(server), client),
3054
+ onClose: () => setManualOpen(false)
3055
+ }
3056
+ )
3057
+ ] }, client);
3058
+ })
3059
+ }
3060
+ );
3061
+ }
3062
+ function defaultClients(mcpbDownloadUrl) {
3063
+ return mcpbDownloadUrl ? ["claude-web", "claude-desktop", "cursor", "vscode", "manual"] : DEFAULT_CLIENTS;
3064
+ }
3065
+ function ManualPopover({
3066
+ id,
3067
+ snippet,
3068
+ copied,
3069
+ onCopy,
3070
+ onClose
3071
+ }) {
3072
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id, className: "fai-connect__popover", role: "dialog", children: [
3073
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fai-connect__popover-head", children: [
3074
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Add to any stdio MCP client" }),
3075
+ /* @__PURE__ */ jsxRuntime.jsx(
3076
+ "button",
3077
+ {
3078
+ type: "button",
3079
+ className: "fai-connect__popover-close",
3080
+ "aria-label": "Close",
3081
+ onClick: onClose,
3082
+ children: "\xD7"
3083
+ }
3084
+ )
3085
+ ] }),
3086
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "fai-connect__popover-hint", children: [
3087
+ "Paste into ",
3088
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: "claude_desktop_config.json" }),
3089
+ " (or any stdio MCP client config). Needs Node 18+."
3090
+ ] }),
3091
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "fai-connect__snippet", children: snippet }),
3092
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "fai-connect__copy-btn", onClick: onCopy, children: copied ? "Copied" : "Copy snippet" })
3093
+ ] });
3094
+ }
3095
+
3096
+ // src/connectors/mcpb.ts
3097
+ var MCPB_MANIFEST_VERSION = "0.2";
3098
+ var MCPB_MIN_NODE = ">=18.0.0";
3099
+ var DEFAULT_MCPB_ENTRY_POINT = "server/proxy.js";
3100
+ function buildMcpbManifest(input) {
3101
+ const entryPoint = input.entryPoint ?? DEFAULT_MCPB_ENTRY_POINT;
3102
+ return {
3103
+ manifest_version: MCPB_MANIFEST_VERSION,
3104
+ name: input.name,
3105
+ display_name: input.display_name ?? input.name,
3106
+ version: input.version,
3107
+ description: input.description,
3108
+ ...input.long_description ? { long_description: input.long_description } : {},
3109
+ author: input.author,
3110
+ ...input.homepage ? { homepage: input.homepage } : {},
3111
+ ...input.documentation ? { documentation: input.documentation } : {},
3112
+ ...input.support ? { support: input.support } : {},
3113
+ server: {
3114
+ type: "node",
3115
+ entry_point: entryPoint,
3116
+ mcp_config: {
3117
+ command: "npx",
3118
+ args: ["-y", "mcp-remote", input.mcpUrl]
3119
+ }
3120
+ },
3121
+ tools: input.tools ?? [],
3122
+ tools_generated: false,
3123
+ prompts_generated: false,
3124
+ ...input.keywords ? { keywords: input.keywords } : {},
3125
+ license: input.license ?? "MIT",
3126
+ compatibility: {
3127
+ claude_desktop: ">=0.10.0",
3128
+ platforms: ["darwin", "win32", "linux"],
3129
+ runtimes: { node: MCPB_MIN_NODE }
3130
+ }
3131
+ };
3132
+ }
3133
+ function buildMcpbProxyStub(mcpUrl) {
3134
+ const urlLiteral = JSON.stringify(mcpUrl);
3135
+ return `#!/usr/bin/env node
3136
+ // MCPB proxy shim (generated by @particle-academy/agent-integrations).
3137
+ //
3138
+ // MCPB (Claude Desktop Extensions) only supports local stdio servers, but this
3139
+ // MCP server is a remote HTTP endpoint. The manifest's \`mcp_config\` invokes
3140
+ // \`npx -y mcp-remote <url>\` to bridge the gap \u2014 this file is the entry_point
3141
+ // fallback the manifest validator requires. If you're seeing this run,
3142
+ // mcp_config wasn't honored; spawn mcp-remote directly so the bundle still works.
3143
+
3144
+ const { spawn } = require("node:child_process");
3145
+
3146
+ const url = ${urlLiteral};
3147
+ const child = spawn("npx", ["-y", "mcp-remote", url], { stdio: "inherit" });
3148
+
3149
+ child.on("exit", (code) => process.exit(code ?? 0));
3150
+ process.on("SIGINT", () => child.kill("SIGINT"));
3151
+ process.on("SIGTERM", () => child.kill("SIGTERM"));
3152
+ `;
3153
+ }
3154
+
2819
3155
  Object.defineProperty(exports, "clearUndoStack", {
2820
3156
  enumerable: true,
2821
3157
  get: function () { return fancyAutoCommon.clearStack; }
@@ -2860,7 +3196,17 @@ exports.AgentActivityHighlight = AgentActivityHighlight;
2860
3196
  exports.AgentCursor = AgentCursor;
2861
3197
  exports.AgentPanel = AgentPanel;
2862
3198
  exports.BridgedForm = BridgedForm;
3199
+ exports.CLAUDE_CONNECTORS_URL = CLAUDE_CONNECTORS_URL;
3200
+ exports.CONNECTOR_GLYPHS = CONNECTOR_GLYPHS;
3201
+ exports.CONNECTOR_TARGETS = CONNECTOR_TARGETS;
3202
+ exports.ClaudeMark = ClaudeMark;
3203
+ exports.ConnectorButtons = ConnectorButtons;
3204
+ exports.CursorMark = CursorMark;
3205
+ exports.DEFAULT_MCPB_ENTRY_POINT = DEFAULT_MCPB_ENTRY_POINT;
3206
+ exports.DesktopMark = DesktopMark;
2863
3207
  exports.InProcessTransport = InProcessTransport;
3208
+ exports.MCPB_MANIFEST_VERSION = MCPB_MANIFEST_VERSION;
3209
+ exports.MCPB_MIN_NODE = MCPB_MIN_NODE;
2864
3210
  exports.MCP_PROTOCOL_VERSION = MCP_PROTOCOL_VERSION;
2865
3211
  exports.MicroMcpServer = MicroMcpServer;
2866
3212
  exports.RelayTransport = RelayTransport;
@@ -2868,13 +3214,23 @@ exports.ScreensActivityBridge = ScreensActivityBridge;
2868
3214
  exports.ShareControls = ShareControls;
2869
3215
  exports.SseRelayTransport = SseRelayTransport;
2870
3216
  exports.ToolRegistry = ToolRegistry;
3217
+ exports.VscodeMark = VscodeMark;
3218
+ exports.WrenchMark = WrenchMark;
2871
3219
  exports.attachInProcess = attachInProcess;
2872
3220
  exports.attachRelay = attachRelay;
2873
3221
  exports.attachSseRelay = attachSseRelay;
3222
+ exports.buildCursorDeeplink = buildCursorDeeplink;
3223
+ exports.buildManualConfig = buildManualConfig;
3224
+ exports.buildManualConfigSnippet = buildManualConfigSnippet;
3225
+ exports.buildMcpbManifest = buildMcpbManifest;
3226
+ exports.buildMcpbProxyStub = buildMcpbProxyStub;
2874
3227
  exports.buildShareConfig = buildShareConfig;
2875
3228
  exports.buildShareUrl = buildShareUrl;
3229
+ exports.buildVscodeDeeplink = buildVscodeDeeplink;
3230
+ exports.connectorHref = connectorHref;
2876
3231
  exports.createSessionDescriptor = createSessionDescriptor;
2877
3232
  exports.describeSession = describeSession;
3233
+ exports.encodeBase64Json = encodeBase64Json;
2878
3234
  exports.ensureUndoToolsRegistered = ensureUndoToolsRegistered;
2879
3235
  exports.errorResult = errorResult;
2880
3236
  exports.readSessionFromUrl = readSessionFromUrl;
@@ -2888,6 +3244,7 @@ exports.registerSlidesBridge = registerSlidesBridge;
2888
3244
  exports.registerTerminalBridge = registerTerminalBridge;
2889
3245
  exports.registerUndoTools = registerUndoTools;
2890
3246
  exports.rpcError = rpcError;
3247
+ exports.slugifyServerName = slugifyServerName;
2891
3248
  exports.textResult = textResult;
2892
3249
  exports.useAgentActivity = useAgentActivity;
2893
3250
  exports.useAgentActivityForScreen = useAgentActivityForScreen;