@fabricorg/sdk-mcp 0.1.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 +141 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +56 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.js +139 -0
- package/dist/index.js.map +1 -0
- package/dist/stdio.cjs +164 -0
- package/dist/stdio.cjs.map +1 -0
- package/dist/stdio.d.cts +15 -0
- package/dist/stdio.d.ts +15 -0
- package/dist/stdio.js +162 -0
- package/dist/stdio.js.map +1 -0
- package/package.json +54 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
4
|
+
var zod = require('zod');
|
|
5
|
+
|
|
6
|
+
var __async = (__this, __arguments, generator) => {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
var fulfilled = (value) => {
|
|
9
|
+
try {
|
|
10
|
+
step(generator.next(value));
|
|
11
|
+
} catch (e) {
|
|
12
|
+
reject(e);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var rejected = (value) => {
|
|
16
|
+
try {
|
|
17
|
+
step(generator.throw(value));
|
|
18
|
+
} catch (e) {
|
|
19
|
+
reject(e);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
23
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
function createFabricMcpServer(options) {
|
|
27
|
+
var _a, _b;
|
|
28
|
+
const fabric = options.fabric;
|
|
29
|
+
const server = new mcp_js.McpServer({
|
|
30
|
+
name: (_a = options.name) != null ? _a : "fabric",
|
|
31
|
+
version: (_b = options.version) != null ? _b : "0.1.0"
|
|
32
|
+
});
|
|
33
|
+
server.registerTool(
|
|
34
|
+
"fabric_list_integrations",
|
|
35
|
+
{
|
|
36
|
+
title: "List Fabric Integrations",
|
|
37
|
+
description: "List integrations connected for the authenticated Fabric workspace. Returns slug, display name, current connection status, permission mode (open/cautious/strict/readonly), and source (plugin/mcp-server/connector).",
|
|
38
|
+
inputSchema: {}
|
|
39
|
+
},
|
|
40
|
+
() => __async(null, null, function* () {
|
|
41
|
+
const integrations = yield fabric.integrations.list();
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: "text",
|
|
46
|
+
text: JSON.stringify(integrations, null, 2)
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
};
|
|
50
|
+
})
|
|
51
|
+
);
|
|
52
|
+
server.registerTool(
|
|
53
|
+
"fabric_list_operations",
|
|
54
|
+
{
|
|
55
|
+
title: "List Operations for an Integration",
|
|
56
|
+
description: "List the dot-notation operations available on a single Fabric integration. Returns an array of `{ operation, riskLevel, description }`. Supply the slug from `fabric_list_integrations`.",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
slug: zod.z.string().describe(
|
|
59
|
+
'Integration slug, e.g. "slack", "github", "linear".'
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
(_0) => __async(null, [_0], function* ({ slug }) {
|
|
64
|
+
var _a2;
|
|
65
|
+
const integration = fabric.integrations[slug];
|
|
66
|
+
if (!integration) {
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: "text",
|
|
71
|
+
text: `Integration "${slug}" is not registered for this workspace.`
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
isError: true
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const ops = yield (_a2 = integration.call) == null ? void 0 : _a2.call(integration, "__operations");
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: "text", text: JSON.stringify(ops, null, 2) }]
|
|
81
|
+
};
|
|
82
|
+
} catch (e) {
|
|
83
|
+
return {
|
|
84
|
+
content: [
|
|
85
|
+
{
|
|
86
|
+
type: "text",
|
|
87
|
+
text: `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.`
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
);
|
|
94
|
+
server.registerTool(
|
|
95
|
+
"fabric_call",
|
|
96
|
+
{
|
|
97
|
+
title: "Call a Fabric Integration Operation",
|
|
98
|
+
description: "Execute an operation on a connected Fabric integration. Args is a JSON object whose shape depends on the specific operation. Returns the upstream response, or { status: 'pending_approval' | 'denied' } when the workspace permission policy gates the call.",
|
|
99
|
+
inputSchema: {
|
|
100
|
+
slug: zod.z.string().describe('Integration slug, e.g. "slack".'),
|
|
101
|
+
operation: zod.z.string().describe(
|
|
102
|
+
'Dot-notation operation, e.g. "messages.send" or "channels.list".'
|
|
103
|
+
),
|
|
104
|
+
args: zod.z.record(zod.z.string(), zod.z.unknown()).optional().describe(
|
|
105
|
+
"Arguments object. Shape depends on the operation."
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
(_0) => __async(null, [_0], function* ({ slug, operation, args }) {
|
|
110
|
+
const integration = fabric.integrations[slug];
|
|
111
|
+
if (!(integration == null ? void 0 : integration.call)) {
|
|
112
|
+
return {
|
|
113
|
+
content: [
|
|
114
|
+
{
|
|
115
|
+
type: "text",
|
|
116
|
+
text: `Integration "${slug}" is not registered for this workspace.`
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
isError: true
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const result = yield integration.call(operation, args != null ? args : {});
|
|
124
|
+
return {
|
|
125
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
126
|
+
};
|
|
127
|
+
} catch (err) {
|
|
128
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
129
|
+
return {
|
|
130
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
131
|
+
isError: true
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
);
|
|
136
|
+
return server;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
exports.createFabricMcpServer = createFabricMcpServer;
|
|
140
|
+
//# sourceMappingURL=index.cjs.map
|
|
141
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fabricorg/sdk-mcp
|
|
5
|
+
*
|
|
6
|
+
* Builds an MCP (Model Context Protocol) server that exposes a Fabric
|
|
7
|
+
* workspace's whole integration catalog as MCP tools — any MCP-compatible
|
|
8
|
+
* agent (Claude Desktop, Cursor, Continue, OpenAI agents, …) can point at
|
|
9
|
+
* one endpoint and get every connected vendor.
|
|
10
|
+
*
|
|
11
|
+
* Three generic tools (corsair-style):
|
|
12
|
+
* - `fabric_list_integrations` — what's connected for this tenant
|
|
13
|
+
* - `fabric_list_operations` — endpoints for one integration
|
|
14
|
+
* - `fabric_call` — execute an operation
|
|
15
|
+
*
|
|
16
|
+
* Usage (stdio transport, e.g. Claude Desktop):
|
|
17
|
+
* import { createFabricMcpServer } from "@fabricorg/sdk-mcp";
|
|
18
|
+
* import { createFabric } from "@fabricorg/sdk";
|
|
19
|
+
* import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
20
|
+
*
|
|
21
|
+
* const fabric = createFabric({ apiKey: process.env.FABRIC_API_KEY });
|
|
22
|
+
* const server = createFabricMcpServer({ fabric });
|
|
23
|
+
* await server.connect(new StdioServerTransport());
|
|
24
|
+
*
|
|
25
|
+
* Or use the prebuilt stdio entry: `import "@fabricorg/sdk-mcp/stdio";`
|
|
26
|
+
* (The `fabric mcp serve` CLI command is the recommended user-facing path.)
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
type FabricLike = {
|
|
30
|
+
integrations: {
|
|
31
|
+
list(): Promise<Array<{
|
|
32
|
+
slug: string;
|
|
33
|
+
name: string;
|
|
34
|
+
status: string;
|
|
35
|
+
mode: string;
|
|
36
|
+
source: string;
|
|
37
|
+
}>>;
|
|
38
|
+
[slug: string]: unknown;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
interface CreateFabricMcpServerOptions {
|
|
42
|
+
/** A configured FabricClient (createFabric) instance. Required. */
|
|
43
|
+
fabric: FabricLike;
|
|
44
|
+
/** Server name reported on the MCP handshake. Default `"fabric"`. */
|
|
45
|
+
name?: string;
|
|
46
|
+
/** Server version. Default `"0.1.0"`. */
|
|
47
|
+
version?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build a configured `McpServer` exposing the workspace catalog. Caller is
|
|
51
|
+
* responsible for `.connect(transport)` so the same server works over stdio,
|
|
52
|
+
* HTTP, or any other MCP transport.
|
|
53
|
+
*/
|
|
54
|
+
declare function createFabricMcpServer(options: CreateFabricMcpServerOptions): McpServer;
|
|
55
|
+
|
|
56
|
+
export { type CreateFabricMcpServerOptions, createFabricMcpServer };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fabricorg/sdk-mcp
|
|
5
|
+
*
|
|
6
|
+
* Builds an MCP (Model Context Protocol) server that exposes a Fabric
|
|
7
|
+
* workspace's whole integration catalog as MCP tools — any MCP-compatible
|
|
8
|
+
* agent (Claude Desktop, Cursor, Continue, OpenAI agents, …) can point at
|
|
9
|
+
* one endpoint and get every connected vendor.
|
|
10
|
+
*
|
|
11
|
+
* Three generic tools (corsair-style):
|
|
12
|
+
* - `fabric_list_integrations` — what's connected for this tenant
|
|
13
|
+
* - `fabric_list_operations` — endpoints for one integration
|
|
14
|
+
* - `fabric_call` — execute an operation
|
|
15
|
+
*
|
|
16
|
+
* Usage (stdio transport, e.g. Claude Desktop):
|
|
17
|
+
* import { createFabricMcpServer } from "@fabricorg/sdk-mcp";
|
|
18
|
+
* import { createFabric } from "@fabricorg/sdk";
|
|
19
|
+
* import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
20
|
+
*
|
|
21
|
+
* const fabric = createFabric({ apiKey: process.env.FABRIC_API_KEY });
|
|
22
|
+
* const server = createFabricMcpServer({ fabric });
|
|
23
|
+
* await server.connect(new StdioServerTransport());
|
|
24
|
+
*
|
|
25
|
+
* Or use the prebuilt stdio entry: `import "@fabricorg/sdk-mcp/stdio";`
|
|
26
|
+
* (The `fabric mcp serve` CLI command is the recommended user-facing path.)
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
type FabricLike = {
|
|
30
|
+
integrations: {
|
|
31
|
+
list(): Promise<Array<{
|
|
32
|
+
slug: string;
|
|
33
|
+
name: string;
|
|
34
|
+
status: string;
|
|
35
|
+
mode: string;
|
|
36
|
+
source: string;
|
|
37
|
+
}>>;
|
|
38
|
+
[slug: string]: unknown;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
interface CreateFabricMcpServerOptions {
|
|
42
|
+
/** A configured FabricClient (createFabric) instance. Required. */
|
|
43
|
+
fabric: FabricLike;
|
|
44
|
+
/** Server name reported on the MCP handshake. Default `"fabric"`. */
|
|
45
|
+
name?: string;
|
|
46
|
+
/** Server version. Default `"0.1.0"`. */
|
|
47
|
+
version?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build a configured `McpServer` exposing the workspace catalog. Caller is
|
|
51
|
+
* responsible for `.connect(transport)` so the same server works over stdio,
|
|
52
|
+
* HTTP, or any other MCP transport.
|
|
53
|
+
*/
|
|
54
|
+
declare function createFabricMcpServer(options: CreateFabricMcpServerOptions): McpServer;
|
|
55
|
+
|
|
56
|
+
export { type CreateFabricMcpServerOptions, createFabricMcpServer };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
var __async = (__this, __arguments, generator) => {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
var fulfilled = (value) => {
|
|
7
|
+
try {
|
|
8
|
+
step(generator.next(value));
|
|
9
|
+
} catch (e) {
|
|
10
|
+
reject(e);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var rejected = (value) => {
|
|
14
|
+
try {
|
|
15
|
+
step(generator.throw(value));
|
|
16
|
+
} catch (e) {
|
|
17
|
+
reject(e);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
21
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
function createFabricMcpServer(options) {
|
|
25
|
+
var _a, _b;
|
|
26
|
+
const fabric = options.fabric;
|
|
27
|
+
const server = new McpServer({
|
|
28
|
+
name: (_a = options.name) != null ? _a : "fabric",
|
|
29
|
+
version: (_b = options.version) != null ? _b : "0.1.0"
|
|
30
|
+
});
|
|
31
|
+
server.registerTool(
|
|
32
|
+
"fabric_list_integrations",
|
|
33
|
+
{
|
|
34
|
+
title: "List Fabric Integrations",
|
|
35
|
+
description: "List integrations connected for the authenticated Fabric workspace. Returns slug, display name, current connection status, permission mode (open/cautious/strict/readonly), and source (plugin/mcp-server/connector).",
|
|
36
|
+
inputSchema: {}
|
|
37
|
+
},
|
|
38
|
+
() => __async(null, null, function* () {
|
|
39
|
+
const integrations = yield fabric.integrations.list();
|
|
40
|
+
return {
|
|
41
|
+
content: [
|
|
42
|
+
{
|
|
43
|
+
type: "text",
|
|
44
|
+
text: JSON.stringify(integrations, null, 2)
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
};
|
|
48
|
+
})
|
|
49
|
+
);
|
|
50
|
+
server.registerTool(
|
|
51
|
+
"fabric_list_operations",
|
|
52
|
+
{
|
|
53
|
+
title: "List Operations for an Integration",
|
|
54
|
+
description: "List the dot-notation operations available on a single Fabric integration. Returns an array of `{ operation, riskLevel, description }`. Supply the slug from `fabric_list_integrations`.",
|
|
55
|
+
inputSchema: {
|
|
56
|
+
slug: z.string().describe(
|
|
57
|
+
'Integration slug, e.g. "slack", "github", "linear".'
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
(_0) => __async(null, [_0], function* ({ slug }) {
|
|
62
|
+
var _a2;
|
|
63
|
+
const integration = fabric.integrations[slug];
|
|
64
|
+
if (!integration) {
|
|
65
|
+
return {
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: "text",
|
|
69
|
+
text: `Integration "${slug}" is not registered for this workspace.`
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
isError: true
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
const ops = yield (_a2 = integration.call) == null ? void 0 : _a2.call(integration, "__operations");
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: "text", text: JSON.stringify(ops, null, 2) }]
|
|
79
|
+
};
|
|
80
|
+
} catch (e) {
|
|
81
|
+
return {
|
|
82
|
+
content: [
|
|
83
|
+
{
|
|
84
|
+
type: "text",
|
|
85
|
+
text: `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.`
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
);
|
|
92
|
+
server.registerTool(
|
|
93
|
+
"fabric_call",
|
|
94
|
+
{
|
|
95
|
+
title: "Call a Fabric Integration Operation",
|
|
96
|
+
description: "Execute an operation on a connected Fabric integration. Args is a JSON object whose shape depends on the specific operation. Returns the upstream response, or { status: 'pending_approval' | 'denied' } when the workspace permission policy gates the call.",
|
|
97
|
+
inputSchema: {
|
|
98
|
+
slug: z.string().describe('Integration slug, e.g. "slack".'),
|
|
99
|
+
operation: z.string().describe(
|
|
100
|
+
'Dot-notation operation, e.g. "messages.send" or "channels.list".'
|
|
101
|
+
),
|
|
102
|
+
args: z.record(z.string(), z.unknown()).optional().describe(
|
|
103
|
+
"Arguments object. Shape depends on the operation."
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
(_0) => __async(null, [_0], function* ({ slug, operation, args }) {
|
|
108
|
+
const integration = fabric.integrations[slug];
|
|
109
|
+
if (!(integration == null ? void 0 : integration.call)) {
|
|
110
|
+
return {
|
|
111
|
+
content: [
|
|
112
|
+
{
|
|
113
|
+
type: "text",
|
|
114
|
+
text: `Integration "${slug}" is not registered for this workspace.`
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
isError: true
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const result = yield integration.call(operation, args != null ? args : {});
|
|
122
|
+
return {
|
|
123
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
124
|
+
};
|
|
125
|
+
} catch (err) {
|
|
126
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
127
|
+
return {
|
|
128
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
129
|
+
isError: true
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
return server;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export { createFabricMcpServer };
|
|
138
|
+
//# sourceMappingURL=index.js.map
|
|
139
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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"]}
|
package/dist/stdio.cjs
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var sdk = require('@fabricorg/sdk');
|
|
4
|
+
var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
5
|
+
var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
6
|
+
var zod = require('zod');
|
|
7
|
+
|
|
8
|
+
var __async = (__this, __arguments, generator) => {
|
|
9
|
+
return new Promise((resolve, reject) => {
|
|
10
|
+
var fulfilled = (value) => {
|
|
11
|
+
try {
|
|
12
|
+
step(generator.next(value));
|
|
13
|
+
} catch (e) {
|
|
14
|
+
reject(e);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var rejected = (value) => {
|
|
18
|
+
try {
|
|
19
|
+
step(generator.throw(value));
|
|
20
|
+
} catch (e) {
|
|
21
|
+
reject(e);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
25
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
function createFabricMcpServer(options) {
|
|
29
|
+
var _a, _b;
|
|
30
|
+
const fabric = options.fabric;
|
|
31
|
+
const server = new mcp_js.McpServer({
|
|
32
|
+
name: (_a = options.name) != null ? _a : "fabric",
|
|
33
|
+
version: (_b = options.version) != null ? _b : "0.1.0"
|
|
34
|
+
});
|
|
35
|
+
server.registerTool(
|
|
36
|
+
"fabric_list_integrations",
|
|
37
|
+
{
|
|
38
|
+
title: "List Fabric Integrations",
|
|
39
|
+
description: "List integrations connected for the authenticated Fabric workspace. Returns slug, display name, current connection status, permission mode (open/cautious/strict/readonly), and source (plugin/mcp-server/connector).",
|
|
40
|
+
inputSchema: {}
|
|
41
|
+
},
|
|
42
|
+
() => __async(null, null, function* () {
|
|
43
|
+
const integrations = yield fabric.integrations.list();
|
|
44
|
+
return {
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: "text",
|
|
48
|
+
text: JSON.stringify(integrations, null, 2)
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
};
|
|
52
|
+
})
|
|
53
|
+
);
|
|
54
|
+
server.registerTool(
|
|
55
|
+
"fabric_list_operations",
|
|
56
|
+
{
|
|
57
|
+
title: "List Operations for an Integration",
|
|
58
|
+
description: "List the dot-notation operations available on a single Fabric integration. Returns an array of `{ operation, riskLevel, description }`. Supply the slug from `fabric_list_integrations`.",
|
|
59
|
+
inputSchema: {
|
|
60
|
+
slug: zod.z.string().describe(
|
|
61
|
+
'Integration slug, e.g. "slack", "github", "linear".'
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
(_0) => __async(null, [_0], function* ({ slug }) {
|
|
66
|
+
var _a2;
|
|
67
|
+
const integration = fabric.integrations[slug];
|
|
68
|
+
if (!integration) {
|
|
69
|
+
return {
|
|
70
|
+
content: [
|
|
71
|
+
{
|
|
72
|
+
type: "text",
|
|
73
|
+
text: `Integration "${slug}" is not registered for this workspace.`
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
isError: true
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const ops = yield (_a2 = integration.call) == null ? void 0 : _a2.call(integration, "__operations");
|
|
81
|
+
return {
|
|
82
|
+
content: [{ type: "text", text: JSON.stringify(ops, null, 2) }]
|
|
83
|
+
};
|
|
84
|
+
} catch (e) {
|
|
85
|
+
return {
|
|
86
|
+
content: [
|
|
87
|
+
{
|
|
88
|
+
type: "text",
|
|
89
|
+
text: `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.`
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
);
|
|
96
|
+
server.registerTool(
|
|
97
|
+
"fabric_call",
|
|
98
|
+
{
|
|
99
|
+
title: "Call a Fabric Integration Operation",
|
|
100
|
+
description: "Execute an operation on a connected Fabric integration. Args is a JSON object whose shape depends on the specific operation. Returns the upstream response, or { status: 'pending_approval' | 'denied' } when the workspace permission policy gates the call.",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
slug: zod.z.string().describe('Integration slug, e.g. "slack".'),
|
|
103
|
+
operation: zod.z.string().describe(
|
|
104
|
+
'Dot-notation operation, e.g. "messages.send" or "channels.list".'
|
|
105
|
+
),
|
|
106
|
+
args: zod.z.record(zod.z.string(), zod.z.unknown()).optional().describe(
|
|
107
|
+
"Arguments object. Shape depends on the operation."
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
(_0) => __async(null, [_0], function* ({ slug, operation, args }) {
|
|
112
|
+
const integration = fabric.integrations[slug];
|
|
113
|
+
if (!(integration == null ? void 0 : integration.call)) {
|
|
114
|
+
return {
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: "text",
|
|
118
|
+
text: `Integration "${slug}" is not registered for this workspace.`
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
isError: true
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const result = yield integration.call(operation, args != null ? args : {});
|
|
126
|
+
return {
|
|
127
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
128
|
+
};
|
|
129
|
+
} catch (err) {
|
|
130
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
131
|
+
return {
|
|
132
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
133
|
+
isError: true
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
);
|
|
138
|
+
return server;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/stdio.ts
|
|
142
|
+
function runStdio() {
|
|
143
|
+
return __async(this, null, function* () {
|
|
144
|
+
const fabric = sdk.createFabric({});
|
|
145
|
+
const server = createFabricMcpServer({ fabric });
|
|
146
|
+
const transport = new stdio_js.StdioServerTransport();
|
|
147
|
+
yield server.connect(transport);
|
|
148
|
+
process.stderr.write("[fabric-mcp] stdio transport connected\n");
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
var isDirectInvocation = typeof process !== "undefined" && Array.isArray(process.argv) && process.argv[1] !== void 0 && (process.argv[1].endsWith("stdio.js") || process.argv[1].endsWith("stdio.cjs"));
|
|
152
|
+
if (isDirectInvocation) {
|
|
153
|
+
runStdio().catch((err) => {
|
|
154
|
+
process.stderr.write(
|
|
155
|
+
`[fabric-mcp] fatal: ${err instanceof Error ? err.message : String(err)}
|
|
156
|
+
`
|
|
157
|
+
);
|
|
158
|
+
process.exit(1);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
exports.runStdio = runStdio;
|
|
163
|
+
//# sourceMappingURL=stdio.cjs.map
|
|
164
|
+
//# sourceMappingURL=stdio.cjs.map
|
|
@@ -0,0 +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"]}
|
package/dist/stdio.d.cts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fabricorg/sdk-mcp/stdio
|
|
3
|
+
*
|
|
4
|
+
* Convenience entry: runs a stdio MCP server using `FABRIC_API_KEY`
|
|
5
|
+
* (and optional `FABRIC_BASE_URL` / `FABRIC_ORG`) from the environment.
|
|
6
|
+
*
|
|
7
|
+
* Designed to be exec'd by an MCP client (Claude Desktop, Cursor, etc.).
|
|
8
|
+
* The `fabric mcp serve` CLI command is the recommended invocation; this
|
|
9
|
+
* file is the underlying script.
|
|
10
|
+
*
|
|
11
|
+
* Stdout is reserved for the JSON-RPC framing — log only to stderr.
|
|
12
|
+
*/
|
|
13
|
+
declare function runStdio(): Promise<void>;
|
|
14
|
+
|
|
15
|
+
export { runStdio };
|
package/dist/stdio.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fabricorg/sdk-mcp/stdio
|
|
3
|
+
*
|
|
4
|
+
* Convenience entry: runs a stdio MCP server using `FABRIC_API_KEY`
|
|
5
|
+
* (and optional `FABRIC_BASE_URL` / `FABRIC_ORG`) from the environment.
|
|
6
|
+
*
|
|
7
|
+
* Designed to be exec'd by an MCP client (Claude Desktop, Cursor, etc.).
|
|
8
|
+
* The `fabric mcp serve` CLI command is the recommended invocation; this
|
|
9
|
+
* file is the underlying script.
|
|
10
|
+
*
|
|
11
|
+
* Stdout is reserved for the JSON-RPC framing — log only to stderr.
|
|
12
|
+
*/
|
|
13
|
+
declare function runStdio(): Promise<void>;
|
|
14
|
+
|
|
15
|
+
export { runStdio };
|
package/dist/stdio.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { createFabric } from '@fabricorg/sdk';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
|
|
6
|
+
var __async = (__this, __arguments, generator) => {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
var fulfilled = (value) => {
|
|
9
|
+
try {
|
|
10
|
+
step(generator.next(value));
|
|
11
|
+
} catch (e) {
|
|
12
|
+
reject(e);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var rejected = (value) => {
|
|
16
|
+
try {
|
|
17
|
+
step(generator.throw(value));
|
|
18
|
+
} catch (e) {
|
|
19
|
+
reject(e);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
23
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
function createFabricMcpServer(options) {
|
|
27
|
+
var _a, _b;
|
|
28
|
+
const fabric = options.fabric;
|
|
29
|
+
const server = new McpServer({
|
|
30
|
+
name: (_a = options.name) != null ? _a : "fabric",
|
|
31
|
+
version: (_b = options.version) != null ? _b : "0.1.0"
|
|
32
|
+
});
|
|
33
|
+
server.registerTool(
|
|
34
|
+
"fabric_list_integrations",
|
|
35
|
+
{
|
|
36
|
+
title: "List Fabric Integrations",
|
|
37
|
+
description: "List integrations connected for the authenticated Fabric workspace. Returns slug, display name, current connection status, permission mode (open/cautious/strict/readonly), and source (plugin/mcp-server/connector).",
|
|
38
|
+
inputSchema: {}
|
|
39
|
+
},
|
|
40
|
+
() => __async(null, null, function* () {
|
|
41
|
+
const integrations = yield fabric.integrations.list();
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: "text",
|
|
46
|
+
text: JSON.stringify(integrations, null, 2)
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
};
|
|
50
|
+
})
|
|
51
|
+
);
|
|
52
|
+
server.registerTool(
|
|
53
|
+
"fabric_list_operations",
|
|
54
|
+
{
|
|
55
|
+
title: "List Operations for an Integration",
|
|
56
|
+
description: "List the dot-notation operations available on a single Fabric integration. Returns an array of `{ operation, riskLevel, description }`. Supply the slug from `fabric_list_integrations`.",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
slug: z.string().describe(
|
|
59
|
+
'Integration slug, e.g. "slack", "github", "linear".'
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
(_0) => __async(null, [_0], function* ({ slug }) {
|
|
64
|
+
var _a2;
|
|
65
|
+
const integration = fabric.integrations[slug];
|
|
66
|
+
if (!integration) {
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: "text",
|
|
71
|
+
text: `Integration "${slug}" is not registered for this workspace.`
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
isError: true
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const ops = yield (_a2 = integration.call) == null ? void 0 : _a2.call(integration, "__operations");
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: "text", text: JSON.stringify(ops, null, 2) }]
|
|
81
|
+
};
|
|
82
|
+
} catch (e) {
|
|
83
|
+
return {
|
|
84
|
+
content: [
|
|
85
|
+
{
|
|
86
|
+
type: "text",
|
|
87
|
+
text: `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.`
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
);
|
|
94
|
+
server.registerTool(
|
|
95
|
+
"fabric_call",
|
|
96
|
+
{
|
|
97
|
+
title: "Call a Fabric Integration Operation",
|
|
98
|
+
description: "Execute an operation on a connected Fabric integration. Args is a JSON object whose shape depends on the specific operation. Returns the upstream response, or { status: 'pending_approval' | 'denied' } when the workspace permission policy gates the call.",
|
|
99
|
+
inputSchema: {
|
|
100
|
+
slug: z.string().describe('Integration slug, e.g. "slack".'),
|
|
101
|
+
operation: z.string().describe(
|
|
102
|
+
'Dot-notation operation, e.g. "messages.send" or "channels.list".'
|
|
103
|
+
),
|
|
104
|
+
args: z.record(z.string(), z.unknown()).optional().describe(
|
|
105
|
+
"Arguments object. Shape depends on the operation."
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
(_0) => __async(null, [_0], function* ({ slug, operation, args }) {
|
|
110
|
+
const integration = fabric.integrations[slug];
|
|
111
|
+
if (!(integration == null ? void 0 : integration.call)) {
|
|
112
|
+
return {
|
|
113
|
+
content: [
|
|
114
|
+
{
|
|
115
|
+
type: "text",
|
|
116
|
+
text: `Integration "${slug}" is not registered for this workspace.`
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
isError: true
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const result = yield integration.call(operation, args != null ? args : {});
|
|
124
|
+
return {
|
|
125
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
126
|
+
};
|
|
127
|
+
} catch (err) {
|
|
128
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
129
|
+
return {
|
|
130
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
131
|
+
isError: true
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
);
|
|
136
|
+
return server;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/stdio.ts
|
|
140
|
+
function runStdio() {
|
|
141
|
+
return __async(this, null, function* () {
|
|
142
|
+
const fabric = createFabric({});
|
|
143
|
+
const server = createFabricMcpServer({ fabric });
|
|
144
|
+
const transport = new StdioServerTransport();
|
|
145
|
+
yield server.connect(transport);
|
|
146
|
+
process.stderr.write("[fabric-mcp] stdio transport connected\n");
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
var isDirectInvocation = typeof process !== "undefined" && Array.isArray(process.argv) && process.argv[1] !== void 0 && (process.argv[1].endsWith("stdio.js") || process.argv[1].endsWith("stdio.cjs"));
|
|
150
|
+
if (isDirectInvocation) {
|
|
151
|
+
runStdio().catch((err) => {
|
|
152
|
+
process.stderr.write(
|
|
153
|
+
`[fabric-mcp] fatal: ${err instanceof Error ? err.message : String(err)}
|
|
154
|
+
`
|
|
155
|
+
);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export { runStdio };
|
|
161
|
+
//# sourceMappingURL=stdio.js.map
|
|
162
|
+
//# sourceMappingURL=stdio.js.map
|
|
@@ -0,0 +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"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fabricorg/sdk-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server adapter for @fabricorg/sdk — expose a Fabric workspace as MCP tools",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"fabric",
|
|
7
|
+
"mcp",
|
|
8
|
+
"model-context-protocol",
|
|
9
|
+
"agent"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://fabric.pro",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"require": "./dist/index.cjs"
|
|
19
|
+
},
|
|
20
|
+
"./stdio": {
|
|
21
|
+
"types": "./dist/stdio.d.ts",
|
|
22
|
+
"import": "./dist/stdio.js",
|
|
23
|
+
"require": "./dist/stdio.cjs"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"main": "./dist/index.cjs",
|
|
27
|
+
"module": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist"
|
|
34
|
+
],
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@fabricorg/sdk": "0.1.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
40
|
+
"zod": "^4.3.6"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@biomejs/biome": "2.3.3",
|
|
44
|
+
"tsup": "^8.0.0",
|
|
45
|
+
"typescript": "5.9.3",
|
|
46
|
+
"@fabricorg/sdk": "0.1.0",
|
|
47
|
+
"@repo/tsconfig": "0.0.0"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsup",
|
|
51
|
+
"dev": "tsup --watch",
|
|
52
|
+
"type-check": "tsc --noEmit"
|
|
53
|
+
}
|
|
54
|
+
}
|