@sxl-studio/bridge 1.2.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/README.md +153 -0
- package/dist/bridge-version.d.ts +4 -0
- package/dist/bridge-version.js +18 -0
- package/dist/bridge-version.js.map +1 -0
- package/dist/command-http.d.ts +13 -0
- package/dist/command-http.js +29 -0
- package/dist/command-http.js.map +1 -0
- package/dist/command-queue.d.ts +29 -0
- package/dist/command-queue.js +168 -0
- package/dist/command-queue.js.map +1 -0
- package/dist/http-api.d.ts +8 -0
- package/dist/http-api.js +146 -0
- package/dist/http-api.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-factory.d.ts +7 -0
- package/dist/mcp-factory.js +30 -0
- package/dist/mcp-factory.js.map +1 -0
- package/dist/mcp-server.d.ts +9 -0
- package/dist/mcp-server.js +16 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/session.d.ts +22 -0
- package/dist/session.js +64 -0
- package/dist/session.js.map +1 -0
- package/dist/sxl-mcp-instructions.d.ts +5 -0
- package/dist/sxl-mcp-instructions.js +36 -0
- package/dist/sxl-mcp-instructions.js.map +1 -0
- package/dist/tools/composition.d.ts +6 -0
- package/dist/tools/composition.js +47 -0
- package/dist/tools/composition.js.map +1 -0
- package/dist/tools/data.d.ts +6 -0
- package/dist/tools/data.js +56 -0
- package/dist/tools/data.js.map +1 -0
- package/dist/tools/diagnostics.d.ts +6 -0
- package/dist/tools/diagnostics.js +70 -0
- package/dist/tools/diagnostics.js.map +1 -0
- package/dist/tools/figma-nodes.d.ts +9 -0
- package/dist/tools/figma-nodes.js +347 -0
- package/dist/tools/figma-nodes.js.map +1 -0
- package/dist/tools/figma-rc-extended.d.ts +6 -0
- package/dist/tools/figma-rc-extended.js +54 -0
- package/dist/tools/figma-rc-extended.js.map +1 -0
- package/dist/tools/git.d.ts +6 -0
- package/dist/tools/git.js +40 -0
- package/dist/tools/git.js.map +1 -0
- package/dist/tools/tokens.d.ts +6 -0
- package/dist/tools/tokens.js +66 -0
- package/dist/tools/tokens.js.map +1 -0
- package/dist/types.d.ts +44 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/ws-server.d.ts +31 -0
- package/dist/ws-server.js +120 -0
- package/dist/ws-server.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared MCP tool registration for SXL Studio Bridge.
|
|
3
|
+
* Used by stdio transport (Cursor spawn) and Streamable HTTP at /mcp (Cursor URL).
|
|
4
|
+
*/
|
|
5
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
|
+
import type { CommandQueue } from "./command-queue.js";
|
|
7
|
+
export declare function createBridgeMcpServer(commandQueue: CommandQueue): McpServer;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared MCP tool registration for SXL Studio Bridge.
|
|
3
|
+
* Used by stdio transport (Cursor spawn) and Streamable HTTP at /mcp (Cursor URL).
|
|
4
|
+
*/
|
|
5
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
|
+
import { registerCompositionTools } from "./tools/composition.js";
|
|
7
|
+
import { registerDataTools } from "./tools/data.js";
|
|
8
|
+
import { registerDiagnosticTools } from "./tools/diagnostics.js";
|
|
9
|
+
import { registerFigmaNodeTools } from "./tools/figma-nodes.js";
|
|
10
|
+
import { registerRcExtendedCanvasTools } from "./tools/figma-rc-extended.js";
|
|
11
|
+
import { registerGitTools } from "./tools/git.js";
|
|
12
|
+
import { registerTokenTools } from "./tools/tokens.js";
|
|
13
|
+
import { SXL_BRIDGE_MCP_INSTRUCTIONS } from "./sxl-mcp-instructions.js";
|
|
14
|
+
export function createBridgeMcpServer(commandQueue) {
|
|
15
|
+
const server = new McpServer({
|
|
16
|
+
name: "@sxl-studio/bridge",
|
|
17
|
+
version: "1.2.0",
|
|
18
|
+
}, {
|
|
19
|
+
instructions: SXL_BRIDGE_MCP_INSTRUCTIONS,
|
|
20
|
+
});
|
|
21
|
+
registerTokenTools(server, commandQueue);
|
|
22
|
+
registerCompositionTools(server, commandQueue);
|
|
23
|
+
registerDataTools(server, commandQueue);
|
|
24
|
+
registerDiagnosticTools(server, commandQueue);
|
|
25
|
+
registerFigmaNodeTools(server, commandQueue);
|
|
26
|
+
registerRcExtendedCanvasTools(server, commandQueue);
|
|
27
|
+
registerGitTools(server, commandQueue);
|
|
28
|
+
return server;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=mcp-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-factory.js","sourceRoot":"","sources":["../src/mcp-factory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAExE,MAAM,UAAU,qBAAqB,CAAC,YAA0B;IAC9D,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EAAE,2BAA2B;KAC1C,CACF,CAAC;IAEF,kBAAkB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACzC,wBAAwB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC/C,iBAAiB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACxC,uBAAuB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC9C,sBAAsB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC7C,6BAA6B,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACpD,gBAAgB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAEvC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server for SXL Studio Bridge (stdio transport).
|
|
3
|
+
*
|
|
4
|
+
* Optional: Cursor can use HTTP MCP at http://127.0.0.1:{BRIDGE_PORT}/mcp instead
|
|
5
|
+
* (see http-api.ts) so the IDE does not need to spawn this process.
|
|
6
|
+
*/
|
|
7
|
+
import type { CommandQueue } from "./command-queue.js";
|
|
8
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
|
+
export declare function startMcpServer(commandQueue: CommandQueue): Promise<McpServer>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server for SXL Studio Bridge (stdio transport).
|
|
3
|
+
*
|
|
4
|
+
* Optional: Cursor can use HTTP MCP at http://127.0.0.1:{BRIDGE_PORT}/mcp instead
|
|
5
|
+
* (see http-api.ts) so the IDE does not need to spawn this process.
|
|
6
|
+
*/
|
|
7
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
8
|
+
import { createBridgeMcpServer } from "./mcp-factory.js";
|
|
9
|
+
export async function startMcpServer(commandQueue) {
|
|
10
|
+
const server = createBridgeMcpServer(commandQueue);
|
|
11
|
+
const transport = new StdioServerTransport();
|
|
12
|
+
await server.connect(transport);
|
|
13
|
+
console.error("[MCP] SXL Studio Bridge MCP server started (stdio)");
|
|
14
|
+
return server;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAGjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,YAA0B;IAC7D,MAAM,MAAM,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,OAAO,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;IAEpE,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session manager for Bridge server.
|
|
3
|
+
*
|
|
4
|
+
* Tracks plugin connection state and manages heartbeat timeouts.
|
|
5
|
+
*/
|
|
6
|
+
import type { SessionInfo } from "./types.js";
|
|
7
|
+
export declare class SessionManager {
|
|
8
|
+
private _connected;
|
|
9
|
+
private _pluginName;
|
|
10
|
+
private _connectedAt;
|
|
11
|
+
private _lastHeartbeat;
|
|
12
|
+
private _heartbeatCheck;
|
|
13
|
+
private _onDisconnect;
|
|
14
|
+
get connected(): boolean;
|
|
15
|
+
get info(): SessionInfo;
|
|
16
|
+
onDisconnect(handler: () => void): void;
|
|
17
|
+
connect(pluginName?: string): void;
|
|
18
|
+
heartbeat(): void;
|
|
19
|
+
disconnect(): void;
|
|
20
|
+
private startHeartbeatMonitor;
|
|
21
|
+
private stopHeartbeatMonitor;
|
|
22
|
+
}
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session manager for Bridge server.
|
|
3
|
+
*
|
|
4
|
+
* Tracks plugin connection state and manages heartbeat timeouts.
|
|
5
|
+
*/
|
|
6
|
+
const HEARTBEAT_TIMEOUT_MS = 30_000;
|
|
7
|
+
export class SessionManager {
|
|
8
|
+
_connected = false;
|
|
9
|
+
_pluginName = null;
|
|
10
|
+
_connectedAt = null;
|
|
11
|
+
_lastHeartbeat = null;
|
|
12
|
+
_heartbeatCheck = null;
|
|
13
|
+
_onDisconnect = null;
|
|
14
|
+
get connected() {
|
|
15
|
+
return this._connected;
|
|
16
|
+
}
|
|
17
|
+
get info() {
|
|
18
|
+
return {
|
|
19
|
+
connected: this._connected,
|
|
20
|
+
pluginName: this._pluginName,
|
|
21
|
+
connectedAt: this._connectedAt,
|
|
22
|
+
lastHeartbeat: this._lastHeartbeat,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
onDisconnect(handler) {
|
|
26
|
+
this._onDisconnect = handler;
|
|
27
|
+
}
|
|
28
|
+
connect(pluginName) {
|
|
29
|
+
this._connected = true;
|
|
30
|
+
this._pluginName = pluginName ?? "SXL Studio";
|
|
31
|
+
this._connectedAt = Date.now();
|
|
32
|
+
this._lastHeartbeat = Date.now();
|
|
33
|
+
this.startHeartbeatMonitor();
|
|
34
|
+
console.error(`[Session] Plugin connected: ${this._pluginName}`);
|
|
35
|
+
}
|
|
36
|
+
heartbeat() {
|
|
37
|
+
this._lastHeartbeat = Date.now();
|
|
38
|
+
}
|
|
39
|
+
disconnect() {
|
|
40
|
+
this.stopHeartbeatMonitor();
|
|
41
|
+
this._connected = false;
|
|
42
|
+
this._pluginName = null;
|
|
43
|
+
this._connectedAt = null;
|
|
44
|
+
this._lastHeartbeat = null;
|
|
45
|
+
console.error("[Session] Plugin disconnected");
|
|
46
|
+
}
|
|
47
|
+
startHeartbeatMonitor() {
|
|
48
|
+
this.stopHeartbeatMonitor();
|
|
49
|
+
this._heartbeatCheck = setInterval(() => {
|
|
50
|
+
if (this._lastHeartbeat && Date.now() - this._lastHeartbeat > HEARTBEAT_TIMEOUT_MS) {
|
|
51
|
+
console.warn("[Session] Heartbeat timeout — plugin may be unresponsive");
|
|
52
|
+
this.disconnect();
|
|
53
|
+
this._onDisconnect?.();
|
|
54
|
+
}
|
|
55
|
+
}, HEARTBEAT_TIMEOUT_MS / 2);
|
|
56
|
+
}
|
|
57
|
+
stopHeartbeatMonitor() {
|
|
58
|
+
if (this._heartbeatCheck) {
|
|
59
|
+
clearInterval(this._heartbeatCheck);
|
|
60
|
+
this._heartbeatCheck = null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAEpC,MAAM,OAAO,cAAc;IACjB,UAAU,GAAG,KAAK,CAAC;IACnB,WAAW,GAAkB,IAAI,CAAC;IAClC,YAAY,GAAkB,IAAI,CAAC;IACnC,cAAc,GAAkB,IAAI,CAAC;IACrC,eAAe,GAA0C,IAAI,CAAC;IAC9D,aAAa,GAAwB,IAAI,CAAC;IAElD,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,IAAI,IAAI;QACN,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,UAAU;YAC1B,UAAU,EAAE,IAAI,CAAC,WAAW;YAC5B,WAAW,EAAE,IAAI,CAAC,YAAY;YAC9B,aAAa,EAAE,IAAI,CAAC,cAAc;SACnC,CAAC;IACJ,CAAC;IAED,YAAY,CAAC,OAAmB;QAC9B,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;IAC/B,CAAC;IAED,OAAO,CAAC,UAAmB;QACzB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,UAAU,IAAI,YAAY,CAAC;QAC9C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEjC,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAE7B,OAAO,CAAC,KAAK,CAAC,+BAA+B,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,SAAS;QACP,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACnC,CAAC;IAED,UAAU;QACR,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAE3B,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACjD,CAAC;IAEO,qBAAqB;QAC3B,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;YACtC,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,cAAc,GAAG,oBAAoB,EAAE,CAAC;gBACnF,OAAO,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;gBACzE,IAAI,CAAC,UAAU,EAAE,CAAC;gBAClB,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;YACzB,CAAC;QACH,CAAC,EAAE,oBAAoB,GAAG,CAAC,CAAC,CAAC;IAC/B,CAAC;IAEO,oBAAoB;QAC1B,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YACpC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC9B,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP server instructions for Cursor / other agents using SXL Studio Bridge.
|
|
3
|
+
* Keep in sync with Plugin/docs/ru/60-remote-connect.md (agent workflows).
|
|
4
|
+
*/
|
|
5
|
+
export const SXL_BRIDGE_MCP_INSTRUCTIONS = `
|
|
6
|
+
You are assisting with Figma via the SXL Studio plugin and this Bridge.
|
|
7
|
+
|
|
8
|
+
## Two MCP servers (recommended)
|
|
9
|
+
- **Official Figma MCP** (often remote): design context from links, selection, native file ops (e.g. use_figma). Parse node-id from figma.com URLs (replace "-" with ":" in node-id).
|
|
10
|
+
- **SXL Studio Bridge (this server)**: plugin-only commands — compositions, token files, Git in the plugin, and whitelisted canvas helpers.
|
|
11
|
+
|
|
12
|
+
## Prerequisites
|
|
13
|
+
1. Bridge running (HTTP/WebSocket on BRIDGE_PORT).
|
|
14
|
+
2. Figma: SXL Studio plugin open, **Remote Connect** session active.
|
|
15
|
+
|
|
16
|
+
## Workflow: component from layout + composition JSON + generate in Figma
|
|
17
|
+
1. Use **Figma MCP** (or user selection) to identify the **nodeId** of the frame/component the user wants as the composition source.
|
|
18
|
+
2. Call **export_composition_json** with \`payload.nodeId\` (or select the node in Figma first). You receive \`compositionJson\`.
|
|
19
|
+
3. In the IDE, **write** a new \`.json\` composition file in the user repo (path they expect under tokens/compositions).
|
|
20
|
+
4. Call **save_token_file** if the file is managed by the plugin, or ensure the plugin sees the file via normal sync.
|
|
21
|
+
5. Call **generate_composition** or **apply_composition** with \`fileId\` / \`compositionName\` as required by the project.
|
|
22
|
+
|
|
23
|
+
## Workflow: documentation in Figma
|
|
24
|
+
**Template in Figma:** duplicate a template subtree under the doc page, then place an instance of the new component.
|
|
25
|
+
- **duplicate_subtree**: \`sourceNodeId\` (template root), \`targetParentId\` (e.g. doc section), optional \`offsetX\` / \`offsetY\`.
|
|
26
|
+
- **create_component_instance**: \`mainComponentId\` (local COMPONENT) or \`componentKey\` (published library), optional \`parentId\`, \`x\`, \`y\`.
|
|
27
|
+
|
|
28
|
+
**Template from repo:** build section text in the IDE, then **apply_documentation_payload** with \`targetRootId\` and \`entries: [{ layerName, text }]\` matching text layer names under the duplicated template.
|
|
29
|
+
|
|
30
|
+
## Canvas tools
|
|
31
|
+
Atomic node tools (create_frame, create_text, set_node_fill, etc.) execute in the plugin sandbox. They must stay on the whitelist — do not assume a tool exists until documented in Bridge release notes.
|
|
32
|
+
|
|
33
|
+
## Stability
|
|
34
|
+
If a command fails, check: Remote Connect connected, Bridge port matches, plugin version supports the commandType, and composition tier for composition commands.
|
|
35
|
+
`.trim();
|
|
36
|
+
//# sourceMappingURL=sxl-mcp-instructions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sxl-mcp-instructions.js","sourceRoot":"","sources":["../src/sxl-mcp-instructions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,2BAA2B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8B1C,CAAC,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tools for Composition operations.
|
|
3
|
+
*/
|
|
4
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import type { CommandQueue } from "../command-queue.js";
|
|
6
|
+
export declare function registerCompositionTools(server: McpServer, queue: CommandQueue): void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tools for Composition operations.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
export function registerCompositionTools(server, queue) {
|
|
6
|
+
server.tool("generate_composition", "Generate a Figma component (or ComponentSet) from a composition JSON file. Creates the component structure, applies styles, binds variables. The fileId can be an internal file ID or a file path like 'compositions/MyButton/MyButton.json'.", {
|
|
7
|
+
fileId: z.string().describe("File path (e.g. 'compositions/MyButton/MyButton.json') or internal file ID"),
|
|
8
|
+
compositionName: z.string().optional().describe("Component name from JSON (e.g. 'MyButton') — used as fallback if fileId doesn't resolve"),
|
|
9
|
+
}, async ({ fileId, compositionName }) => {
|
|
10
|
+
const result = await queue.execute("generate_composition", { fileId, compositionName });
|
|
11
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
12
|
+
});
|
|
13
|
+
server.tool("apply_composition", "Apply a composition JSON to an existing Figma component. Updates structure, styles, and bindings without re-creating. The fileId can be an internal file ID or a file path.", {
|
|
14
|
+
fileId: z.string().describe("File path (e.g. 'compositions/MyButton/MyButton.json') or internal file ID"),
|
|
15
|
+
compositionName: z.string().optional().describe("Component name from JSON — used as fallback"),
|
|
16
|
+
}, async ({ fileId, compositionName }) => {
|
|
17
|
+
const result = await queue.execute("apply_composition", { fileId, compositionName });
|
|
18
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
19
|
+
});
|
|
20
|
+
server.tool("preview_composition", "Preview a composition JSON without applying it. Returns parsed structure and any validation errors. The fileId can be an internal file ID or a file path.", {
|
|
21
|
+
fileId: z.string().describe("File path (e.g. 'compositions/MyButton/MyButton.json') or internal file ID"),
|
|
22
|
+
}, async ({ fileId }) => {
|
|
23
|
+
const result = await queue.execute("preview_composition", { fileId });
|
|
24
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
25
|
+
});
|
|
26
|
+
server.tool("check_composition_linked", "Check if a composition is linked to an existing component in the Figma file.", { compositionName: z.string().describe("Name of the composition to check") }, async ({ compositionName }) => {
|
|
27
|
+
const result = await queue.execute("check_composition_linked", { compositionName });
|
|
28
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
29
|
+
});
|
|
30
|
+
server.tool("inspect_selection", "Inspect the currently selected nodes in Figma. Returns token bindings, composition status, drift status, and node hierarchy.", {}, async () => {
|
|
31
|
+
const result = await queue.execute("inspect_selection");
|
|
32
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
33
|
+
});
|
|
34
|
+
server.tool("export_composition_json", "Export the selected node (or a node by ID) as composition JSON string, same format as Dev Tool codegen. Requires design mode with a selection unless nodeId is set.", {
|
|
35
|
+
nodeId: z
|
|
36
|
+
.string()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("Figma node id. Omit to use current selection (first selected node)."),
|
|
39
|
+
}, async ({ nodeId }) => {
|
|
40
|
+
const payload = {};
|
|
41
|
+
if (nodeId)
|
|
42
|
+
payload.nodeId = nodeId;
|
|
43
|
+
const result = await queue.execute("export_composition_json", payload);
|
|
44
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=composition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composition.js","sourceRoot":"","sources":["../../src/tools/composition.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tools for Data / Mapping operations.
|
|
3
|
+
*/
|
|
4
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import type { CommandQueue } from "../command-queue.js";
|
|
6
|
+
export declare function registerDataTools(server: McpServer, queue: CommandQueue): void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tools for Data / Mapping operations.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
export function registerDataTools(server, queue) {
|
|
6
|
+
server.tool("apply_mapping", "Apply a data mapping to target nodes in Figma. Maps dataset fields to Figma layers.", {
|
|
7
|
+
mappingId: z.string().describe("ID of the mapping to apply"),
|
|
8
|
+
targetNodes: z.array(z.unknown()).optional().describe("Optional target nodes array"),
|
|
9
|
+
}, async ({ mappingId, targetNodes }) => {
|
|
10
|
+
const result = await queue.execute("apply_mapping", { mappingId, targetNodes: targetNodes ?? [] });
|
|
11
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
12
|
+
});
|
|
13
|
+
server.tool("apply_all_mappings", "Apply all mappings within a scope (selection, page, or document).", { scope: z.string().optional().describe("Scope: selection, page, or document") }, async ({ scope }) => {
|
|
14
|
+
const result = await queue.execute("apply_all_mappings", scope ? { scope } : {});
|
|
15
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
16
|
+
});
|
|
17
|
+
server.tool("count_apply_targets", "Count how many nodes match a mapping scope.", { scope: z.string().describe("Scope: selection, page, or document") }, async ({ scope }) => {
|
|
18
|
+
const result = await queue.execute("count_apply_targets", { scope });
|
|
19
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
20
|
+
});
|
|
21
|
+
server.tool("generate_instances", "Generate component instances from mapping data.", {
|
|
22
|
+
mappingId: z.string().describe("Mapping ID to generate from"),
|
|
23
|
+
rowCount: z.number().nullable().optional().describe("Number of rows to generate (null for all)"),
|
|
24
|
+
}, async ({ mappingId, rowCount }) => {
|
|
25
|
+
const result = await queue.execute("generate_instances", {
|
|
26
|
+
mappingId,
|
|
27
|
+
rowCount: rowCount ?? null,
|
|
28
|
+
scope: "selection",
|
|
29
|
+
});
|
|
30
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
31
|
+
});
|
|
32
|
+
server.tool("apply_image", "Apply an image from URL to the current selection.", {
|
|
33
|
+
url: z.string().describe("Image URL"),
|
|
34
|
+
name: z.string().describe("Image name"),
|
|
35
|
+
}, async ({ url, name }) => {
|
|
36
|
+
const result = await queue.execute("apply_image", { url, name });
|
|
37
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
38
|
+
});
|
|
39
|
+
server.tool("set_node_text", "Set text content on a text layer in the currently selected nodes (or a specific node by ID). If layerName is provided, finds text nodes with that name inside the selection. Otherwise sets text on all text nodes in selection.", {
|
|
40
|
+
text: z.string().describe("Text content to set"),
|
|
41
|
+
layerName: z.string().optional().describe("Name of the text layer to target (e.g. 'label', 'title'). Omit to set all text nodes."),
|
|
42
|
+
nodeId: z.string().optional().describe("Specific Figma node ID. Omit to use current selection."),
|
|
43
|
+
}, async ({ text, layerName, nodeId }) => {
|
|
44
|
+
const result = await queue.execute("set_node_text", { text, layerName, nodeId });
|
|
45
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
46
|
+
});
|
|
47
|
+
server.tool("set_node_property", "Set a component property on a selected instance or component. For instances, sets instance property. For components, sets default value.", {
|
|
48
|
+
propertyName: z.string().describe("Property name (e.g. 'label', 'isIcon', 'size')"),
|
|
49
|
+
propertyValue: z.union([z.string(), z.boolean(), z.number()]).describe("Property value"),
|
|
50
|
+
nodeId: z.string().optional().describe("Specific Figma node ID. Omit to use current selection."),
|
|
51
|
+
}, async ({ propertyName, propertyValue, nodeId }) => {
|
|
52
|
+
const result = await queue.execute("set_node_property", { propertyName, propertyValue, nodeId });
|
|
53
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.js","sourceRoot":"","sources":["../../src/tools/data.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tools for Diagnostics, Recovery, and Code Connect operations.
|
|
3
|
+
*/
|
|
4
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import type { CommandQueue } from "../command-queue.js";
|
|
6
|
+
export declare function registerDiagnosticTools(server: McpServer, queue: CommandQueue): void;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tools for Diagnostics, Recovery, and Code Connect operations.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
export function registerDiagnosticTools(server, queue) {
|
|
6
|
+
// ─── Diagnostics ───
|
|
7
|
+
server.tool("get_plugin_status", "Get current plugin status: editor type, current page, selection, session state.", {}, async () => {
|
|
8
|
+
const result = await queue.execute("get_plugin_status");
|
|
9
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
10
|
+
});
|
|
11
|
+
server.tool("get_selection_summary", "Get detailed information about currently selected nodes in Figma: types, names, bound compositions/templates.", {}, async () => {
|
|
12
|
+
const result = await queue.execute("get_selection_summary");
|
|
13
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
14
|
+
});
|
|
15
|
+
server.tool("get_drift_status", "Get drift status for selected nodes — shows which compositions have diverged from their JSON source.", {}, async () => {
|
|
16
|
+
const result = await queue.execute("get_drift_status");
|
|
17
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
18
|
+
});
|
|
19
|
+
server.tool("get_export_report", "Get information about the last export operation results.", {}, async () => {
|
|
20
|
+
const result = await queue.execute("get_export_report");
|
|
21
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
22
|
+
});
|
|
23
|
+
server.tool("list_token_files", "List all token/composition files loaded in the plugin. Returns file IDs, names, and folder paths. Use this to discover correct file IDs before generating compositions.", {}, async () => {
|
|
24
|
+
const result = await queue.execute("list_token_files");
|
|
25
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
26
|
+
});
|
|
27
|
+
// ─── Recovery ───
|
|
28
|
+
server.tool("rebind_instance", "Rebind one or more instances to a different component.", {
|
|
29
|
+
instanceNodeIds: z.array(z.string()).describe("Node IDs of instances to rebind"),
|
|
30
|
+
componentId: z.string().describe("Target component ID"),
|
|
31
|
+
isKey: z.boolean().optional().describe("Whether componentId is a component key"),
|
|
32
|
+
}, async ({ instanceNodeIds, componentId, isKey }) => {
|
|
33
|
+
const result = await queue.execute("rebind_instance", { instanceNodeIds, componentId, isKey });
|
|
34
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
35
|
+
});
|
|
36
|
+
server.tool("remap_composition_id", "Remap the composition tracking ID on a node to point to a different composition.", {
|
|
37
|
+
nodeId: z.string().describe("Node ID to remap"),
|
|
38
|
+
compositionName: z.string().describe("New composition name"),
|
|
39
|
+
}, async ({ nodeId, compositionName }) => {
|
|
40
|
+
const result = await queue.execute("remap_composition_id", { nodeId, compositionName });
|
|
41
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
42
|
+
});
|
|
43
|
+
server.tool("reapply_compositions", "Re-apply all drifted compositions to restore them to their JSON-defined state.", {}, async () => {
|
|
44
|
+
const result = await queue.execute("reapply_compositions");
|
|
45
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
46
|
+
});
|
|
47
|
+
// ─── Code Connect ───
|
|
48
|
+
server.tool("codeconnect_get_binding", "Get the Code Connect binding for a specific node — the GitLab link and metadata.", { nodeId: z.string().describe("Node ID to get binding for") }, async ({ nodeId }) => {
|
|
49
|
+
const result = await queue.execute("codeconnect_get_binding", { nodeId });
|
|
50
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
51
|
+
});
|
|
52
|
+
server.tool("codeconnect_save_binding", "Save a Code Connect binding on a node — links a Figma component to a GitLab resource.", {
|
|
53
|
+
nodeId: z.string().describe("Node ID to bind"),
|
|
54
|
+
binding: z.object({
|
|
55
|
+
gitlabUrl: z.string().describe("GitLab URL"),
|
|
56
|
+
displayName: z.string().describe("Display name"),
|
|
57
|
+
resourceType: z.enum(["source", "docs", "story", "package"]).describe("Resource type"),
|
|
58
|
+
importPath: z.string().optional().describe("Import path"),
|
|
59
|
+
snippetTemplate: z.string().optional().describe("Code snippet template"),
|
|
60
|
+
}).describe("Code Connect binding data"),
|
|
61
|
+
}, async ({ nodeId, binding }) => {
|
|
62
|
+
const result = await queue.execute("codeconnect_save_binding", { nodeId, binding });
|
|
63
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
64
|
+
});
|
|
65
|
+
server.tool("codeconnect_get_selection_status", "Get Code Connect binding status for all selected nodes.", {}, async () => {
|
|
66
|
+
const result = await queue.execute("codeconnect_get_selection_status");
|
|
67
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/tools/diagnostics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tools for direct Figma node manipulation.
|
|
3
|
+
*
|
|
4
|
+
* These tools give the agent full control over the Figma file:
|
|
5
|
+
* reading nodes, modifying properties, navigation, creation, deletion.
|
|
6
|
+
*/
|
|
7
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
|
+
import type { CommandQueue } from "../command-queue.js";
|
|
9
|
+
export declare function registerFigmaNodeTools(server: McpServer, queue: CommandQueue): void;
|