@gtkx/mcp 1.0.0-rc.4 → 1.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.
Files changed (41) hide show
  1. package/README.md +5 -5
  2. package/dist/app-router.d.ts +1 -3
  3. package/dist/app-router.d.ts.map +1 -1
  4. package/dist/app-router.js +1 -1
  5. package/dist/app-router.js.map +1 -1
  6. package/dist/internal.d.ts +2 -2
  7. package/dist/internal.d.ts.map +1 -1
  8. package/dist/internal.js +2 -2
  9. package/dist/internal.js.map +1 -1
  10. package/dist/protocol/errors.d.ts +3 -1
  11. package/dist/protocol/errors.d.ts.map +1 -1
  12. package/dist/protocol/errors.js +9 -1
  13. package/dist/protocol/errors.js.map +1 -1
  14. package/dist/protocol/schemas.d.ts +16 -2
  15. package/dist/protocol/schemas.d.ts.map +1 -1
  16. package/dist/protocol/schemas.js +10 -3
  17. package/dist/protocol/schemas.js.map +1 -1
  18. package/dist/reference.d.ts +17 -3
  19. package/dist/reference.d.ts.map +1 -1
  20. package/dist/reference.js +123 -64
  21. package/dist/reference.js.map +1 -1
  22. package/dist/server.d.ts +1 -10
  23. package/dist/server.d.ts.map +1 -1
  24. package/dist/server.js +123 -61
  25. package/dist/server.js.map +1 -1
  26. package/dist/socket-server.d.ts +8 -0
  27. package/dist/socket-server.d.ts.map +1 -1
  28. package/dist/socket-server.js +233 -32
  29. package/dist/socket-server.js.map +1 -1
  30. package/dist/transport.d.ts +1 -1
  31. package/dist/transport.d.ts.map +1 -1
  32. package/dist/transport.js.map +1 -1
  33. package/package.json +18 -4
  34. package/src/app-router.ts +1 -1
  35. package/src/internal.ts +4 -0
  36. package/src/protocol/errors.ts +14 -0
  37. package/src/protocol/schemas.ts +30 -4
  38. package/src/reference.ts +205 -84
  39. package/src/server.ts +165 -76
  40. package/src/socket-server.ts +308 -39
  41. package/src/transport.ts +0 -1
package/dist/server.js CHANGED
@@ -1,16 +1,15 @@
1
1
  import { createLogger, installGracefulShutdown } from "@gtkx/utils";
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { createRequire } from "node:module";
5
4
  import { z } from "zod";
5
+ import packageManifest from "../package.json" with { type: "json" };
6
6
  import { AppRouter } from "./app-router.js";
7
7
  import { ConnectionRegistry } from "./connection-registry.js";
8
- import { DEFAULT_SOCKET_PATH, fireEventParams, queryParams, screenshotParams, treeParams, typeParams, widgetIdParams, } from "./protocol/schemas.js";
9
- import { buildReferenceTools, createReferenceProvider, registerReferenceResources } from "./reference.js";
8
+ import { DEFAULT_SOCKET_PATH, DEFAULT_SUBTREE_DEPTH, fireEventParams, MAX_SUBTREE_WIDGETS, queryParams, screenshotParams, treeParams, typeParams, widgetIdParams, widgetPropsParams, } from "./protocol/schemas.js";
9
+ import { buildReferenceTools, createReferenceProvider, registerReferenceResources, } from "./reference.js";
10
10
  import { SocketServer } from "./socket-server.js";
11
11
  import { defineTool, imageContent, registerTool, textContent } from "./tool.js";
12
- const require = createRequire(import.meta.url);
13
- const { version } = require("../package.json");
12
+ const { version } = packageManifest;
14
13
  const log = createLogger("mcp");
15
14
  const APPLICATION_ID_DESCRIPTION = "Application ID to query. If not specified, uses the first connected app.";
16
15
  const WIDGET_ID_DESCRIPTION = "Widget ID obtained from `gtkx_get_widget_tree`, `gtkx_query_widgets`, or `gtkx_get_widget_props`. " +
@@ -19,13 +18,28 @@ const WIDGET_ID_DESCRIPTION = "Widget ID obtained from `gtkx_get_widget_tree`, `
19
18
  const applicationIdShape = { applicationId: z.string().optional().describe(APPLICATION_ID_DESCRIPTION) };
20
19
  const widgetIdShape = {
21
20
  ...applicationIdShape,
22
- widgetId: widgetIdParams.shape.widgetId.describe(WIDGET_ID_DESCRIPTION),
21
+ ...describeParams(widgetIdParams.shape, { widgetId: WIDGET_ID_DESCRIPTION }),
22
+ };
23
+ const widgetPropsShape = {
24
+ ...applicationIdShape,
25
+ ...describeParams(widgetPropsParams.shape, {
26
+ widgetId: WIDGET_ID_DESCRIPTION,
27
+ properties: "GObject property names to read as well, in kebab-case or camelCase (\"current-breakpoint\" or " +
28
+ "\"currentBreakpoint\"). Omit for the summary alone.",
29
+ maxDepth: `How many levels of descendants to include: ${String(DEFAULT_SUBTREE_DEPTH)} by default, and 0 ` +
30
+ `for the widget on its own. At most ${String(MAX_SUBTREE_WIDGETS)} widgets come back whatever ` +
31
+ "the depth, and any widget whose own direct children were left out carries a `hiddenChildren` count.",
32
+ }),
23
33
  };
24
34
  const treeShape = {
25
35
  ...applicationIdShape,
26
- rootId: treeParams.shape.rootId.describe("Render only the subtree rooted at this widget ID (from a prior tree or query). Omit for the whole app."),
27
- maxDepth: treeParams.shape.maxDepth.describe("Limit how many levels deep to render; deeper descendants are summarized with a count. " +
28
- "Combine with rootId to drill in without dumping the whole tree."),
36
+ ...describeParams(treeParams.shape, {
37
+ rootId: "Render only the subtree rooted at this widget ID (from a prior tree or query). Omit for the " +
38
+ "whole app.",
39
+ maxDepth: "Limit how many levels deep to render, and 0 for the root widget on its own; deeper " +
40
+ "descendants are summarized with a count. Combine with rootId to drill in without dumping " +
41
+ "the whole tree.",
42
+ }),
29
43
  };
30
44
  const listAppsShape = {
31
45
  waitForApps: z
@@ -36,25 +50,48 @@ const listAppsShape = {
36
50
  };
37
51
  const queryWidgetsShape = {
38
52
  ...applicationIdShape,
39
- by: queryParams.shape.by.describe("Query type"),
40
- value: queryParams.shape.value.describe("Value to search for"),
41
- options: queryParams.shape.options.describe("Additional query options"),
53
+ ...describeParams(queryParams.shape, {
54
+ by: "Query type",
55
+ value: "Value to search for",
56
+ options: "Additional query options",
57
+ }),
42
58
  };
43
59
  const typeShape = {
44
- ...widgetIdShape,
45
- text: typeParams.shape.text.describe("Text to type"),
46
- clear: typeParams.shape.clear.describe("Clear existing text before typing"),
60
+ ...applicationIdShape,
61
+ ...describeParams(typeParams.shape, {
62
+ widgetId: WIDGET_ID_DESCRIPTION,
63
+ text: "Text to type",
64
+ clear: "Clear existing text before typing",
65
+ }),
47
66
  };
48
67
  const fireEventShape = {
49
- ...widgetIdShape,
50
- signal: fireEventParams.shape.signal.describe("GTK4 signal name to emit"),
51
- args: fireEventParams.shape.args.describe("Arguments to pass to the signal"),
68
+ ...applicationIdShape,
69
+ ...describeParams(fireEventParams.shape, {
70
+ widgetId: WIDGET_ID_DESCRIPTION,
71
+ signal: "GTK4 signal name to emit",
72
+ args: "Arguments to pass to the signal",
73
+ }),
52
74
  };
53
75
  const screenshotShape = {
54
76
  ...applicationIdShape,
55
- windowId: screenshotParams.shape.windowId.describe("Window ID to capture. If not specified, captures the first window."),
56
- path: screenshotParams.shape.path.describe("Absolute path to write the PNG to on the app's machine. If set, the screenshot is saved there " +
57
- "in addition to being returned."),
77
+ ...describeParams(screenshotParams.shape, {
78
+ windowId: "Window ID to capture. If not specified, captures the first window.",
79
+ path: "Absolute path to write the PNG to on the app's machine. If set, the screenshot is saved there " +
80
+ "in addition to being returned.",
81
+ }),
82
+ };
83
+ function describeParams(shape, descriptions) {
84
+ const described = Object.entries(shape).map(([key, schema]) => [
85
+ key,
86
+ schema.describe(descriptions[key]),
87
+ ]);
88
+ return Object.fromEntries(described);
89
+ }
90
+ const connectStdio = async (mcpServer, stop) => {
91
+ const transport = new StdioServerTransport();
92
+ process.stdin.on("end", () => void stop());
93
+ process.stdin.on("close", () => void stop());
94
+ await mcpServer.connect(transport);
58
95
  };
59
96
  const logSocketError = (event) => {
60
97
  const error = event.detail;
@@ -109,6 +146,28 @@ const screenshotTool = (appRouter) => defineTool({
109
146
  return imageContent(result.data, result.mimeType);
110
147
  },
111
148
  });
149
+ const widgetPropsTool = (appRouter) => defineTool({
150
+ name: "gtkx_get_widget_props",
151
+ title: "Get widget properties",
152
+ kind: "readOnly",
153
+ description: "Get a fixed summary of one widget by ID: type, accessible role, name, text, sensitivity, " +
154
+ "visibility, CSS classes, and the same summary for its descendants. The subtree is bounded " +
155
+ `twice: ${String(DEFAULT_SUBTREE_DEPTH)} levels deep unless \`maxDepth\` says otherwise, and ` +
156
+ `${String(MAX_SUBTREE_WIDGETS)} widgets in all, filled breadth first. Wherever either bound ` +
157
+ "cut a branch, that widget carries `hiddenChildren`, the count of its own direct children left " +
158
+ "out rather than of everything below them; call again with that widget's ID to drill in, or " +
159
+ "use `gtkx_get_widget_tree` for a wider map. Pass `properties` to read GObject properties too; " +
160
+ "they come back first in the payload, each under its canonical kebab-case name as " +
161
+ "`{type, value}`, where an enum or flags value is its GType value name, a 64-bit integer a " +
162
+ "decimal string, and an object its GType name plus `widgetId` when it is a widget. Asking for " +
163
+ "a property the widget does not have fails; a value that cannot be marshalled carries a `note` " +
164
+ "instead.",
165
+ inputSchema: widgetPropsShape,
166
+ handler: async ({ applicationId, ...params }) => {
167
+ const result = await appRouter.sendToApp(applicationId, "widget.getProps", params);
168
+ return textContent(JSON.stringify(result, null, 2));
169
+ },
170
+ });
112
171
  function buildInspectionTools(appRouter) {
113
172
  return [
114
173
  listAppsTool(appRouter),
@@ -132,26 +191,17 @@ function buildInspectionTools(appRouter) {
132
191
  name: "gtkx_query_widgets",
133
192
  title: "Query widgets",
134
193
  kind: "readOnly",
135
- description: "Find widgets by role, text, name, or label. Returns matching widgets with their IDs and properties.",
194
+ description: "Find widgets by role, text, name, or label. Returns each match with its ID and the same " +
195
+ "fixed summary `gtkx_get_widget_props` returns, with no descendants: a match that has " +
196
+ "children carries `hiddenChildren`, the count of its direct children left out. Read a " +
197
+ "match's subtree with `gtkx_get_widget_props` or `gtkx_get_widget_tree`.",
136
198
  inputSchema: queryWidgetsShape,
137
199
  handler: async ({ applicationId, ...params }) => {
138
200
  const result = await appRouter.sendToApp(applicationId, "widget.query", params);
139
201
  return textContent(JSON.stringify(result, null, 2));
140
202
  },
141
203
  }),
142
- defineTool({
143
- name: "gtkx_get_widget_props",
144
- title: "Get widget properties",
145
- kind: "readOnly",
146
- description: "Get a fixed summary of one widget by ID: type, accessible role, name, text, sensitivity, " +
147
- "visibility, CSS classes, and the full subtree of descendant widgets. It does not return " +
148
- "arbitrary GObject properties.",
149
- inputSchema: widgetIdShape,
150
- handler: async ({ applicationId, ...params }) => {
151
- const result = await appRouter.sendToApp(applicationId, "widget.getProps", params);
152
- return textContent(JSON.stringify(result, null, 2));
153
- },
154
- }),
204
+ widgetPropsTool(appRouter),
155
205
  screenshotTool(appRouter),
156
206
  ];
157
207
  }
@@ -161,7 +211,9 @@ function buildInteractionTools(appRouter) {
161
211
  name: "gtkx_click",
162
212
  title: "Click widget",
163
213
  kind: "action",
164
- description: "Click a widget. Works with buttons, checkboxes, and other interactive widgets.",
214
+ description: "Click a widget through userEvent.click, with no special case per widget. Works with " +
215
+ "buttons, checkboxes, switches, list and grid rows, tree expanders, and column headers: a " +
216
+ "row is selected, an expander toggles its row's expansion, and a header sorts its column.",
165
217
  inputSchema: widgetIdShape,
166
218
  handler: async ({ applicationId, ...params }) => {
167
219
  await appRouter.sendToApp(applicationId, "widget.click", params);
@@ -186,8 +238,8 @@ function buildInteractionTools(appRouter) {
186
238
  description: "Emit a GTK4 signal on a widget. Use this for custom interactions.",
187
239
  inputSchema: fireEventShape,
188
240
  handler: async ({ applicationId, ...params }) => {
189
- await appRouter.sendToApp(applicationId, "widget.fireEvent", params);
190
- return textContent("Fired event");
241
+ const result = await appRouter.sendToApp(applicationId, "widget.fireEvent", params);
242
+ return textContent(JSON.stringify(result, null, 2));
191
243
  },
192
244
  }),
193
245
  ];
@@ -195,6 +247,35 @@ function buildInteractionTools(appRouter) {
195
247
  function buildTools(appRouter) {
196
248
  return [...buildInspectionTools(appRouter), ...buildInteractionTools(appRouter)];
197
249
  }
250
+ const registerTools = (mcpServer, appRouter, provider) => {
251
+ for (const tool of [...buildTools(appRouter), ...buildReferenceTools(provider)]) {
252
+ registerTool(mcpServer, tool);
253
+ }
254
+ };
255
+ async function stopServer(state) {
256
+ if (state.isStopped) {
257
+ return;
258
+ }
259
+ state.isStopped = true;
260
+ await state.socketServer.stop();
261
+ await state.mcpServer.close();
262
+ }
263
+ async function startServer(state) {
264
+ if (state.isStopped) {
265
+ throw new Error("createMcpServer: a stopped server cannot be started again");
266
+ }
267
+ await state.socketServer.start();
268
+ if (state.isStarted) {
269
+ return;
270
+ }
271
+ state.isStarted = true;
272
+ log.info(`socket server listening on ${state.socketPath}`);
273
+ await connectStdio(state.mcpServer, () => stopServer(state));
274
+ }
275
+ const createServerHandle = (socketServer, mcpServer, socketPath) => {
276
+ const state = { socketServer, mcpServer, socketPath, isStopped: false, isStarted: false };
277
+ return { start: () => startServer(state), stop: () => stopServer(state) };
278
+ };
198
279
  const createMcpServer = (options) => {
199
280
  const socketPath = options.socketPath ?? DEFAULT_SOCKET_PATH;
200
281
  const registry = new ConnectionRegistry();
@@ -209,29 +290,10 @@ const createMcpServer = (options) => {
209
290
  log.info(`app unregistered: ${event.detail}`);
210
291
  });
211
292
  const mcpServer = new McpServer({ name: "gtkx-mcp", version: options.version });
212
- const referenceProvider = createReferenceProvider(() => appRouter.getProjectRoot() ?? process.cwd());
213
- for (const tool of [...buildTools(appRouter), ...buildReferenceTools(referenceProvider)]) {
214
- registerTool(mcpServer, tool);
215
- }
293
+ const referenceProvider = createReferenceProvider({ getAppRoot: () => appRouter.getProjectRoot() });
294
+ registerTools(mcpServer, appRouter, referenceProvider);
216
295
  registerReferenceResources(mcpServer, referenceProvider);
217
- let isStopped = false;
218
- const stop = async () => {
219
- if (isStopped) {
220
- return;
221
- }
222
- isStopped = true;
223
- await socketServer.stop();
224
- await mcpServer.close();
225
- };
226
- const start = async () => {
227
- await socketServer.start();
228
- log.info(`socket server listening on ${socketPath}`);
229
- const transport = new StdioServerTransport();
230
- process.stdin.on("end", () => void stop());
231
- process.stdin.on("close", () => void stop());
232
- await mcpServer.connect(transport);
233
- };
234
- return { start, stop };
296
+ return createServerHandle(socketServer, mcpServer, socketPath);
235
297
  };
236
298
  async function main() {
237
299
  const server = createMcpServer({ version });
@@ -240,5 +302,5 @@ async function main() {
240
302
  });
241
303
  await server.start();
242
304
  }
243
- export { log, createMcpServer, main };
305
+ export { log, main };
244
306
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createLogger, installGracefulShutdown, type Logger } from \"@gtkx/utils\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { createRequire } from \"node:module\";\nimport { z } from \"zod\";\nimport type { ConnectionErrorEvent } from \"./transport.js\";\nimport { type AppRegisteredEvent, AppRouter, type AppUnregisteredEvent } from \"./app-router.js\";\nimport { ConnectionRegistry } from \"./connection-registry.js\";\nimport {\n type AppInfo,\n DEFAULT_SOCKET_PATH,\n fireEventParams,\n queryParams,\n screenshotParams,\n treeParams,\n typeParams,\n widgetIdParams,\n} from \"./protocol/schemas.js\";\nimport { buildReferenceTools, createReferenceProvider, registerReferenceResources } from \"./reference.js\";\nimport { SocketServer } from \"./socket-server.js\";\nimport { defineTool, imageContent, registerTool, textContent, type Tool } from \"./tool.js\";\n\ntype CreateMcpServerOptions = {\n socketPath?: string;\n version: string;\n};\n\ntype McpServerHandle = {\n start(): Promise<void>;\n stop(): Promise<void>;\n};\n\ntype AppWindow = { id: string; title: string | null };\ntype AppWithWindows = AppInfo & { windows?: AppWindow[] };\n\nconst require = createRequire(import.meta.url);\nconst { version } = require(\"../package.json\") as { version: string };\nconst log: Logger = createLogger(\"mcp\");\nconst APPLICATION_ID_DESCRIPTION = \"Application ID to query. If not specified, uses the first connected app.\";\n\nconst WIDGET_ID_DESCRIPTION =\n \"Widget ID obtained from `gtkx_get_widget_tree`, `gtkx_query_widgets`, or `gtkx_get_widget_props`. \" +\n \"IDs are scoped to a single app. An ID stays valid for as long as its widget is mounted and stops \" +\n \"resolving once the widget is unmounted.\";\n\nconst applicationIdShape = { applicationId: z.string().optional().describe(APPLICATION_ID_DESCRIPTION) };\n\nconst widgetIdShape = {\n ...applicationIdShape,\n widgetId: widgetIdParams.shape.widgetId.describe(WIDGET_ID_DESCRIPTION),\n};\n\nconst treeShape = {\n ...applicationIdShape,\n rootId: treeParams.shape.rootId.describe(\n \"Render only the subtree rooted at this widget ID (from a prior tree or query). Omit for the whole app.\",\n ),\n maxDepth: treeParams.shape.maxDepth.describe(\n \"Limit how many levels deep to render; deeper descendants are summarized with a count. \" +\n \"Combine with rootId to drill in without dumping the whole tree.\",\n ),\n};\n\nconst listAppsShape = {\n waitForApps: z\n .boolean()\n .optional()\n .describe(\n \"If true, wait for at least one app to register before returning. Useful when app is still starting.\",\n ),\n timeout: z.number().optional().describe(\"Timeout in milliseconds when waitForApps is true (default: 10000)\"),\n};\n\nconst queryWidgetsShape = {\n ...applicationIdShape,\n by: queryParams.shape.by.describe(\"Query type\"),\n value: queryParams.shape.value.describe(\"Value to search for\"),\n options: queryParams.shape.options.describe(\"Additional query options\"),\n};\n\nconst typeShape = {\n ...widgetIdShape,\n text: typeParams.shape.text.describe(\"Text to type\"),\n clear: typeParams.shape.clear.describe(\"Clear existing text before typing\"),\n};\n\nconst fireEventShape = {\n ...widgetIdShape,\n signal: fireEventParams.shape.signal.describe(\"GTK4 signal name to emit\"),\n args: fireEventParams.shape.args.describe(\"Arguments to pass to the signal\"),\n};\n\nconst screenshotShape = {\n ...applicationIdShape,\n windowId: screenshotParams.shape.windowId.describe(\n \"Window ID to capture. If not specified, captures the first window.\",\n ),\n path: screenshotParams.shape.path.describe(\n \"Absolute path to write the PNG to on the app's machine. If set, the screenshot is saved there \" +\n \"in addition to being returned.\",\n ),\n};\n\nconst logSocketError = (event: Event): void => {\n const error = (event as ConnectionErrorEvent).detail;\n const code = (error as NodeJS.ErrnoException).code;\n\n if (code === \"EPIPE\" || code === \"ECONNRESET\") {\n return;\n }\n\n log.error(`socket error: ${error.message}`);\n};\n\nconst appWithWindows = async (appRouter: AppRouter, app: AppInfo): Promise<AppWithWindows> => {\n try {\n const result = await appRouter.sendToApp<{ windows: AppWindow[] }>(\n app.applicationId,\n \"app.getWindows\",\n {},\n );\n\n return { ...app, windows: result.windows };\n } catch {\n return app;\n }\n};\n\nconst listAppsTool = (appRouter: AppRouter): Tool =>\n defineTool({\n name: \"gtkx_list_apps\",\n title: \"List apps\",\n kind: \"readOnly\",\n description: \"List all connected GTKX applications and their open windows.\",\n inputSchema: listAppsShape,\n handler: async ({ waitForApps, timeout }) => {\n if (waitForApps && !appRouter.hasConnectedApps()) {\n await appRouter.waitForApp(timeout);\n }\n\n const apps = appRouter.getApps();\n const appsWithWindows = await Promise.all(apps.map((app) => appWithWindows(appRouter, app)));\n\n return textContent(JSON.stringify(appsWithWindows, null, 2));\n },\n });\n\nconst screenshotTool = (appRouter: AppRouter): Tool =>\n defineTool({\n name: \"gtkx_take_screenshot\",\n title: \"Take screenshot\",\n kind: \"readOnly\",\n description:\n \"Capture a screenshot of a window. Returns base64-encoded PNG image data, and optionally writes \" +\n \"the PNG to `path` on the app's machine. You can't target widgets from a screenshot; use \" +\n \"`gtkx_get_widget_tree` to find widget IDs for interaction.\",\n inputSchema: screenshotShape,\n handler: async ({ applicationId, ...params }) => {\n const result = await appRouter.sendToApp<{ data: string; mimeType: string; savedPath?: string }>(\n applicationId,\n \"widget.screenshot\",\n params,\n );\n\n if (result.savedPath) {\n return {\n content: [\n { type: \"text\", text: `Screenshot saved to ${result.savedPath}` },\n { type: \"image\", data: result.data, mimeType: result.mimeType },\n ],\n };\n }\n\n return imageContent(result.data, result.mimeType);\n },\n });\n\nfunction buildInspectionTools(appRouter: AppRouter): Tool[] {\n return [\n listAppsTool(appRouter),\n defineTool({\n name: \"gtkx_get_widget_tree\",\n title: \"Widget tree\",\n kind: \"readOnly\",\n description:\n \"Get the widget hierarchy for a connected GTKX app. Returns a tree of widgets with their IDs, \" +\n \"types, roles, and properties. For large apps, pass `maxDepth` for a shallow overview and/or \" +\n \"`rootId` to render just one subtree instead of the whole (possibly truncated) tree.\",\n inputSchema: treeShape,\n handler: async ({ applicationId, rootId, maxDepth }) => {\n const result = await appRouter.sendToApp<{ tree: string }>(applicationId, \"widget.getTree\", {\n rootId,\n maxDepth,\n });\n\n return textContent(result.tree);\n },\n }),\n defineTool({\n name: \"gtkx_query_widgets\",\n title: \"Query widgets\",\n kind: \"readOnly\",\n description:\n \"Find widgets by role, text, name, or label. Returns matching widgets with their IDs and properties.\",\n inputSchema: queryWidgetsShape,\n handler: async ({ applicationId, ...params }) => {\n const result = await appRouter.sendToApp(applicationId, \"widget.query\", params);\n\n return textContent(JSON.stringify(result, null, 2));\n },\n }),\n defineTool({\n name: \"gtkx_get_widget_props\",\n title: \"Get widget properties\",\n kind: \"readOnly\",\n description:\n \"Get a fixed summary of one widget by ID: type, accessible role, name, text, sensitivity, \" +\n \"visibility, CSS classes, and the full subtree of descendant widgets. It does not return \" +\n \"arbitrary GObject properties.\",\n inputSchema: widgetIdShape,\n handler: async ({ applicationId, ...params }) => {\n const result = await appRouter.sendToApp(applicationId, \"widget.getProps\", params);\n\n return textContent(JSON.stringify(result, null, 2));\n },\n }),\n screenshotTool(appRouter),\n ];\n}\n\nfunction buildInteractionTools(appRouter: AppRouter): Tool[] {\n return [\n defineTool({\n name: \"gtkx_click\",\n title: \"Click widget\",\n kind: \"action\",\n description: \"Click a widget. Works with buttons, checkboxes, and other interactive widgets.\",\n inputSchema: widgetIdShape,\n handler: async ({ applicationId, ...params }) => {\n await appRouter.sendToApp(applicationId, \"widget.click\", params);\n\n return textContent(\"Clicked\");\n },\n }),\n defineTool({\n name: \"gtkx_type\",\n title: \"Type text\",\n kind: \"action\",\n description: \"Type text into an editable widget like Entry or TextView\",\n inputSchema: typeShape,\n handler: async ({ applicationId, ...params }) => {\n await appRouter.sendToApp(applicationId, \"widget.type\", params);\n\n return textContent(\"Typed text\");\n },\n }),\n defineTool({\n name: \"gtkx_fire_event\",\n title: \"Fire event\",\n kind: \"action\",\n description: \"Emit a GTK4 signal on a widget. Use this for custom interactions.\",\n inputSchema: fireEventShape,\n handler: async ({ applicationId, ...params }) => {\n await appRouter.sendToApp(applicationId, \"widget.fireEvent\", params);\n\n return textContent(\"Fired event\");\n },\n }),\n ];\n}\n\nfunction buildTools(appRouter: AppRouter): Tool[] {\n return [...buildInspectionTools(appRouter), ...buildInteractionTools(appRouter)];\n}\n\nconst createMcpServer = (options: CreateMcpServerOptions): McpServerHandle => {\n const socketPath = options.socketPath ?? DEFAULT_SOCKET_PATH;\n const registry = new ConnectionRegistry();\n const socketServer = new SocketServer(registry, socketPath);\n const appRouter = new AppRouter(registry);\n registry.addEventListener(\"error\", logSocketError);\n\n appRouter.addEventListener(\"appRegistered\", (event) => {\n const appInfo = (event as AppRegisteredEvent).detail;\n log.info(`app registered: ${appInfo.applicationId} (PID: ${String(appInfo.pid)})`);\n });\n\n appRouter.addEventListener(\"appUnregistered\", (event) => {\n log.info(`app unregistered: ${(event as AppUnregisteredEvent).detail}`);\n });\n\n const mcpServer = new McpServer({ name: \"gtkx-mcp\", version: options.version });\n const referenceProvider = createReferenceProvider(() => appRouter.getProjectRoot() ?? process.cwd());\n\n for (const tool of [...buildTools(appRouter), ...buildReferenceTools(referenceProvider)]) {\n registerTool(mcpServer, tool);\n }\n\n registerReferenceResources(mcpServer, referenceProvider);\n let isStopped = false;\n\n const stop = async (): Promise<void> => {\n if (isStopped) {\n return;\n }\n\n isStopped = true;\n await socketServer.stop();\n await mcpServer.close();\n };\n\n const start = async (): Promise<void> => {\n await socketServer.start();\n log.info(`socket server listening on ${socketPath}`);\n const transport = new StdioServerTransport();\n process.stdin.on(\"end\", () => void stop());\n process.stdin.on(\"close\", () => void stop());\n await mcpServer.connect(transport);\n };\n\n return { start, stop };\n};\n\nasync function main(): Promise<void> {\n const server = createMcpServer({ version });\n\n installGracefulShutdown({\n onSignal: () => server.stop(),\n });\n\n await server.start();\n}\n\nexport { log, createMcpServer, main };\n"]}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createLogger, installGracefulShutdown, type Logger } from \"@gtkx/utils\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport type { ConnectionErrorEvent } from \"./transport.js\";\nimport packageManifest from \"../package.json\" with { type: \"json\" };\nimport { type AppRegisteredEvent, AppRouter, type AppUnregisteredEvent } from \"./app-router.js\";\nimport { ConnectionRegistry } from \"./connection-registry.js\";\nimport {\n type AppInfo,\n DEFAULT_SOCKET_PATH,\n DEFAULT_SUBTREE_DEPTH,\n fireEventParams,\n MAX_SUBTREE_WIDGETS,\n queryParams,\n screenshotParams,\n treeParams,\n typeParams,\n widgetIdParams,\n widgetPropsParams,\n} from \"./protocol/schemas.js\";\nimport {\n buildReferenceTools,\n createReferenceProvider,\n type ReferenceProvider,\n registerReferenceResources,\n} from \"./reference.js\";\nimport { SocketServer } from \"./socket-server.js\";\nimport { defineTool, imageContent, registerTool, textContent, type Tool } from \"./tool.js\";\n\ntype CreateMcpServerOptions = {\n socketPath?: string;\n version: string;\n};\n\ntype McpServerHandle = {\n start(): Promise<void>;\n stop(): Promise<void>;\n};\n\ntype ServerLifecycle = {\n socketServer: SocketServer;\n mcpServer: McpServer;\n socketPath: string;\n isStopped: boolean;\n isStarted: boolean;\n};\n\ntype AppWindow = { id: string; title: string | null };\ntype AppWithWindows = AppInfo & { windows?: AppWindow[] };\n\nconst { version } = packageManifest;\nconst log: Logger = createLogger(\"mcp\");\nconst APPLICATION_ID_DESCRIPTION = \"Application ID to query. If not specified, uses the first connected app.\";\n\nconst WIDGET_ID_DESCRIPTION =\n \"Widget ID obtained from `gtkx_get_widget_tree`, `gtkx_query_widgets`, or `gtkx_get_widget_props`. \" +\n \"IDs are scoped to a single app. An ID stays valid for as long as its widget is mounted and stops \" +\n \"resolving once the widget is unmounted.\";\n\nconst applicationIdShape = { applicationId: z.string().optional().describe(APPLICATION_ID_DESCRIPTION) };\n\nconst widgetIdShape = {\n ...applicationIdShape,\n ...describeParams(widgetIdParams.shape, { widgetId: WIDGET_ID_DESCRIPTION }),\n};\n\nconst widgetPropsShape = {\n ...applicationIdShape,\n ...describeParams(widgetPropsParams.shape, {\n widgetId: WIDGET_ID_DESCRIPTION,\n properties:\n \"GObject property names to read as well, in kebab-case or camelCase (\\\"current-breakpoint\\\" or \" +\n \"\\\"currentBreakpoint\\\"). Omit for the summary alone.\",\n maxDepth:\n `How many levels of descendants to include: ${String(DEFAULT_SUBTREE_DEPTH)} by default, and 0 ` +\n `for the widget on its own. At most ${String(MAX_SUBTREE_WIDGETS)} widgets come back whatever ` +\n \"the depth, and any widget whose own direct children were left out carries a `hiddenChildren` count.\",\n }),\n};\n\nconst treeShape = {\n ...applicationIdShape,\n ...describeParams(treeParams.shape, {\n rootId:\n \"Render only the subtree rooted at this widget ID (from a prior tree or query). Omit for the \" +\n \"whole app.\",\n maxDepth:\n \"Limit how many levels deep to render, and 0 for the root widget on its own; deeper \" +\n \"descendants are summarized with a count. Combine with rootId to drill in without dumping \" +\n \"the whole tree.\",\n }),\n};\n\nconst listAppsShape = {\n waitForApps: z\n .boolean()\n .optional()\n .describe(\n \"If true, wait for at least one app to register before returning. Useful when app is still starting.\",\n ),\n timeout: z.number().optional().describe(\"Timeout in milliseconds when waitForApps is true (default: 10000)\"),\n};\n\nconst queryWidgetsShape = {\n ...applicationIdShape,\n ...describeParams(queryParams.shape, {\n by: \"Query type\",\n value: \"Value to search for\",\n options: \"Additional query options\",\n }),\n};\n\nconst typeShape = {\n ...applicationIdShape,\n ...describeParams(typeParams.shape, {\n widgetId: WIDGET_ID_DESCRIPTION,\n text: \"Text to type\",\n clear: \"Clear existing text before typing\",\n }),\n};\n\nconst fireEventShape = {\n ...applicationIdShape,\n ...describeParams(fireEventParams.shape, {\n widgetId: WIDGET_ID_DESCRIPTION,\n signal: \"GTK4 signal name to emit\",\n args: \"Arguments to pass to the signal\",\n }),\n};\n\nconst screenshotShape = {\n ...applicationIdShape,\n ...describeParams(screenshotParams.shape, {\n windowId: \"Window ID to capture. If not specified, captures the first window.\",\n path:\n \"Absolute path to write the PNG to on the app's machine. If set, the screenshot is saved there \" +\n \"in addition to being returned.\",\n }),\n};\n\nfunction describeParams<Shape extends Record<string, z.ZodType>>(\n shape: Shape,\n descriptions: { [Key in keyof Shape]: string },\n): Shape {\n const described: [string, z.ZodType][] = Object.entries(shape).map(([key, schema]) => [\n key,\n schema.describe(descriptions[key as keyof Shape]),\n ]);\n\n return Object.fromEntries(described) as Shape;\n}\n\nconst connectStdio = async (mcpServer: McpServer, stop: () => Promise<void>): Promise<void> => {\n const transport = new StdioServerTransport();\n process.stdin.on(\"end\", () => void stop());\n process.stdin.on(\"close\", () => void stop());\n await mcpServer.connect(transport);\n};\n\nconst logSocketError = (event: Event): void => {\n const error = (event as ConnectionErrorEvent).detail;\n const code = (error as NodeJS.ErrnoException).code;\n\n if (code === \"EPIPE\" || code === \"ECONNRESET\") {\n return;\n }\n\n log.error(`socket error: ${error.message}`);\n};\n\nconst appWithWindows = async (appRouter: AppRouter, app: AppInfo): Promise<AppWithWindows> => {\n try {\n const result = await appRouter.sendToApp<{ windows: AppWindow[] }>(\n app.applicationId,\n \"app.getWindows\",\n {},\n );\n\n return { ...app, windows: result.windows };\n } catch {\n return app;\n }\n};\n\nconst listAppsTool = (appRouter: AppRouter): Tool =>\n defineTool({\n name: \"gtkx_list_apps\",\n title: \"List apps\",\n kind: \"readOnly\",\n description: \"List all connected GTKX applications and their open windows.\",\n inputSchema: listAppsShape,\n handler: async ({ waitForApps, timeout }) => {\n if (waitForApps && !appRouter.hasConnectedApps()) {\n await appRouter.waitForApp(timeout);\n }\n\n const apps = appRouter.getApps();\n const appsWithWindows = await Promise.all(apps.map((app) => appWithWindows(appRouter, app)));\n\n return textContent(JSON.stringify(appsWithWindows, null, 2));\n },\n });\n\nconst screenshotTool = (appRouter: AppRouter): Tool =>\n defineTool({\n name: \"gtkx_take_screenshot\",\n title: \"Take screenshot\",\n kind: \"readOnly\",\n description:\n \"Capture a screenshot of a window. Returns base64-encoded PNG image data, and optionally writes \" +\n \"the PNG to `path` on the app's machine. You can't target widgets from a screenshot; use \" +\n \"`gtkx_get_widget_tree` to find widget IDs for interaction.\",\n inputSchema: screenshotShape,\n handler: async ({ applicationId, ...params }) => {\n const result = await appRouter.sendToApp<{ data: string; mimeType: string; savedPath?: string }>(\n applicationId,\n \"widget.screenshot\",\n params,\n );\n\n if (result.savedPath) {\n return {\n content: [\n { type: \"text\", text: `Screenshot saved to ${result.savedPath}` },\n { type: \"image\", data: result.data, mimeType: result.mimeType },\n ],\n };\n }\n\n return imageContent(result.data, result.mimeType);\n },\n });\n\nconst widgetPropsTool = (appRouter: AppRouter): Tool =>\n defineTool({\n name: \"gtkx_get_widget_props\",\n title: \"Get widget properties\",\n kind: \"readOnly\",\n description:\n \"Get a fixed summary of one widget by ID: type, accessible role, name, text, sensitivity, \" +\n \"visibility, CSS classes, and the same summary for its descendants. The subtree is bounded \" +\n `twice: ${String(DEFAULT_SUBTREE_DEPTH)} levels deep unless \\`maxDepth\\` says otherwise, and ` +\n `${String(MAX_SUBTREE_WIDGETS)} widgets in all, filled breadth first. Wherever either bound ` +\n \"cut a branch, that widget carries `hiddenChildren`, the count of its own direct children left \" +\n \"out rather than of everything below them; call again with that widget's ID to drill in, or \" +\n \"use `gtkx_get_widget_tree` for a wider map. Pass `properties` to read GObject properties too; \" +\n \"they come back first in the payload, each under its canonical kebab-case name as \" +\n \"`{type, value}`, where an enum or flags value is its GType value name, a 64-bit integer a \" +\n \"decimal string, and an object its GType name plus `widgetId` when it is a widget. Asking for \" +\n \"a property the widget does not have fails; a value that cannot be marshalled carries a `note` \" +\n \"instead.\",\n inputSchema: widgetPropsShape,\n handler: async ({ applicationId, ...params }) => {\n const result = await appRouter.sendToApp(applicationId, \"widget.getProps\", params);\n\n return textContent(JSON.stringify(result, null, 2));\n },\n });\n\nfunction buildInspectionTools(appRouter: AppRouter): Tool[] {\n return [\n listAppsTool(appRouter),\n defineTool({\n name: \"gtkx_get_widget_tree\",\n title: \"Widget tree\",\n kind: \"readOnly\",\n description:\n \"Get the widget hierarchy for a connected GTKX app. Returns a tree of widgets with their IDs, \" +\n \"types, roles, and properties. For large apps, pass `maxDepth` for a shallow overview and/or \" +\n \"`rootId` to render just one subtree instead of the whole (possibly truncated) tree.\",\n inputSchema: treeShape,\n handler: async ({ applicationId, rootId, maxDepth }) => {\n const result = await appRouter.sendToApp<{ tree: string }>(applicationId, \"widget.getTree\", {\n rootId,\n maxDepth,\n });\n\n return textContent(result.tree);\n },\n }),\n defineTool({\n name: \"gtkx_query_widgets\",\n title: \"Query widgets\",\n kind: \"readOnly\",\n description:\n \"Find widgets by role, text, name, or label. Returns each match with its ID and the same \" +\n \"fixed summary `gtkx_get_widget_props` returns, with no descendants: a match that has \" +\n \"children carries `hiddenChildren`, the count of its direct children left out. Read a \" +\n \"match's subtree with `gtkx_get_widget_props` or `gtkx_get_widget_tree`.\",\n inputSchema: queryWidgetsShape,\n handler: async ({ applicationId, ...params }) => {\n const result = await appRouter.sendToApp(applicationId, \"widget.query\", params);\n\n return textContent(JSON.stringify(result, null, 2));\n },\n }),\n widgetPropsTool(appRouter),\n screenshotTool(appRouter),\n ];\n}\n\nfunction buildInteractionTools(appRouter: AppRouter): Tool[] {\n return [\n defineTool({\n name: \"gtkx_click\",\n title: \"Click widget\",\n kind: \"action\",\n description:\n \"Click a widget through userEvent.click, with no special case per widget. Works with \" +\n \"buttons, checkboxes, switches, list and grid rows, tree expanders, and column headers: a \" +\n \"row is selected, an expander toggles its row's expansion, and a header sorts its column.\",\n inputSchema: widgetIdShape,\n handler: async ({ applicationId, ...params }) => {\n await appRouter.sendToApp(applicationId, \"widget.click\", params);\n\n return textContent(\"Clicked\");\n },\n }),\n defineTool({\n name: \"gtkx_type\",\n title: \"Type text\",\n kind: \"action\",\n description: \"Type text into an editable widget like Entry or TextView\",\n inputSchema: typeShape,\n handler: async ({ applicationId, ...params }) => {\n await appRouter.sendToApp(applicationId, \"widget.type\", params);\n\n return textContent(\"Typed text\");\n },\n }),\n defineTool({\n name: \"gtkx_fire_event\",\n title: \"Fire event\",\n kind: \"action\",\n description: \"Emit a GTK4 signal on a widget. Use this for custom interactions.\",\n inputSchema: fireEventShape,\n handler: async ({ applicationId, ...params }) => {\n const result = await appRouter.sendToApp(applicationId, \"widget.fireEvent\", params);\n\n return textContent(JSON.stringify(result, null, 2));\n },\n }),\n ];\n}\n\nfunction buildTools(appRouter: AppRouter): Tool[] {\n return [...buildInspectionTools(appRouter), ...buildInteractionTools(appRouter)];\n}\n\nconst registerTools = (mcpServer: McpServer, appRouter: AppRouter, provider: ReferenceProvider): void => {\n for (const tool of [...buildTools(appRouter), ...buildReferenceTools(provider)]) {\n registerTool(mcpServer, tool);\n }\n};\n\nasync function stopServer(state: ServerLifecycle): Promise<void> {\n if (state.isStopped) {\n return;\n }\n\n state.isStopped = true;\n await state.socketServer.stop();\n await state.mcpServer.close();\n}\n\nasync function startServer(state: ServerLifecycle): Promise<void> {\n if (state.isStopped) {\n throw new Error(\"createMcpServer: a stopped server cannot be started again\");\n }\n\n await state.socketServer.start();\n\n if (state.isStarted) {\n return;\n }\n\n state.isStarted = true;\n log.info(`socket server listening on ${state.socketPath}`);\n await connectStdio(state.mcpServer, () => stopServer(state));\n}\n\nconst createServerHandle = (socketServer: SocketServer, mcpServer: McpServer, socketPath: string): McpServerHandle => {\n const state: ServerLifecycle = { socketServer, mcpServer, socketPath, isStopped: false, isStarted: false };\n\n return { start: () => startServer(state), stop: () => stopServer(state) };\n};\n\nconst createMcpServer = (options: CreateMcpServerOptions): McpServerHandle => {\n const socketPath = options.socketPath ?? DEFAULT_SOCKET_PATH;\n const registry = new ConnectionRegistry();\n const socketServer = new SocketServer(registry, socketPath);\n const appRouter = new AppRouter(registry);\n registry.addEventListener(\"error\", logSocketError);\n\n appRouter.addEventListener(\"appRegistered\", (event) => {\n const appInfo = (event as AppRegisteredEvent).detail;\n log.info(`app registered: ${appInfo.applicationId} (PID: ${String(appInfo.pid)})`);\n });\n\n appRouter.addEventListener(\"appUnregistered\", (event) => {\n log.info(`app unregistered: ${(event as AppUnregisteredEvent).detail}`);\n });\n\n const mcpServer = new McpServer({ name: \"gtkx-mcp\", version: options.version });\n const referenceProvider = createReferenceProvider({ getAppRoot: () => appRouter.getProjectRoot() });\n registerTools(mcpServer, appRouter, referenceProvider);\n registerReferenceResources(mcpServer, referenceProvider);\n\n return createServerHandle(socketServer, mcpServer, socketPath);\n};\n\nasync function main(): Promise<void> {\n const server = createMcpServer({ version });\n\n installGracefulShutdown({\n onSignal: () => server.stop(),\n });\n\n await server.start();\n}\n\nexport { log, main };\n"]}
@@ -3,7 +3,15 @@ declare class SocketServer {
3
3
  private server;
4
4
  private socketPath;
5
5
  private registry;
6
+ private boundInode;
7
+ private startup;
6
8
  constructor(registry: ConnectionRegistry, socketPath?: string);
9
+ private listen;
10
+ private listenPrivately;
11
+ private bind;
12
+ private open;
13
+ private settleStartup;
14
+ private release;
7
15
  start(): Promise<void>;
8
16
  stop(): Promise<void>;
9
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"socket-server.d.ts","sourceRoot":"","sources":["../src/socket-server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAiCnE,cAAM,YAAY;IACd,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAqB;gBAEzB,QAAQ,EAAE,kBAAkB,EAAE,UAAU,GAAE,MAA4B;IAK5E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAmB9B;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"socket-server.d.ts","sourceRoot":"","sources":["../src/socket-server.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AA0PnE,cAAM,YAAY;IACd,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,OAAO,CAA8B;gBAEjC,QAAQ,EAAE,kBAAkB,EAAE,UAAU,GAAE,MAA4B;IAKlF,OAAO,CAAC,MAAM;YAoBA,eAAe;YASf,IAAI;IAclB,OAAO,CAAC,IAAI;YAIE,aAAa;YASb,OAAO;IASf,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAetB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAa9B;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}