@fabricorg/sdk-mcp 0.1.0 → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TechFabric LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs CHANGED
@@ -77,7 +77,9 @@ function createFabricMcpServer(options) {
77
77
  try {
78
78
  const ops = yield (_a2 = integration.call) == null ? void 0 : _a2.call(integration, "__operations");
79
79
  return {
80
- content: [{ type: "text", text: JSON.stringify(ops, null, 2) }]
80
+ content: [
81
+ { type: "text", text: JSON.stringify(ops, null, 2) }
82
+ ]
81
83
  };
82
84
  } catch (e) {
83
85
  return {
@@ -122,7 +124,9 @@ function createFabricMcpServer(options) {
122
124
  try {
123
125
  const result = yield integration.call(operation, args != null ? args : {});
124
126
  return {
125
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
127
+ content: [
128
+ { type: "text", text: JSON.stringify(result, null, 2) }
129
+ ]
126
130
  };
127
131
  } catch (err) {
128
132
  const message = err instanceof Error ? err.message : String(err);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["McpServer","z","_a"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @fabricorg/sdk-mcp\n *\n * Builds an MCP (Model Context Protocol) server that exposes a Fabric\n * workspace's whole integration catalog as MCP tools — any MCP-compatible\n * agent (Claude Desktop, Cursor, Continue, OpenAI agents, …) can point at\n * one endpoint and get every connected vendor.\n *\n * Three generic tools (corsair-style):\n * - `fabric_list_integrations` — what's connected for this tenant\n * - `fabric_list_operations` — endpoints for one integration\n * - `fabric_call` — execute an operation\n *\n * Usage (stdio transport, e.g. Claude Desktop):\n * import { createFabricMcpServer } from \"@fabricorg/sdk-mcp\";\n * import { createFabric } from \"@fabricorg/sdk\";\n * import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n *\n * const fabric = createFabric({ apiKey: process.env.FABRIC_API_KEY });\n * const server = createFabricMcpServer({ fabric });\n * await server.connect(new StdioServerTransport());\n *\n * Or use the prebuilt stdio entry: `import \"@fabricorg/sdk-mcp/stdio\";`\n * (The `fabric mcp serve` CLI command is the recommended user-facing path.)\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\n// Avoid importing @fabricorg/sdk concrete types at runtime; we only need its\n// shape so the server is decoupled from a specific SDK version. Consumers\n// pass an `FabricClient` instance.\ntype FabricLike = {\n\tintegrations: {\n\t\tlist(): Promise<\n\t\t\tArray<{\n\t\t\t\tslug: string;\n\t\t\t\tname: string;\n\t\t\t\tstatus: string;\n\t\t\t\tmode: string;\n\t\t\t\tsource: string;\n\t\t\t}>\n\t\t>;\n\t\t[slug: string]: unknown;\n\t};\n};\n\nexport interface CreateFabricMcpServerOptions {\n\t/** A configured FabricClient (createFabric) instance. Required. */\n\tfabric: FabricLike;\n\t/** Server name reported on the MCP handshake. Default `\"fabric\"`. */\n\tname?: string;\n\t/** Server version. Default `\"0.1.0\"`. */\n\tversion?: string;\n}\n\n/**\n * Build a configured `McpServer` exposing the workspace catalog. Caller is\n * responsible for `.connect(transport)` so the same server works over stdio,\n * HTTP, or any other MCP transport.\n */\nexport function createFabricMcpServer(\n\toptions: CreateFabricMcpServerOptions,\n): McpServer {\n\tconst fabric = options.fabric;\n\tconst server = new McpServer({\n\t\tname: options.name ?? \"fabric\",\n\t\tversion: options.version ?? \"0.1.0\",\n\t});\n\n\tserver.registerTool(\n\t\t\"fabric_list_integrations\",\n\t\t{\n\t\t\ttitle: \"List Fabric Integrations\",\n\t\t\tdescription:\n\t\t\t\t\"List integrations connected for the authenticated Fabric workspace. \" +\n\t\t\t\t\"Returns slug, display name, current connection status, permission mode \" +\n\t\t\t\t\"(open/cautious/strict/readonly), and source (plugin/mcp-server/connector).\",\n\t\t\tinputSchema: {},\n\t\t},\n\t\tasync () => {\n\t\t\tconst integrations = await fabric.integrations.list();\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: JSON.stringify(integrations, null, 2),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_list_operations\",\n\t\t{\n\t\t\ttitle: \"List Operations for an Integration\",\n\t\t\tdescription:\n\t\t\t\t\"List the dot-notation operations available on a single Fabric integration. \" +\n\t\t\t\t\"Returns an array of `{ operation, riskLevel, description }`. Supply the \" +\n\t\t\t\t\"slug from `fabric_list_integrations`.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Integration slug, e.g. \\\"slack\\\", \\\"github\\\", \\\"linear\\\".\",\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug }) => {\n\t\t\t// Endpoint metadata isn't exposed via the SDK's HTTP surface yet, so we\n\t\t\t// hit a known introspection path the portal returns under\n\t\t\t// `/integrations/:slug/operations`. Until that route lands, we surface a\n\t\t\t// helpful TODO so agents don't silently get an empty list.\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// Best-effort: the portal may expose `__operations` as a\n\t\t\t\t// magic operation that returns the catalog.\n\t\t\t\tconst ops = await integration.call?.(\"__operations\");\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify(ops, null, 2) }],\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Operation listing for \"${slug}\" requires portal endpoint /api/v1/integrations/${slug}/operations (not yet exposed). Use fabric_call with a known operation path in the meantime.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_call\",\n\t\t{\n\t\t\ttitle: \"Call a Fabric Integration Operation\",\n\t\t\tdescription:\n\t\t\t\t\"Execute an operation on a connected Fabric integration. Args is a JSON \" +\n\t\t\t\t\"object whose shape depends on the specific operation. Returns the \" +\n\t\t\t\t\"upstream response, or { status: 'pending_approval' | 'denied' } when \" +\n\t\t\t\t\"the workspace permission policy gates the call.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\"Integration slug, e.g. \\\"slack\\\".\"),\n\t\t\t\toperation: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Dot-notation operation, e.g. \\\"messages.send\\\" or \\\"channels.list\\\".\",\n\t\t\t\t\t),\n\t\t\t\targs: z\n\t\t\t\t\t.record(z.string(), z.unknown())\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Arguments object. Shape depends on the operation.\",\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug, operation, args }) => {\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration?.call) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst result = await integration.call(operation, args ?? {});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Error: ${message}` }],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\treturn server;\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["McpServer","z","_a"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @fabricorg/sdk-mcp\n *\n * Builds an MCP (Model Context Protocol) server that exposes a Fabric\n * workspace's whole integration catalog as MCP tools — any MCP-compatible\n * agent (Claude Desktop, Cursor, Continue, OpenAI agents, …) can point at\n * one endpoint and get every connected vendor.\n *\n * Three generic tools (corsair-style):\n * - `fabric_list_integrations` — what's connected for this tenant\n * - `fabric_list_operations` — endpoints for one integration\n * - `fabric_call` — execute an operation\n *\n * Usage (stdio transport, e.g. Claude Desktop):\n * import { createFabricMcpServer } from \"@fabricorg/sdk-mcp\";\n * import { createFabric } from \"@fabricorg/sdk\";\n * import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n *\n * const fabric = createFabric({ apiKey: process.env.FABRIC_API_KEY });\n * const server = createFabricMcpServer({ fabric });\n * await server.connect(new StdioServerTransport());\n *\n * Or use the prebuilt stdio entry: `import \"@fabricorg/sdk-mcp/stdio\";`\n * (The `fabric mcp serve` CLI command is the recommended user-facing path.)\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\n// Avoid importing @fabricorg/sdk concrete types at runtime; we only need its\n// shape so the server is decoupled from a specific SDK version. Consumers\n// pass an `FabricClient` instance.\ntype FabricLike = {\n\tintegrations: {\n\t\tlist(): Promise<\n\t\t\tArray<{\n\t\t\t\tslug: string;\n\t\t\t\tname: string;\n\t\t\t\tstatus: string;\n\t\t\t\tmode: string;\n\t\t\t\tsource: string;\n\t\t\t}>\n\t\t>;\n\t\t[slug: string]: unknown;\n\t};\n};\n\nexport interface CreateFabricMcpServerOptions {\n\t/** A configured FabricClient (createFabric) instance. Required. */\n\tfabric: FabricLike;\n\t/** Server name reported on the MCP handshake. Default `\"fabric\"`. */\n\tname?: string;\n\t/** Server version. Default `\"0.1.0\"`. */\n\tversion?: string;\n}\n\n/**\n * Build a configured `McpServer` exposing the workspace catalog. Caller is\n * responsible for `.connect(transport)` so the same server works over stdio,\n * HTTP, or any other MCP transport.\n */\nexport function createFabricMcpServer(\n\toptions: CreateFabricMcpServerOptions,\n): McpServer {\n\tconst fabric = options.fabric;\n\tconst server = new McpServer({\n\t\tname: options.name ?? \"fabric\",\n\t\tversion: options.version ?? \"0.1.0\",\n\t});\n\n\tserver.registerTool(\n\t\t\"fabric_list_integrations\",\n\t\t{\n\t\t\ttitle: \"List Fabric Integrations\",\n\t\t\tdescription:\n\t\t\t\t\"List integrations connected for the authenticated Fabric workspace. \" +\n\t\t\t\t\"Returns slug, display name, current connection status, permission mode \" +\n\t\t\t\t\"(open/cautious/strict/readonly), and source (plugin/mcp-server/connector).\",\n\t\t\tinputSchema: {},\n\t\t},\n\t\tasync () => {\n\t\t\tconst integrations = await fabric.integrations.list();\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: JSON.stringify(integrations, null, 2),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_list_operations\",\n\t\t{\n\t\t\ttitle: \"List Operations for an Integration\",\n\t\t\tdescription:\n\t\t\t\t\"List the dot-notation operations available on a single Fabric integration. \" +\n\t\t\t\t\"Returns an array of `{ operation, riskLevel, description }`. Supply the \" +\n\t\t\t\t\"slug from `fabric_list_integrations`.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t'Integration slug, e.g. \"slack\", \"github\", \"linear\".',\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug }) => {\n\t\t\t// Endpoint metadata isn't exposed via the SDK's HTTP surface yet, so we\n\t\t\t// hit a known introspection path the portal returns under\n\t\t\t// `/integrations/:slug/operations`. Until that route lands, we surface a\n\t\t\t// helpful TODO so agents don't silently get an empty list.\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// Best-effort: the portal may expose `__operations` as a\n\t\t\t\t// magic operation that returns the catalog.\n\t\t\t\tconst ops = await integration.call?.(\"__operations\");\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{ type: \"text\", text: JSON.stringify(ops, null, 2) },\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Operation listing for \"${slug}\" requires portal endpoint /api/v1/integrations/${slug}/operations (not yet exposed). Use fabric_call with a known operation path in the meantime.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_call\",\n\t\t{\n\t\t\ttitle: \"Call a Fabric Integration Operation\",\n\t\t\tdescription:\n\t\t\t\t\"Execute an operation on a connected Fabric integration. Args is a JSON \" +\n\t\t\t\t\"object whose shape depends on the specific operation. Returns the \" +\n\t\t\t\t\"upstream response, or { status: 'pending_approval' | 'denied' } when \" +\n\t\t\t\t\"the workspace permission policy gates the call.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z.string().describe('Integration slug, e.g. \"slack\".'),\n\t\t\t\toperation: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t'Dot-notation operation, e.g. \"messages.send\" or \"channels.list\".',\n\t\t\t\t\t),\n\t\t\t\targs: z\n\t\t\t\t\t.record(z.string(), z.unknown())\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Arguments object. Shape depends on the operation.\",\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug, operation, args }) => {\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration?.call) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst result = await integration.call(operation, args ?? {});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{ type: \"text\", text: JSON.stringify(result, null, 2) },\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\tconst message =\n\t\t\t\t\terr instanceof Error ? err.message : String(err);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Error: ${message}` }],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\treturn server;\n}\n"]}
package/dist/index.js CHANGED
@@ -75,7 +75,9 @@ function createFabricMcpServer(options) {
75
75
  try {
76
76
  const ops = yield (_a2 = integration.call) == null ? void 0 : _a2.call(integration, "__operations");
77
77
  return {
78
- content: [{ type: "text", text: JSON.stringify(ops, null, 2) }]
78
+ content: [
79
+ { type: "text", text: JSON.stringify(ops, null, 2) }
80
+ ]
79
81
  };
80
82
  } catch (e) {
81
83
  return {
@@ -120,7 +122,9 @@ function createFabricMcpServer(options) {
120
122
  try {
121
123
  const result = yield integration.call(operation, args != null ? args : {});
122
124
  return {
123
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
125
+ content: [
126
+ { type: "text", text: JSON.stringify(result, null, 2) }
127
+ ]
124
128
  };
125
129
  } catch (err) {
126
130
  const message = err instanceof Error ? err.message : String(err);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["_a"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @fabricorg/sdk-mcp\n *\n * Builds an MCP (Model Context Protocol) server that exposes a Fabric\n * workspace's whole integration catalog as MCP tools — any MCP-compatible\n * agent (Claude Desktop, Cursor, Continue, OpenAI agents, …) can point at\n * one endpoint and get every connected vendor.\n *\n * Three generic tools (corsair-style):\n * - `fabric_list_integrations` — what's connected for this tenant\n * - `fabric_list_operations` — endpoints for one integration\n * - `fabric_call` — execute an operation\n *\n * Usage (stdio transport, e.g. Claude Desktop):\n * import { createFabricMcpServer } from \"@fabricorg/sdk-mcp\";\n * import { createFabric } from \"@fabricorg/sdk\";\n * import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n *\n * const fabric = createFabric({ apiKey: process.env.FABRIC_API_KEY });\n * const server = createFabricMcpServer({ fabric });\n * await server.connect(new StdioServerTransport());\n *\n * Or use the prebuilt stdio entry: `import \"@fabricorg/sdk-mcp/stdio\";`\n * (The `fabric mcp serve` CLI command is the recommended user-facing path.)\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\n// Avoid importing @fabricorg/sdk concrete types at runtime; we only need its\n// shape so the server is decoupled from a specific SDK version. Consumers\n// pass an `FabricClient` instance.\ntype FabricLike = {\n\tintegrations: {\n\t\tlist(): Promise<\n\t\t\tArray<{\n\t\t\t\tslug: string;\n\t\t\t\tname: string;\n\t\t\t\tstatus: string;\n\t\t\t\tmode: string;\n\t\t\t\tsource: string;\n\t\t\t}>\n\t\t>;\n\t\t[slug: string]: unknown;\n\t};\n};\n\nexport interface CreateFabricMcpServerOptions {\n\t/** A configured FabricClient (createFabric) instance. Required. */\n\tfabric: FabricLike;\n\t/** Server name reported on the MCP handshake. Default `\"fabric\"`. */\n\tname?: string;\n\t/** Server version. Default `\"0.1.0\"`. */\n\tversion?: string;\n}\n\n/**\n * Build a configured `McpServer` exposing the workspace catalog. Caller is\n * responsible for `.connect(transport)` so the same server works over stdio,\n * HTTP, or any other MCP transport.\n */\nexport function createFabricMcpServer(\n\toptions: CreateFabricMcpServerOptions,\n): McpServer {\n\tconst fabric = options.fabric;\n\tconst server = new McpServer({\n\t\tname: options.name ?? \"fabric\",\n\t\tversion: options.version ?? \"0.1.0\",\n\t});\n\n\tserver.registerTool(\n\t\t\"fabric_list_integrations\",\n\t\t{\n\t\t\ttitle: \"List Fabric Integrations\",\n\t\t\tdescription:\n\t\t\t\t\"List integrations connected for the authenticated Fabric workspace. \" +\n\t\t\t\t\"Returns slug, display name, current connection status, permission mode \" +\n\t\t\t\t\"(open/cautious/strict/readonly), and source (plugin/mcp-server/connector).\",\n\t\t\tinputSchema: {},\n\t\t},\n\t\tasync () => {\n\t\t\tconst integrations = await fabric.integrations.list();\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: JSON.stringify(integrations, null, 2),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_list_operations\",\n\t\t{\n\t\t\ttitle: \"List Operations for an Integration\",\n\t\t\tdescription:\n\t\t\t\t\"List the dot-notation operations available on a single Fabric integration. \" +\n\t\t\t\t\"Returns an array of `{ operation, riskLevel, description }`. Supply the \" +\n\t\t\t\t\"slug from `fabric_list_integrations`.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Integration slug, e.g. \\\"slack\\\", \\\"github\\\", \\\"linear\\\".\",\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug }) => {\n\t\t\t// Endpoint metadata isn't exposed via the SDK's HTTP surface yet, so we\n\t\t\t// hit a known introspection path the portal returns under\n\t\t\t// `/integrations/:slug/operations`. Until that route lands, we surface a\n\t\t\t// helpful TODO so agents don't silently get an empty list.\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// Best-effort: the portal may expose `__operations` as a\n\t\t\t\t// magic operation that returns the catalog.\n\t\t\t\tconst ops = await integration.call?.(\"__operations\");\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify(ops, null, 2) }],\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Operation listing for \"${slug}\" requires portal endpoint /api/v1/integrations/${slug}/operations (not yet exposed). Use fabric_call with a known operation path in the meantime.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_call\",\n\t\t{\n\t\t\ttitle: \"Call a Fabric Integration Operation\",\n\t\t\tdescription:\n\t\t\t\t\"Execute an operation on a connected Fabric integration. Args is a JSON \" +\n\t\t\t\t\"object whose shape depends on the specific operation. Returns the \" +\n\t\t\t\t\"upstream response, or { status: 'pending_approval' | 'denied' } when \" +\n\t\t\t\t\"the workspace permission policy gates the call.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\"Integration slug, e.g. \\\"slack\\\".\"),\n\t\t\t\toperation: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Dot-notation operation, e.g. \\\"messages.send\\\" or \\\"channels.list\\\".\",\n\t\t\t\t\t),\n\t\t\t\targs: z\n\t\t\t\t\t.record(z.string(), z.unknown())\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Arguments object. Shape depends on the operation.\",\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug, operation, args }) => {\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration?.call) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst result = await integration.call(operation, args ?? {});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Error: ${message}` }],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\treturn server;\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["_a"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @fabricorg/sdk-mcp\n *\n * Builds an MCP (Model Context Protocol) server that exposes a Fabric\n * workspace's whole integration catalog as MCP tools — any MCP-compatible\n * agent (Claude Desktop, Cursor, Continue, OpenAI agents, …) can point at\n * one endpoint and get every connected vendor.\n *\n * Three generic tools (corsair-style):\n * - `fabric_list_integrations` — what's connected for this tenant\n * - `fabric_list_operations` — endpoints for one integration\n * - `fabric_call` — execute an operation\n *\n * Usage (stdio transport, e.g. Claude Desktop):\n * import { createFabricMcpServer } from \"@fabricorg/sdk-mcp\";\n * import { createFabric } from \"@fabricorg/sdk\";\n * import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n *\n * const fabric = createFabric({ apiKey: process.env.FABRIC_API_KEY });\n * const server = createFabricMcpServer({ fabric });\n * await server.connect(new StdioServerTransport());\n *\n * Or use the prebuilt stdio entry: `import \"@fabricorg/sdk-mcp/stdio\";`\n * (The `fabric mcp serve` CLI command is the recommended user-facing path.)\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\n// Avoid importing @fabricorg/sdk concrete types at runtime; we only need its\n// shape so the server is decoupled from a specific SDK version. Consumers\n// pass an `FabricClient` instance.\ntype FabricLike = {\n\tintegrations: {\n\t\tlist(): Promise<\n\t\t\tArray<{\n\t\t\t\tslug: string;\n\t\t\t\tname: string;\n\t\t\t\tstatus: string;\n\t\t\t\tmode: string;\n\t\t\t\tsource: string;\n\t\t\t}>\n\t\t>;\n\t\t[slug: string]: unknown;\n\t};\n};\n\nexport interface CreateFabricMcpServerOptions {\n\t/** A configured FabricClient (createFabric) instance. Required. */\n\tfabric: FabricLike;\n\t/** Server name reported on the MCP handshake. Default `\"fabric\"`. */\n\tname?: string;\n\t/** Server version. Default `\"0.1.0\"`. */\n\tversion?: string;\n}\n\n/**\n * Build a configured `McpServer` exposing the workspace catalog. Caller is\n * responsible for `.connect(transport)` so the same server works over stdio,\n * HTTP, or any other MCP transport.\n */\nexport function createFabricMcpServer(\n\toptions: CreateFabricMcpServerOptions,\n): McpServer {\n\tconst fabric = options.fabric;\n\tconst server = new McpServer({\n\t\tname: options.name ?? \"fabric\",\n\t\tversion: options.version ?? \"0.1.0\",\n\t});\n\n\tserver.registerTool(\n\t\t\"fabric_list_integrations\",\n\t\t{\n\t\t\ttitle: \"List Fabric Integrations\",\n\t\t\tdescription:\n\t\t\t\t\"List integrations connected for the authenticated Fabric workspace. \" +\n\t\t\t\t\"Returns slug, display name, current connection status, permission mode \" +\n\t\t\t\t\"(open/cautious/strict/readonly), and source (plugin/mcp-server/connector).\",\n\t\t\tinputSchema: {},\n\t\t},\n\t\tasync () => {\n\t\t\tconst integrations = await fabric.integrations.list();\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: JSON.stringify(integrations, null, 2),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_list_operations\",\n\t\t{\n\t\t\ttitle: \"List Operations for an Integration\",\n\t\t\tdescription:\n\t\t\t\t\"List the dot-notation operations available on a single Fabric integration. \" +\n\t\t\t\t\"Returns an array of `{ operation, riskLevel, description }`. Supply the \" +\n\t\t\t\t\"slug from `fabric_list_integrations`.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t'Integration slug, e.g. \"slack\", \"github\", \"linear\".',\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug }) => {\n\t\t\t// Endpoint metadata isn't exposed via the SDK's HTTP surface yet, so we\n\t\t\t// hit a known introspection path the portal returns under\n\t\t\t// `/integrations/:slug/operations`. Until that route lands, we surface a\n\t\t\t// helpful TODO so agents don't silently get an empty list.\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// Best-effort: the portal may expose `__operations` as a\n\t\t\t\t// magic operation that returns the catalog.\n\t\t\t\tconst ops = await integration.call?.(\"__operations\");\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{ type: \"text\", text: JSON.stringify(ops, null, 2) },\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Operation listing for \"${slug}\" requires portal endpoint /api/v1/integrations/${slug}/operations (not yet exposed). Use fabric_call with a known operation path in the meantime.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_call\",\n\t\t{\n\t\t\ttitle: \"Call a Fabric Integration Operation\",\n\t\t\tdescription:\n\t\t\t\t\"Execute an operation on a connected Fabric integration. Args is a JSON \" +\n\t\t\t\t\"object whose shape depends on the specific operation. Returns the \" +\n\t\t\t\t\"upstream response, or { status: 'pending_approval' | 'denied' } when \" +\n\t\t\t\t\"the workspace permission policy gates the call.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z.string().describe('Integration slug, e.g. \"slack\".'),\n\t\t\t\toperation: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t'Dot-notation operation, e.g. \"messages.send\" or \"channels.list\".',\n\t\t\t\t\t),\n\t\t\t\targs: z\n\t\t\t\t\t.record(z.string(), z.unknown())\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Arguments object. Shape depends on the operation.\",\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug, operation, args }) => {\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration?.call) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst result = await integration.call(operation, args ?? {});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{ type: \"text\", text: JSON.stringify(result, null, 2) },\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\tconst message =\n\t\t\t\t\terr instanceof Error ? err.message : String(err);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Error: ${message}` }],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\treturn server;\n}\n"]}
package/dist/stdio.cjs CHANGED
@@ -79,7 +79,9 @@ function createFabricMcpServer(options) {
79
79
  try {
80
80
  const ops = yield (_a2 = integration.call) == null ? void 0 : _a2.call(integration, "__operations");
81
81
  return {
82
- content: [{ type: "text", text: JSON.stringify(ops, null, 2) }]
82
+ content: [
83
+ { type: "text", text: JSON.stringify(ops, null, 2) }
84
+ ]
83
85
  };
84
86
  } catch (e) {
85
87
  return {
@@ -124,7 +126,9 @@ function createFabricMcpServer(options) {
124
126
  try {
125
127
  const result = yield integration.call(operation, args != null ? args : {});
126
128
  return {
127
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
129
+ content: [
130
+ { type: "text", text: JSON.stringify(result, null, 2) }
131
+ ]
128
132
  };
129
133
  } catch (err) {
130
134
  const message = err instanceof Error ? err.message : String(err);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/stdio.ts"],"names":["McpServer","z","_a","createFabric","StdioServerTransport"],"mappings":"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","file":"stdio.cjs","sourcesContent":["/**\n * @fabricorg/sdk-mcp\n *\n * Builds an MCP (Model Context Protocol) server that exposes a Fabric\n * workspace's whole integration catalog as MCP tools — any MCP-compatible\n * agent (Claude Desktop, Cursor, Continue, OpenAI agents, …) can point at\n * one endpoint and get every connected vendor.\n *\n * Three generic tools (corsair-style):\n * - `fabric_list_integrations` — what's connected for this tenant\n * - `fabric_list_operations` — endpoints for one integration\n * - `fabric_call` — execute an operation\n *\n * Usage (stdio transport, e.g. Claude Desktop):\n * import { createFabricMcpServer } from \"@fabricorg/sdk-mcp\";\n * import { createFabric } from \"@fabricorg/sdk\";\n * import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n *\n * const fabric = createFabric({ apiKey: process.env.FABRIC_API_KEY });\n * const server = createFabricMcpServer({ fabric });\n * await server.connect(new StdioServerTransport());\n *\n * Or use the prebuilt stdio entry: `import \"@fabricorg/sdk-mcp/stdio\";`\n * (The `fabric mcp serve` CLI command is the recommended user-facing path.)\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\n// Avoid importing @fabricorg/sdk concrete types at runtime; we only need its\n// shape so the server is decoupled from a specific SDK version. Consumers\n// pass an `FabricClient` instance.\ntype FabricLike = {\n\tintegrations: {\n\t\tlist(): Promise<\n\t\t\tArray<{\n\t\t\t\tslug: string;\n\t\t\t\tname: string;\n\t\t\t\tstatus: string;\n\t\t\t\tmode: string;\n\t\t\t\tsource: string;\n\t\t\t}>\n\t\t>;\n\t\t[slug: string]: unknown;\n\t};\n};\n\nexport interface CreateFabricMcpServerOptions {\n\t/** A configured FabricClient (createFabric) instance. Required. */\n\tfabric: FabricLike;\n\t/** Server name reported on the MCP handshake. Default `\"fabric\"`. */\n\tname?: string;\n\t/** Server version. Default `\"0.1.0\"`. */\n\tversion?: string;\n}\n\n/**\n * Build a configured `McpServer` exposing the workspace catalog. Caller is\n * responsible for `.connect(transport)` so the same server works over stdio,\n * HTTP, or any other MCP transport.\n */\nexport function createFabricMcpServer(\n\toptions: CreateFabricMcpServerOptions,\n): McpServer {\n\tconst fabric = options.fabric;\n\tconst server = new McpServer({\n\t\tname: options.name ?? \"fabric\",\n\t\tversion: options.version ?? \"0.1.0\",\n\t});\n\n\tserver.registerTool(\n\t\t\"fabric_list_integrations\",\n\t\t{\n\t\t\ttitle: \"List Fabric Integrations\",\n\t\t\tdescription:\n\t\t\t\t\"List integrations connected for the authenticated Fabric workspace. \" +\n\t\t\t\t\"Returns slug, display name, current connection status, permission mode \" +\n\t\t\t\t\"(open/cautious/strict/readonly), and source (plugin/mcp-server/connector).\",\n\t\t\tinputSchema: {},\n\t\t},\n\t\tasync () => {\n\t\t\tconst integrations = await fabric.integrations.list();\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: JSON.stringify(integrations, null, 2),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_list_operations\",\n\t\t{\n\t\t\ttitle: \"List Operations for an Integration\",\n\t\t\tdescription:\n\t\t\t\t\"List the dot-notation operations available on a single Fabric integration. \" +\n\t\t\t\t\"Returns an array of `{ operation, riskLevel, description }`. Supply the \" +\n\t\t\t\t\"slug from `fabric_list_integrations`.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Integration slug, e.g. \\\"slack\\\", \\\"github\\\", \\\"linear\\\".\",\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug }) => {\n\t\t\t// Endpoint metadata isn't exposed via the SDK's HTTP surface yet, so we\n\t\t\t// hit a known introspection path the portal returns under\n\t\t\t// `/integrations/:slug/operations`. Until that route lands, we surface a\n\t\t\t// helpful TODO so agents don't silently get an empty list.\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// Best-effort: the portal may expose `__operations` as a\n\t\t\t\t// magic operation that returns the catalog.\n\t\t\t\tconst ops = await integration.call?.(\"__operations\");\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify(ops, null, 2) }],\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Operation listing for \"${slug}\" requires portal endpoint /api/v1/integrations/${slug}/operations (not yet exposed). Use fabric_call with a known operation path in the meantime.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_call\",\n\t\t{\n\t\t\ttitle: \"Call a Fabric Integration Operation\",\n\t\t\tdescription:\n\t\t\t\t\"Execute an operation on a connected Fabric integration. Args is a JSON \" +\n\t\t\t\t\"object whose shape depends on the specific operation. Returns the \" +\n\t\t\t\t\"upstream response, or { status: 'pending_approval' | 'denied' } when \" +\n\t\t\t\t\"the workspace permission policy gates the call.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\"Integration slug, e.g. \\\"slack\\\".\"),\n\t\t\t\toperation: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Dot-notation operation, e.g. \\\"messages.send\\\" or \\\"channels.list\\\".\",\n\t\t\t\t\t),\n\t\t\t\targs: z\n\t\t\t\t\t.record(z.string(), z.unknown())\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Arguments object. Shape depends on the operation.\",\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug, operation, args }) => {\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration?.call) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst result = await integration.call(operation, args ?? {});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Error: ${message}` }],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\treturn server;\n}\n","/**\n * @fabricorg/sdk-mcp/stdio\n *\n * Convenience entry: runs a stdio MCP server using `FABRIC_API_KEY`\n * (and optional `FABRIC_BASE_URL` / `FABRIC_ORG`) from the environment.\n *\n * Designed to be exec'd by an MCP client (Claude Desktop, Cursor, etc.).\n * The `fabric mcp serve` CLI command is the recommended invocation; this\n * file is the underlying script.\n *\n * Stdout is reserved for the JSON-RPC framing — log only to stderr.\n */\n\nimport { createFabric } from \"@fabricorg/sdk\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { createFabricMcpServer } from \"./index.js\";\n\nexport async function runStdio(): Promise<void> {\n\tconst fabric = createFabric({});\n\tconst server = createFabricMcpServer({ fabric });\n\tconst transport = new StdioServerTransport();\n\tawait server.connect(transport);\n\tprocess.stderr.write(\"[fabric-mcp] stdio transport connected\\n\");\n}\n\n// When invoked directly (node dist/stdio.js), kick off the server.\nconst isDirectInvocation =\n\ttypeof process !== \"undefined\" &&\n\tArray.isArray(process.argv) &&\n\tprocess.argv[1] !== undefined &&\n\t(process.argv[1].endsWith(\"stdio.js\") ||\n\t\tprocess.argv[1].endsWith(\"stdio.cjs\"));\n\nif (isDirectInvocation) {\n\trunStdio().catch((err) => {\n\t\tprocess.stderr.write(\n\t\t\t`[fabric-mcp] fatal: ${err instanceof Error ? err.message : String(err)}\\n`,\n\t\t);\n\t\tprocess.exit(1);\n\t});\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/stdio.ts"],"names":["McpServer","z","_a","createFabric","StdioServerTransport"],"mappings":"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","file":"stdio.cjs","sourcesContent":["/**\n * @fabricorg/sdk-mcp\n *\n * Builds an MCP (Model Context Protocol) server that exposes a Fabric\n * workspace's whole integration catalog as MCP tools — any MCP-compatible\n * agent (Claude Desktop, Cursor, Continue, OpenAI agents, …) can point at\n * one endpoint and get every connected vendor.\n *\n * Three generic tools (corsair-style):\n * - `fabric_list_integrations` — what's connected for this tenant\n * - `fabric_list_operations` — endpoints for one integration\n * - `fabric_call` — execute an operation\n *\n * Usage (stdio transport, e.g. Claude Desktop):\n * import { createFabricMcpServer } from \"@fabricorg/sdk-mcp\";\n * import { createFabric } from \"@fabricorg/sdk\";\n * import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n *\n * const fabric = createFabric({ apiKey: process.env.FABRIC_API_KEY });\n * const server = createFabricMcpServer({ fabric });\n * await server.connect(new StdioServerTransport());\n *\n * Or use the prebuilt stdio entry: `import \"@fabricorg/sdk-mcp/stdio\";`\n * (The `fabric mcp serve` CLI command is the recommended user-facing path.)\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\n// Avoid importing @fabricorg/sdk concrete types at runtime; we only need its\n// shape so the server is decoupled from a specific SDK version. Consumers\n// pass an `FabricClient` instance.\ntype FabricLike = {\n\tintegrations: {\n\t\tlist(): Promise<\n\t\t\tArray<{\n\t\t\t\tslug: string;\n\t\t\t\tname: string;\n\t\t\t\tstatus: string;\n\t\t\t\tmode: string;\n\t\t\t\tsource: string;\n\t\t\t}>\n\t\t>;\n\t\t[slug: string]: unknown;\n\t};\n};\n\nexport interface CreateFabricMcpServerOptions {\n\t/** A configured FabricClient (createFabric) instance. Required. */\n\tfabric: FabricLike;\n\t/** Server name reported on the MCP handshake. Default `\"fabric\"`. */\n\tname?: string;\n\t/** Server version. Default `\"0.1.0\"`. */\n\tversion?: string;\n}\n\n/**\n * Build a configured `McpServer` exposing the workspace catalog. Caller is\n * responsible for `.connect(transport)` so the same server works over stdio,\n * HTTP, or any other MCP transport.\n */\nexport function createFabricMcpServer(\n\toptions: CreateFabricMcpServerOptions,\n): McpServer {\n\tconst fabric = options.fabric;\n\tconst server = new McpServer({\n\t\tname: options.name ?? \"fabric\",\n\t\tversion: options.version ?? \"0.1.0\",\n\t});\n\n\tserver.registerTool(\n\t\t\"fabric_list_integrations\",\n\t\t{\n\t\t\ttitle: \"List Fabric Integrations\",\n\t\t\tdescription:\n\t\t\t\t\"List integrations connected for the authenticated Fabric workspace. \" +\n\t\t\t\t\"Returns slug, display name, current connection status, permission mode \" +\n\t\t\t\t\"(open/cautious/strict/readonly), and source (plugin/mcp-server/connector).\",\n\t\t\tinputSchema: {},\n\t\t},\n\t\tasync () => {\n\t\t\tconst integrations = await fabric.integrations.list();\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: JSON.stringify(integrations, null, 2),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_list_operations\",\n\t\t{\n\t\t\ttitle: \"List Operations for an Integration\",\n\t\t\tdescription:\n\t\t\t\t\"List the dot-notation operations available on a single Fabric integration. \" +\n\t\t\t\t\"Returns an array of `{ operation, riskLevel, description }`. Supply the \" +\n\t\t\t\t\"slug from `fabric_list_integrations`.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t'Integration slug, e.g. \"slack\", \"github\", \"linear\".',\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug }) => {\n\t\t\t// Endpoint metadata isn't exposed via the SDK's HTTP surface yet, so we\n\t\t\t// hit a known introspection path the portal returns under\n\t\t\t// `/integrations/:slug/operations`. Until that route lands, we surface a\n\t\t\t// helpful TODO so agents don't silently get an empty list.\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// Best-effort: the portal may expose `__operations` as a\n\t\t\t\t// magic operation that returns the catalog.\n\t\t\t\tconst ops = await integration.call?.(\"__operations\");\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{ type: \"text\", text: JSON.stringify(ops, null, 2) },\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Operation listing for \"${slug}\" requires portal endpoint /api/v1/integrations/${slug}/operations (not yet exposed). Use fabric_call with a known operation path in the meantime.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_call\",\n\t\t{\n\t\t\ttitle: \"Call a Fabric Integration Operation\",\n\t\t\tdescription:\n\t\t\t\t\"Execute an operation on a connected Fabric integration. Args is a JSON \" +\n\t\t\t\t\"object whose shape depends on the specific operation. Returns the \" +\n\t\t\t\t\"upstream response, or { status: 'pending_approval' | 'denied' } when \" +\n\t\t\t\t\"the workspace permission policy gates the call.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z.string().describe('Integration slug, e.g. \"slack\".'),\n\t\t\t\toperation: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t'Dot-notation operation, e.g. \"messages.send\" or \"channels.list\".',\n\t\t\t\t\t),\n\t\t\t\targs: z\n\t\t\t\t\t.record(z.string(), z.unknown())\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Arguments object. Shape depends on the operation.\",\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug, operation, args }) => {\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration?.call) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst result = await integration.call(operation, args ?? {});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{ type: \"text\", text: JSON.stringify(result, null, 2) },\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\tconst message =\n\t\t\t\t\terr instanceof Error ? err.message : String(err);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Error: ${message}` }],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\treturn server;\n}\n","/**\n * @fabricorg/sdk-mcp/stdio\n *\n * Convenience entry: runs a stdio MCP server using `FABRIC_API_KEY`\n * (and optional `FABRIC_BASE_URL` / `FABRIC_ORG`) from the environment.\n *\n * Designed to be exec'd by an MCP client (Claude Desktop, Cursor, etc.).\n * The `fabric mcp serve` CLI command is the recommended invocation; this\n * file is the underlying script.\n *\n * Stdout is reserved for the JSON-RPC framing — log only to stderr.\n */\n\nimport { createFabric } from \"@fabricorg/sdk\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { createFabricMcpServer } from \"./index.js\";\n\nexport async function runStdio(): Promise<void> {\n\tconst fabric = createFabric({});\n\tconst server = createFabricMcpServer({ fabric });\n\tconst transport = new StdioServerTransport();\n\tawait server.connect(transport);\n\tprocess.stderr.write(\"[fabric-mcp] stdio transport connected\\n\");\n}\n\n// When invoked directly (node dist/stdio.js), kick off the server.\nconst isDirectInvocation =\n\ttypeof process !== \"undefined\" &&\n\tArray.isArray(process.argv) &&\n\tprocess.argv[1] !== undefined &&\n\t(process.argv[1].endsWith(\"stdio.js\") ||\n\t\tprocess.argv[1].endsWith(\"stdio.cjs\"));\n\nif (isDirectInvocation) {\n\trunStdio().catch((err) => {\n\t\tprocess.stderr.write(\n\t\t\t`[fabric-mcp] fatal: ${err instanceof Error ? err.message : String(err)}\\n`,\n\t\t);\n\t\tprocess.exit(1);\n\t});\n}\n"]}
package/dist/stdio.js CHANGED
@@ -77,7 +77,9 @@ function createFabricMcpServer(options) {
77
77
  try {
78
78
  const ops = yield (_a2 = integration.call) == null ? void 0 : _a2.call(integration, "__operations");
79
79
  return {
80
- content: [{ type: "text", text: JSON.stringify(ops, null, 2) }]
80
+ content: [
81
+ { type: "text", text: JSON.stringify(ops, null, 2) }
82
+ ]
81
83
  };
82
84
  } catch (e) {
83
85
  return {
@@ -122,7 +124,9 @@ function createFabricMcpServer(options) {
122
124
  try {
123
125
  const result = yield integration.call(operation, args != null ? args : {});
124
126
  return {
125
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
127
+ content: [
128
+ { type: "text", text: JSON.stringify(result, null, 2) }
129
+ ]
126
130
  };
127
131
  } catch (err) {
128
132
  const message = err instanceof Error ? err.message : String(err);
package/dist/stdio.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/stdio.ts"],"names":["_a"],"mappings":"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","file":"stdio.js","sourcesContent":["/**\n * @fabricorg/sdk-mcp\n *\n * Builds an MCP (Model Context Protocol) server that exposes a Fabric\n * workspace's whole integration catalog as MCP tools — any MCP-compatible\n * agent (Claude Desktop, Cursor, Continue, OpenAI agents, …) can point at\n * one endpoint and get every connected vendor.\n *\n * Three generic tools (corsair-style):\n * - `fabric_list_integrations` — what's connected for this tenant\n * - `fabric_list_operations` — endpoints for one integration\n * - `fabric_call` — execute an operation\n *\n * Usage (stdio transport, e.g. Claude Desktop):\n * import { createFabricMcpServer } from \"@fabricorg/sdk-mcp\";\n * import { createFabric } from \"@fabricorg/sdk\";\n * import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n *\n * const fabric = createFabric({ apiKey: process.env.FABRIC_API_KEY });\n * const server = createFabricMcpServer({ fabric });\n * await server.connect(new StdioServerTransport());\n *\n * Or use the prebuilt stdio entry: `import \"@fabricorg/sdk-mcp/stdio\";`\n * (The `fabric mcp serve` CLI command is the recommended user-facing path.)\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\n// Avoid importing @fabricorg/sdk concrete types at runtime; we only need its\n// shape so the server is decoupled from a specific SDK version. Consumers\n// pass an `FabricClient` instance.\ntype FabricLike = {\n\tintegrations: {\n\t\tlist(): Promise<\n\t\t\tArray<{\n\t\t\t\tslug: string;\n\t\t\t\tname: string;\n\t\t\t\tstatus: string;\n\t\t\t\tmode: string;\n\t\t\t\tsource: string;\n\t\t\t}>\n\t\t>;\n\t\t[slug: string]: unknown;\n\t};\n};\n\nexport interface CreateFabricMcpServerOptions {\n\t/** A configured FabricClient (createFabric) instance. Required. */\n\tfabric: FabricLike;\n\t/** Server name reported on the MCP handshake. Default `\"fabric\"`. */\n\tname?: string;\n\t/** Server version. Default `\"0.1.0\"`. */\n\tversion?: string;\n}\n\n/**\n * Build a configured `McpServer` exposing the workspace catalog. Caller is\n * responsible for `.connect(transport)` so the same server works over stdio,\n * HTTP, or any other MCP transport.\n */\nexport function createFabricMcpServer(\n\toptions: CreateFabricMcpServerOptions,\n): McpServer {\n\tconst fabric = options.fabric;\n\tconst server = new McpServer({\n\t\tname: options.name ?? \"fabric\",\n\t\tversion: options.version ?? \"0.1.0\",\n\t});\n\n\tserver.registerTool(\n\t\t\"fabric_list_integrations\",\n\t\t{\n\t\t\ttitle: \"List Fabric Integrations\",\n\t\t\tdescription:\n\t\t\t\t\"List integrations connected for the authenticated Fabric workspace. \" +\n\t\t\t\t\"Returns slug, display name, current connection status, permission mode \" +\n\t\t\t\t\"(open/cautious/strict/readonly), and source (plugin/mcp-server/connector).\",\n\t\t\tinputSchema: {},\n\t\t},\n\t\tasync () => {\n\t\t\tconst integrations = await fabric.integrations.list();\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: JSON.stringify(integrations, null, 2),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_list_operations\",\n\t\t{\n\t\t\ttitle: \"List Operations for an Integration\",\n\t\t\tdescription:\n\t\t\t\t\"List the dot-notation operations available on a single Fabric integration. \" +\n\t\t\t\t\"Returns an array of `{ operation, riskLevel, description }`. Supply the \" +\n\t\t\t\t\"slug from `fabric_list_integrations`.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Integration slug, e.g. \\\"slack\\\", \\\"github\\\", \\\"linear\\\".\",\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug }) => {\n\t\t\t// Endpoint metadata isn't exposed via the SDK's HTTP surface yet, so we\n\t\t\t// hit a known introspection path the portal returns under\n\t\t\t// `/integrations/:slug/operations`. Until that route lands, we surface a\n\t\t\t// helpful TODO so agents don't silently get an empty list.\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// Best-effort: the portal may expose `__operations` as a\n\t\t\t\t// magic operation that returns the catalog.\n\t\t\t\tconst ops = await integration.call?.(\"__operations\");\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify(ops, null, 2) }],\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Operation listing for \"${slug}\" requires portal endpoint /api/v1/integrations/${slug}/operations (not yet exposed). Use fabric_call with a known operation path in the meantime.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_call\",\n\t\t{\n\t\t\ttitle: \"Call a Fabric Integration Operation\",\n\t\t\tdescription:\n\t\t\t\t\"Execute an operation on a connected Fabric integration. Args is a JSON \" +\n\t\t\t\t\"object whose shape depends on the specific operation. Returns the \" +\n\t\t\t\t\"upstream response, or { status: 'pending_approval' | 'denied' } when \" +\n\t\t\t\t\"the workspace permission policy gates the call.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\"Integration slug, e.g. \\\"slack\\\".\"),\n\t\t\t\toperation: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Dot-notation operation, e.g. \\\"messages.send\\\" or \\\"channels.list\\\".\",\n\t\t\t\t\t),\n\t\t\t\targs: z\n\t\t\t\t\t.record(z.string(), z.unknown())\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Arguments object. Shape depends on the operation.\",\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug, operation, args }) => {\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration?.call) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst result = await integration.call(operation, args ?? {});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Error: ${message}` }],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\treturn server;\n}\n","/**\n * @fabricorg/sdk-mcp/stdio\n *\n * Convenience entry: runs a stdio MCP server using `FABRIC_API_KEY`\n * (and optional `FABRIC_BASE_URL` / `FABRIC_ORG`) from the environment.\n *\n * Designed to be exec'd by an MCP client (Claude Desktop, Cursor, etc.).\n * The `fabric mcp serve` CLI command is the recommended invocation; this\n * file is the underlying script.\n *\n * Stdout is reserved for the JSON-RPC framing — log only to stderr.\n */\n\nimport { createFabric } from \"@fabricorg/sdk\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { createFabricMcpServer } from \"./index.js\";\n\nexport async function runStdio(): Promise<void> {\n\tconst fabric = createFabric({});\n\tconst server = createFabricMcpServer({ fabric });\n\tconst transport = new StdioServerTransport();\n\tawait server.connect(transport);\n\tprocess.stderr.write(\"[fabric-mcp] stdio transport connected\\n\");\n}\n\n// When invoked directly (node dist/stdio.js), kick off the server.\nconst isDirectInvocation =\n\ttypeof process !== \"undefined\" &&\n\tArray.isArray(process.argv) &&\n\tprocess.argv[1] !== undefined &&\n\t(process.argv[1].endsWith(\"stdio.js\") ||\n\t\tprocess.argv[1].endsWith(\"stdio.cjs\"));\n\nif (isDirectInvocation) {\n\trunStdio().catch((err) => {\n\t\tprocess.stderr.write(\n\t\t\t`[fabric-mcp] fatal: ${err instanceof Error ? err.message : String(err)}\\n`,\n\t\t);\n\t\tprocess.exit(1);\n\t});\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/stdio.ts"],"names":["_a"],"mappings":"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","file":"stdio.js","sourcesContent":["/**\n * @fabricorg/sdk-mcp\n *\n * Builds an MCP (Model Context Protocol) server that exposes a Fabric\n * workspace's whole integration catalog as MCP tools — any MCP-compatible\n * agent (Claude Desktop, Cursor, Continue, OpenAI agents, …) can point at\n * one endpoint and get every connected vendor.\n *\n * Three generic tools (corsair-style):\n * - `fabric_list_integrations` — what's connected for this tenant\n * - `fabric_list_operations` — endpoints for one integration\n * - `fabric_call` — execute an operation\n *\n * Usage (stdio transport, e.g. Claude Desktop):\n * import { createFabricMcpServer } from \"@fabricorg/sdk-mcp\";\n * import { createFabric } from \"@fabricorg/sdk\";\n * import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n *\n * const fabric = createFabric({ apiKey: process.env.FABRIC_API_KEY });\n * const server = createFabricMcpServer({ fabric });\n * await server.connect(new StdioServerTransport());\n *\n * Or use the prebuilt stdio entry: `import \"@fabricorg/sdk-mcp/stdio\";`\n * (The `fabric mcp serve` CLI command is the recommended user-facing path.)\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\n// Avoid importing @fabricorg/sdk concrete types at runtime; we only need its\n// shape so the server is decoupled from a specific SDK version. Consumers\n// pass an `FabricClient` instance.\ntype FabricLike = {\n\tintegrations: {\n\t\tlist(): Promise<\n\t\t\tArray<{\n\t\t\t\tslug: string;\n\t\t\t\tname: string;\n\t\t\t\tstatus: string;\n\t\t\t\tmode: string;\n\t\t\t\tsource: string;\n\t\t\t}>\n\t\t>;\n\t\t[slug: string]: unknown;\n\t};\n};\n\nexport interface CreateFabricMcpServerOptions {\n\t/** A configured FabricClient (createFabric) instance. Required. */\n\tfabric: FabricLike;\n\t/** Server name reported on the MCP handshake. Default `\"fabric\"`. */\n\tname?: string;\n\t/** Server version. Default `\"0.1.0\"`. */\n\tversion?: string;\n}\n\n/**\n * Build a configured `McpServer` exposing the workspace catalog. Caller is\n * responsible for `.connect(transport)` so the same server works over stdio,\n * HTTP, or any other MCP transport.\n */\nexport function createFabricMcpServer(\n\toptions: CreateFabricMcpServerOptions,\n): McpServer {\n\tconst fabric = options.fabric;\n\tconst server = new McpServer({\n\t\tname: options.name ?? \"fabric\",\n\t\tversion: options.version ?? \"0.1.0\",\n\t});\n\n\tserver.registerTool(\n\t\t\"fabric_list_integrations\",\n\t\t{\n\t\t\ttitle: \"List Fabric Integrations\",\n\t\t\tdescription:\n\t\t\t\t\"List integrations connected for the authenticated Fabric workspace. \" +\n\t\t\t\t\"Returns slug, display name, current connection status, permission mode \" +\n\t\t\t\t\"(open/cautious/strict/readonly), and source (plugin/mcp-server/connector).\",\n\t\t\tinputSchema: {},\n\t\t},\n\t\tasync () => {\n\t\t\tconst integrations = await fabric.integrations.list();\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: JSON.stringify(integrations, null, 2),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_list_operations\",\n\t\t{\n\t\t\ttitle: \"List Operations for an Integration\",\n\t\t\tdescription:\n\t\t\t\t\"List the dot-notation operations available on a single Fabric integration. \" +\n\t\t\t\t\"Returns an array of `{ operation, riskLevel, description }`. Supply the \" +\n\t\t\t\t\"slug from `fabric_list_integrations`.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t'Integration slug, e.g. \"slack\", \"github\", \"linear\".',\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug }) => {\n\t\t\t// Endpoint metadata isn't exposed via the SDK's HTTP surface yet, so we\n\t\t\t// hit a known introspection path the portal returns under\n\t\t\t// `/integrations/:slug/operations`. Until that route lands, we surface a\n\t\t\t// helpful TODO so agents don't silently get an empty list.\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// Best-effort: the portal may expose `__operations` as a\n\t\t\t\t// magic operation that returns the catalog.\n\t\t\t\tconst ops = await integration.call?.(\"__operations\");\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{ type: \"text\", text: JSON.stringify(ops, null, 2) },\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Operation listing for \"${slug}\" requires portal endpoint /api/v1/integrations/${slug}/operations (not yet exposed). Use fabric_call with a known operation path in the meantime.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"fabric_call\",\n\t\t{\n\t\t\ttitle: \"Call a Fabric Integration Operation\",\n\t\t\tdescription:\n\t\t\t\t\"Execute an operation on a connected Fabric integration. Args is a JSON \" +\n\t\t\t\t\"object whose shape depends on the specific operation. Returns the \" +\n\t\t\t\t\"upstream response, or { status: 'pending_approval' | 'denied' } when \" +\n\t\t\t\t\"the workspace permission policy gates the call.\",\n\t\t\tinputSchema: {\n\t\t\t\tslug: z.string().describe('Integration slug, e.g. \"slack\".'),\n\t\t\t\toperation: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t'Dot-notation operation, e.g. \"messages.send\" or \"channels.list\".',\n\t\t\t\t\t),\n\t\t\t\targs: z\n\t\t\t\t\t.record(z.string(), z.unknown())\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Arguments object. Shape depends on the operation.\",\n\t\t\t\t\t),\n\t\t\t},\n\t\t},\n\t\tasync ({ slug, operation, args }) => {\n\t\t\tconst integration = (\n\t\t\t\tfabric.integrations as Record<string, unknown>\n\t\t\t)[slug] as\n\t\t\t\t| {\n\t\t\t\t\t\tcall?: (op: string, args?: unknown) => Promise<unknown>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!integration?.call) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Integration \"${slug}\" is not registered for this workspace.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst result = await integration.call(operation, args ?? {});\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{ type: \"text\", text: JSON.stringify(result, null, 2) },\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t} catch (err) {\n\t\t\t\tconst message =\n\t\t\t\t\terr instanceof Error ? err.message : String(err);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Error: ${message}` }],\n\t\t\t\t\tisError: true,\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t);\n\n\treturn server;\n}\n","/**\n * @fabricorg/sdk-mcp/stdio\n *\n * Convenience entry: runs a stdio MCP server using `FABRIC_API_KEY`\n * (and optional `FABRIC_BASE_URL` / `FABRIC_ORG`) from the environment.\n *\n * Designed to be exec'd by an MCP client (Claude Desktop, Cursor, etc.).\n * The `fabric mcp serve` CLI command is the recommended invocation; this\n * file is the underlying script.\n *\n * Stdout is reserved for the JSON-RPC framing — log only to stderr.\n */\n\nimport { createFabric } from \"@fabricorg/sdk\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { createFabricMcpServer } from \"./index.js\";\n\nexport async function runStdio(): Promise<void> {\n\tconst fabric = createFabric({});\n\tconst server = createFabricMcpServer({ fabric });\n\tconst transport = new StdioServerTransport();\n\tawait server.connect(transport);\n\tprocess.stderr.write(\"[fabric-mcp] stdio transport connected\\n\");\n}\n\n// When invoked directly (node dist/stdio.js), kick off the server.\nconst isDirectInvocation =\n\ttypeof process !== \"undefined\" &&\n\tArray.isArray(process.argv) &&\n\tprocess.argv[1] !== undefined &&\n\t(process.argv[1].endsWith(\"stdio.js\") ||\n\t\tprocess.argv[1].endsWith(\"stdio.cjs\"));\n\nif (isDirectInvocation) {\n\trunStdio().catch((err) => {\n\t\tprocess.stderr.write(\n\t\t\t`[fabric-mcp] fatal: ${err instanceof Error ? err.message : String(err)}\\n`,\n\t\t);\n\t\tprocess.exit(1);\n\t});\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabricorg/sdk-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "MCP server adapter for @fabricorg/sdk — expose a Fabric workspace as MCP tools",
5
5
  "keywords": [
6
6
  "fabric",
@@ -10,6 +10,11 @@
10
10
  ],
11
11
  "homepage": "https://fabric.pro",
12
12
  "license": "MIT",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/Fabric-Pro/fabric-oss.git",
16
+ "directory": "packages/sdk-mcp"
17
+ },
13
18
  "type": "module",
14
19
  "exports": {
15
20
  ".": {
@@ -33,18 +38,17 @@
33
38
  "dist"
34
39
  ],
35
40
  "peerDependencies": {
36
- "@fabricorg/sdk": "0.1.0"
41
+ "@fabricorg/sdk": "0.2.0"
37
42
  },
38
43
  "dependencies": {
39
- "@modelcontextprotocol/sdk": "^1.26.0",
44
+ "@modelcontextprotocol/sdk": "^1.30.0",
40
45
  "zod": "^4.3.6"
41
46
  },
42
47
  "devDependencies": {
43
- "@biomejs/biome": "2.3.3",
48
+ "@fabricorg/sdk": "0.2.0",
49
+ "@repo/tsconfig": "0.0.0",
44
50
  "tsup": "^8.0.0",
45
- "typescript": "5.9.3",
46
- "@fabricorg/sdk": "0.1.0",
47
- "@repo/tsconfig": "0.0.0"
51
+ "typescript": "5.9.3"
48
52
  },
49
53
  "scripts": {
50
54
  "build": "tsup",