@gtkx/mcp 1.6.0 → 2.0.0-beta.10
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 +47 -44
- package/dist/app-router.d.ts +6 -2
- package/dist/app-router.d.ts.map +1 -1
- package/dist/app-router.js +56 -19
- package/dist/app-router.js.map +1 -1
- package/dist/internal.d.ts +2 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -1
- package/dist/internal.js.map +1 -1
- package/dist/protocol/schemas.d.ts +1 -2
- package/dist/protocol/schemas.d.ts.map +1 -1
- package/dist/protocol/schemas.js +1 -7
- package/dist/protocol/schemas.js.map +1 -1
- package/dist/reference.d.ts.map +1 -1
- package/dist/reference.js +25 -46
- package/dist/reference.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +92 -44
- package/dist/server.js.map +1 -1
- package/dist/socket-path.d.ts +11 -0
- package/dist/socket-path.d.ts.map +1 -0
- package/dist/socket-path.js +74 -0
- package/dist/socket-path.js.map +1 -0
- package/dist/socket-server.d.ts +3 -1
- package/dist/socket-server.d.ts.map +1 -1
- package/dist/socket-server.js +48 -32
- package/dist/socket-server.js.map +1 -1
- package/package.json +15 -9
- package/src/app-router.ts +77 -22
- package/src/internal.ts +4 -1
- package/src/protocol/schemas.ts +0 -9
- package/src/reference.ts +27 -53
- package/src/server.ts +114 -46
- package/src/socket-path.ts +103 -0
- package/src/socket-server.ts +61 -37
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { loadConfig } from \"@gtkx/config\";\nimport { type McpSettings, resolveMcpSettings } from \"@gtkx/config/internal\";\nimport { createLogger, installGracefulShutdown, type Logger } from \"@gtkx/utils\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { parseArgs } from \"node:util\";\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 { selectTools } from \"./tool-filter.js\";\nimport { defineTool, imageContent, registerTool, textContent, textError, type Tool } from \"./tool.js\";\n\ntype CreateMcpServerOptions = {\n socketPath?: string;\n version: string;\n settings?: McpSettings;\n};\n\ntype ServerOptions = {\n cwd?: string;\n tools?: string[];\n isReadOnly?: boolean;\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 DEFAULT_SETTINGS: McpSettings = { tools: [], isReadOnly: false };\n\nconst INSTRUCTIONS =\n \"The widget tools drive a GTKX app running under `gtkx dev`: they read \" +\n \"its live widget tree, query it by accessible role and name, click and type, and capture screenshots. \" +\n \"They fail until an app is running, so start `gtkx dev` first. The reference tools answer from the \" +\n \"bindings generated for a specific project, so they describe that project's GIR libraries rather than \" +\n \"GTK in general; prefer them over recalled GTK knowledge, which is usually C, PyGObject or GJS and \" +\n \"does not apply here.\\n\\n\" +\n \"Widget IDs are valid only while the widget is mounted. After a dialog closes, a list re-renders, or \" +\n \"fast refresh patches a component, re-read the tree or re-run the query instead of reusing an ID.\";\n\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 returnImage: z\n .boolean()\n .optional()\n .describe(\n \"Whether to return the PNG as image content, true by default. Pass false together with `path` \" +\n \"to save the screenshot and get back only where it landed, which keeps the image out of the \" +\n \"conversation until something actually needs to look at it.\",\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 screenshotResult = (\n result: { data: string; mimeType: string; savedPath?: string },\n shouldReturnImage: boolean,\n): CallToolResult => {\n if (result.savedPath === undefined) {\n return shouldReturnImage\n ? imageContent(result.data, result.mimeType)\n : textError(\n \"Nothing to return: `returnImage` was false and no `path` was given, so the screenshot was \" +\n \"neither saved nor returned. Pass `path` to save it, or leave `returnImage` unset.\",\n );\n }\n\n const saved = { type: \"text\", text: `Screenshot saved to ${result.savedPath}` } as const;\n\n if (!shouldReturnImage) {\n return { content: [saved] };\n }\n\n return { content: [saved, { type: \"image\", data: result.data, mimeType: result.mimeType }] };\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, returnImage, ...params }) => {\n const result = await appRouter.sendToApp<{ data: string; mimeType: string; savedPath?: string }>(\n applicationId,\n \"widget.screenshot\",\n params,\n );\n\n return screenshotResult(result, returnImage !== false);\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 = (\n mcpServer: McpServer,\n appRouter: AppRouter,\n provider: ReferenceProvider,\n settings: McpSettings,\n): void => {\n const tools = selectTools([...buildTools(appRouter), ...buildReferenceTools(provider)], settings);\n\n if (tools.length === 0) {\n log.warn(\"no tools matched the configured filter; the server is registering none\");\n }\n\n for (const tool of tools) {\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 }, { instructions: INSTRUCTIONS });\n const referenceProvider = createReferenceProvider({ getAppRoot: () => appRouter.getProjectRoot() });\n registerTools(mcpServer, appRouter, referenceProvider, options.settings ?? DEFAULT_SETTINGS);\n registerReferenceResources(mcpServer, referenceProvider);\n\n return createServerHandle(socketServer, mcpServer, socketPath);\n};\n\nconst configuredSettings = async (cwd: string): Promise<McpSettings> => {\n try {\n const { config } = await loadConfig(cwd);\n\n return resolveMcpSettings(config);\n } catch {\n return DEFAULT_SETTINGS;\n }\n};\n\nconst resolveSettings = async (options: ServerOptions): Promise<McpSettings> => {\n const configured = await configuredSettings(options.cwd ?? process.cwd());\n\n return {\n tools: options.tools ?? configured.tools,\n isReadOnly: options.isReadOnly ?? configured.isReadOnly,\n };\n};\n\nconst splitPatterns = (values: string[]): string[] =>\n values.flatMap((value) => value.split(\",\")).map((value) => value.trim()).filter((value) => value.length > 0);\n\nconst parseServerArgs = (argv: string[]): ServerOptions => {\n const { values } = parseArgs({\n args: argv,\n options: {\n tools: { type: \"string\", multiple: true },\n \"read-only\": { type: \"boolean\" },\n },\n allowPositionals: false,\n });\n\n const tools = values.tools === undefined ? undefined : splitPatterns(values.tools);\n\n return {\n ...(tools !== undefined && { tools }),\n ...(values[\"read-only\"] !== undefined && { isReadOnly: values[\"read-only\"] }),\n };\n};\n\nasync function main(options: ServerOptions = {}): Promise<void> {\n const settings = await resolveSettings(options);\n const server = createMcpServer({ version, settings });\n\n installGracefulShutdown({\n onSignal: () => server.stop(),\n });\n\n await server.start();\n}\n\nexport { log, main, main as runMcpServer, parseServerArgs };\n"]}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { loadConfig } from \"@gtkx/config\";\nimport { type McpSettings, resolveMcpSettings } from \"@gtkx/config/internal\";\nimport { createLogger, installGracefulShutdown, type Logger } from \"@gtkx/utils\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { parseArgs } from \"node:util\";\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_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 { resolveMcpSocketAddress } from \"./socket-path.js\";\nimport { SocketServer } from \"./socket-server.js\";\nimport { selectTools } from \"./tool-filter.js\";\nimport { defineTool, imageContent, registerTool, textContent, textError, type Tool } from \"./tool.js\";\n\ntype CreateMcpServerOptions = {\n socketPath?: string;\n version: string;\n settings?: McpSettings;\n};\n\ntype ServerOptions = {\n cwd?: string;\n tools?: string[];\n isReadOnly?: boolean;\n};\n\ntype McpServerHandle = {\n start(): Promise<void>;\n stop(): Promise<void>;\n};\n\ntype ServerLifecycle = {\n socketServer: SocketServer;\n mcpServer: McpServer;\n appRouter: AppRouter;\n socketPath: string;\n isStopRequested: boolean;\n startup: Promise<void> | null;\n shutdown: Promise<void> | null;\n};\n\ntype AppWindow = { id: string; title: string | null };\ntype AppWithWindows = AppInfo & { windows?: AppWindow[] };\n\nconst { version } = packageManifest;\nconst log: Logger = createLogger(\"mcp\");\nconst DEFAULT_SETTINGS: McpSettings = { tools: [], isReadOnly: false };\n\nconst INSTRUCTIONS =\n \"The widget tools drive a GTKX app running under `gtkx dev`: they read \" +\n \"its live widget tree, query it by accessible role and name, click and type, and capture screenshots. \" +\n \"They wait briefly for a starting app, so start `gtkx dev` before or alongside a widget request. \" +\n \"The reference tools answer from the \" +\n \"bindings generated for a specific project, so they describe that project's GIR libraries rather than \" +\n \"the GNOME platform in general; prefer them over recalled Adwaita or GTK knowledge, which is usually C, \" +\n \"PyGObject or GJS and does not apply here.\\n\\n\" +\n \"Widget IDs are valid only while the widget is mounted. After a dialog closes, a list re-renders, or \" +\n \"fast refresh patches a component, re-read the tree or re-run the query instead of reusing an ID.\";\n\nconst APPLICATION_ID_DESCRIPTION =\n \"Application ID to query. If not specified, uses the first connected app. The tool waits briefly for the \" +\n \"requested app to register.\";\n\nconst APP_TIMEOUT_DESCRIPTION = \"Milliseconds to wait for the requested app to register (default: 10000).\";\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 = {\n applicationId: z.string().optional().describe(APPLICATION_ID_DESCRIPTION),\n appTimeout: z.number().int().nonnegative().optional().describe(APP_TIMEOUT_DESCRIPTION),\n};\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: \"GObject 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 returnImage: z\n .boolean()\n .optional()\n .describe(\n \"Whether to return the PNG as image content, true by default. Pass false together with `path` \" +\n \"to save the screenshot and get back only where it landed, which keeps the image out of the \" +\n \"conversation until something actually needs to look at it.\",\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:\n \"List connected GTKX applications and their open windows. \" +\n \"Returns the current snapshot immediately unless waitForApps is true.\",\n inputSchema: listAppsShape,\n handler: async ({ waitForApps, timeout }) => {\n if (waitForApps && !appRouter.hasConnectedApps()) {\n await appRouter.waitForApp(undefined, 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 screenshotResult = (\n result: { data: string; mimeType: string; savedPath?: string },\n shouldReturnImage: boolean,\n): CallToolResult => {\n if (result.savedPath === undefined) {\n return shouldReturnImage\n ? imageContent(result.data, result.mimeType)\n : textError(\n \"Nothing to return: `returnImage` was false and no `path` was given, so the screenshot was \" +\n \"neither saved nor returned. Pass `path` to save it, or leave `returnImage` unset.\",\n );\n }\n\n const saved = { type: \"text\", text: `Screenshot saved to ${result.savedPath}` } as const;\n\n if (!shouldReturnImage) {\n return { content: [saved] };\n }\n\n return { content: [saved, { type: \"image\", data: result.data, mimeType: result.mimeType }] };\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, appTimeout, returnImage, ...params }) => {\n const result = await appRouter.sendToApp<{ data: string; mimeType: string; savedPath?: string }>(\n applicationId,\n \"widget.screenshot\",\n params,\n appTimeout,\n );\n\n return screenshotResult(result, returnImage !== false);\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, appTimeout, ...params }) => {\n const result = await appRouter.sendToApp(applicationId, \"widget.getProps\", params, appTimeout);\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, appTimeout, rootId, maxDepth }) => {\n const result = await appRouter.sendToApp<{ tree: string }>(applicationId, \"widget.getTree\", {\n rootId,\n maxDepth,\n }, appTimeout);\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, appTimeout, ...params }) => {\n const result = await appRouter.sendToApp(applicationId, \"widget.query\", params, appTimeout);\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, appTimeout, ...params }) => {\n await appRouter.sendToApp(applicationId, \"widget.click\", params, appTimeout);\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, appTimeout, ...params }) => {\n await appRouter.sendToApp(applicationId, \"widget.type\", params, appTimeout);\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 GObject signal on a widget. Use this for custom interactions.\",\n inputSchema: fireEventShape,\n handler: async ({ applicationId, appTimeout, ...params }) => {\n const result = await appRouter.sendToApp(applicationId, \"widget.fireEvent\", params, appTimeout);\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 = (\n mcpServer: McpServer,\n appRouter: AppRouter,\n provider: ReferenceProvider,\n settings: McpSettings,\n): void => {\n const tools = selectTools([...buildTools(appRouter), ...buildReferenceTools(provider)], settings);\n\n if (tools.length === 0) {\n log.warn(\"no tools matched the configured filter; the server is registering none\");\n }\n\n for (const tool of tools) {\n registerTool(mcpServer, tool);\n }\n};\n\nconst stoppedServerError = (): Error => new Error(\"createMcpServer: a stopped server cannot be started again\");\n\nconst wasStopRequested = (state: ServerLifecycle): boolean => state.isStopRequested;\n\nfunction stopServer(state: ServerLifecycle): Promise<void> {\n if (state.shutdown !== null) {\n return state.shutdown;\n }\n\n state.isStopRequested = true;\n state.appRouter.dispose();\n const startup = state.startup;\n const shutdown = (async (): Promise<void> => {\n if (startup !== null) {\n await Promise.allSettled([startup]);\n }\n\n await state.socketServer.stop();\n await state.mcpServer.close();\n })();\n\n state.shutdown = shutdown;\n\n return shutdown;\n}\n\nfunction startServer(state: ServerLifecycle): Promise<void> {\n if (wasStopRequested(state)) {\n return Promise.reject(stoppedServerError());\n }\n\n if (state.startup !== null) {\n return state.startup;\n }\n\n const startup = (async (): Promise<void> => {\n try {\n await state.socketServer.start();\n\n if (wasStopRequested(state)) {\n return;\n }\n\n log.info(`socket server listening on ${state.socketPath}`);\n await connectStdio(state.mcpServer, () => stopServer(state));\n } catch (error) {\n if (!wasStopRequested(state)) {\n state.isStopRequested = true;\n state.appRouter.dispose();\n await state.socketServer.stop();\n await state.mcpServer.close();\n }\n\n throw error;\n }\n })();\n\n state.startup = startup;\n\n return startup;\n}\n\nconst createServerHandle = (\n socketServer: SocketServer,\n mcpServer: McpServer,\n appRouter: AppRouter,\n socketPath: string,\n): McpServerHandle => {\n const state: ServerLifecycle = {\n socketServer,\n mcpServer,\n appRouter,\n socketPath,\n isStopRequested: false,\n startup: null,\n shutdown: null,\n };\n\n return { start: () => startServer(state), stop: () => stopServer(state) };\n};\n\nconst createMcpServer = (options: CreateMcpServerOptions): McpServerHandle => {\n const socketAddress = resolveMcpSocketAddress(options.socketPath);\n const socketPath = socketAddress.path;\n\n if (socketAddress.fallbackDirectory !== null) {\n log.warn(`MCP socket path exceeds the safe Unix byte budget; using private fallback ${socketPath}`);\n }\n\n const registry = new ConnectionRegistry();\n const socketServer = new SocketServer(registry, socketAddress);\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 }, { instructions: INSTRUCTIONS });\n const referenceProvider = createReferenceProvider({ getAppRoot: () => appRouter.getProjectRoot() });\n registerTools(mcpServer, appRouter, referenceProvider, options.settings ?? DEFAULT_SETTINGS);\n registerReferenceResources(mcpServer, referenceProvider);\n\n return createServerHandle(socketServer, mcpServer, appRouter, socketPath);\n};\n\nconst configuredSettings = async (cwd: string): Promise<McpSettings> => {\n try {\n const { config } = await loadConfig(cwd);\n\n return resolveMcpSettings(config);\n } catch {\n return DEFAULT_SETTINGS;\n }\n};\n\nconst resolveSettings = async (options: ServerOptions): Promise<McpSettings> => {\n const configured = await configuredSettings(options.cwd ?? process.cwd());\n\n return {\n tools: options.tools ?? configured.tools,\n isReadOnly: options.isReadOnly ?? configured.isReadOnly,\n };\n};\n\nconst splitPatterns = (values: string[]): string[] =>\n values.flatMap((value) => value.split(\",\")).map((value) => value.trim()).filter((value) => value.length > 0);\n\nconst parseServerArgs = (argv: string[]): ServerOptions => {\n const { values } = parseArgs({\n args: argv,\n options: {\n tools: { type: \"string\", multiple: true },\n \"read-only\": { type: \"boolean\" },\n },\n allowPositionals: false,\n });\n\n const tools = values.tools === undefined ? undefined : splitPatterns(values.tools);\n\n return {\n ...(tools !== undefined && { tools }),\n ...(values[\"read-only\"] !== undefined && { isReadOnly: values[\"read-only\"] }),\n };\n};\n\nasync function main(options: ServerOptions = {}): Promise<void> {\n const settings = await resolveSettings(options);\n const server = createMcpServer({ version, settings });\n\n installGracefulShutdown({\n onSignal: () => server.stop(),\n });\n\n await server.start();\n}\n\nexport { log, main, main as runMcpServer, parseServerArgs };\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type McpSocketAddress = {
|
|
2
|
+
path: string;
|
|
3
|
+
fallbackDirectory: string | null;
|
|
4
|
+
};
|
|
5
|
+
declare const MCP_SOCKET_PATH_ENV = "GTKX_MCP_SOCKET_PATH";
|
|
6
|
+
declare const resolveMcpSocketAddress: (providedPath?: string) => McpSocketAddress;
|
|
7
|
+
declare const resolveMcpSocketPath: (providedPath?: string) => string;
|
|
8
|
+
declare const prepareMcpSocketAddress: (address: McpSocketAddress) => void;
|
|
9
|
+
declare const cleanupMcpSocketAddress: (address: McpSocketAddress) => void;
|
|
10
|
+
export { cleanupMcpSocketAddress, MCP_SOCKET_PATH_ENV, prepareMcpSocketAddress, resolveMcpSocketAddress, resolveMcpSocketPath, type McpSocketAddress, };
|
|
11
|
+
//# sourceMappingURL=socket-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket-path.d.ts","sourceRoot":"","sources":["../src/socket-path.ts"],"names":[],"mappings":"AAKA,KAAK,gBAAgB,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC,CAAC;AAEF,QAAA,MAAM,mBAAmB,yBAAyB,CAAC;AAsDnD,QAAA,MAAM,uBAAuB,GAAI,eAAe,MAAM,KAAG,gBAMxD,CAAC;AAEF,QAAA,MAAM,oBAAoB,GAAI,eAAe,MAAM,KAAG,MAAoD,CAAC;AAE3G,QAAA,MAAM,uBAAuB,GAAI,SAAS,gBAAgB,KAAG,IAI5D,CAAC;AAEF,QAAA,MAAM,uBAAuB,GAAI,SAAS,gBAAgB,KAAG,IAa5D,CAAC;AAEF,OAAO,EACH,uBAAuB,EACvB,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,KAAK,gBAAgB,GACxB,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { lstatSync, mkdirSync, rmdirSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
const MCP_SOCKET_PATH_ENV = "GTKX_MCP_SOCKET_PATH";
|
|
6
|
+
const SOCKET_NAME = "gtkx-mcp.sock";
|
|
7
|
+
const SOCKET_PATH_BYTE_LIMIT = 100;
|
|
8
|
+
const SHORT_SOCKET_ROOT = "/tmp";
|
|
9
|
+
const socketCandidate = () => process.env[MCP_SOCKET_PATH_ENV] ?? join(process.env.XDG_RUNTIME_DIR ?? tmpdir(), SOCKET_NAME);
|
|
10
|
+
const currentUserId = () => {
|
|
11
|
+
const getuid = process.getuid;
|
|
12
|
+
if (getuid === undefined) {
|
|
13
|
+
throw new Error("GTKX MCP Unix sockets require a platform with user IDs");
|
|
14
|
+
}
|
|
15
|
+
return getuid();
|
|
16
|
+
};
|
|
17
|
+
const verifyPrivateDirectory = (directory, userId) => {
|
|
18
|
+
const entry = lstatSync(directory);
|
|
19
|
+
if (!entry.isDirectory() || entry.uid !== userId || (entry.mode & 0o777) !== 0o700) {
|
|
20
|
+
throw new Error(`GTKX MCP fallback socket directory is not private: ${directory}`);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const ensurePrivateDirectory = (directory, userId) => {
|
|
24
|
+
try {
|
|
25
|
+
mkdirSync(directory, { mode: 0o700 });
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (error.code !== "EEXIST") {
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
verifyPrivateDirectory(directory, userId);
|
|
33
|
+
};
|
|
34
|
+
const fallbackAddress = (candidate) => {
|
|
35
|
+
const userId = currentUserId();
|
|
36
|
+
const digest = createHash("sha256").update(candidate).digest("hex").slice(0, 24);
|
|
37
|
+
const fallbackDirectory = join(SHORT_SOCKET_ROOT, `gtkx-mcp-${String(userId)}-${digest}`);
|
|
38
|
+
try {
|
|
39
|
+
verifyPrivateDirectory(fallbackDirectory, userId);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (error.code !== "ENOENT") {
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return { path: join(fallbackDirectory, "socket"), fallbackDirectory };
|
|
47
|
+
};
|
|
48
|
+
const resolveMcpSocketAddress = (providedPath) => {
|
|
49
|
+
const candidate = providedPath ?? socketCandidate();
|
|
50
|
+
return Buffer.byteLength(candidate) <= SOCKET_PATH_BYTE_LIMIT
|
|
51
|
+
? { path: candidate, fallbackDirectory: null }
|
|
52
|
+
: fallbackAddress(candidate);
|
|
53
|
+
};
|
|
54
|
+
const resolveMcpSocketPath = (providedPath) => resolveMcpSocketAddress(providedPath).path;
|
|
55
|
+
const prepareMcpSocketAddress = (address) => {
|
|
56
|
+
if (address.fallbackDirectory !== null) {
|
|
57
|
+
ensurePrivateDirectory(address.fallbackDirectory, currentUserId());
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const cleanupMcpSocketAddress = (address) => {
|
|
61
|
+
const directory = address.fallbackDirectory;
|
|
62
|
+
if (directory === null) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
verifyPrivateDirectory(directory, currentUserId());
|
|
67
|
+
rmdirSync(directory);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
export { cleanupMcpSocketAddress, MCP_SOCKET_PATH_ENV, prepareMcpSocketAddress, resolveMcpSocketAddress, resolveMcpSocketPath, };
|
|
74
|
+
//# sourceMappingURL=socket-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket-path.js","sourceRoot":"","sources":["../src/socket-path.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { lstatSync, mkdirSync, rmdirSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\ntype McpSocketAddress = {\n path: string;\n fallbackDirectory: string | null;\n};\n\nconst MCP_SOCKET_PATH_ENV = \"GTKX_MCP_SOCKET_PATH\";\nconst SOCKET_NAME = \"gtkx-mcp.sock\";\nconst SOCKET_PATH_BYTE_LIMIT = 100;\nconst SHORT_SOCKET_ROOT = \"/tmp\";\n\nconst socketCandidate = (): string =>\n process.env[MCP_SOCKET_PATH_ENV] ?? join(process.env.XDG_RUNTIME_DIR ?? tmpdir(), SOCKET_NAME);\n\nconst currentUserId = (): number => {\n const getuid = process.getuid;\n\n if (getuid === undefined) {\n throw new Error(\"GTKX MCP Unix sockets require a platform with user IDs\");\n }\n\n return getuid();\n};\n\nconst verifyPrivateDirectory = (directory: string, userId: number): void => {\n const entry = lstatSync(directory);\n\n if (!entry.isDirectory() || entry.uid !== userId || (entry.mode & 0o777) !== 0o700) {\n throw new Error(`GTKX MCP fallback socket directory is not private: ${directory}`);\n }\n};\n\nconst ensurePrivateDirectory = (directory: string, userId: number): void => {\n try {\n mkdirSync(directory, { mode: 0o700 });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw error;\n }\n }\n\n verifyPrivateDirectory(directory, userId);\n};\n\nconst fallbackAddress = (candidate: string): McpSocketAddress => {\n const userId = currentUserId();\n const digest = createHash(\"sha256\").update(candidate).digest(\"hex\").slice(0, 24);\n const fallbackDirectory = join(SHORT_SOCKET_ROOT, `gtkx-mcp-${String(userId)}-${digest}`);\n\n try {\n verifyPrivateDirectory(fallbackDirectory, userId);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n }\n\n return { path: join(fallbackDirectory, \"socket\"), fallbackDirectory };\n};\n\nconst resolveMcpSocketAddress = (providedPath?: string): McpSocketAddress => {\n const candidate = providedPath ?? socketCandidate();\n\n return Buffer.byteLength(candidate) <= SOCKET_PATH_BYTE_LIMIT\n ? { path: candidate, fallbackDirectory: null }\n : fallbackAddress(candidate);\n};\n\nconst resolveMcpSocketPath = (providedPath?: string): string => resolveMcpSocketAddress(providedPath).path;\n\nconst prepareMcpSocketAddress = (address: McpSocketAddress): void => {\n if (address.fallbackDirectory !== null) {\n ensurePrivateDirectory(address.fallbackDirectory, currentUserId());\n }\n};\n\nconst cleanupMcpSocketAddress = (address: McpSocketAddress): void => {\n const directory = address.fallbackDirectory;\n\n if (directory === null) {\n return;\n }\n\n try {\n verifyPrivateDirectory(directory, currentUserId());\n rmdirSync(directory);\n } catch {\n return;\n }\n};\n\nexport {\n cleanupMcpSocketAddress,\n MCP_SOCKET_PATH_ENV,\n prepareMcpSocketAddress,\n resolveMcpSocketAddress,\n resolveMcpSocketPath,\n type McpSocketAddress,\n};\n"]}
|
package/dist/socket-server.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { ConnectionRegistry } from "./connection-registry.js";
|
|
2
|
+
import { type McpSocketAddress } from "./socket-path.js";
|
|
2
3
|
declare class SocketServer {
|
|
3
4
|
private server;
|
|
4
5
|
private socketPath;
|
|
5
6
|
private registry;
|
|
7
|
+
private address;
|
|
6
8
|
private boundInode;
|
|
7
9
|
private startup;
|
|
8
|
-
constructor(registry: ConnectionRegistry,
|
|
10
|
+
constructor(registry: ConnectionRegistry, address?: McpSocketAddress);
|
|
9
11
|
private listen;
|
|
10
12
|
private listenPrivately;
|
|
11
13
|
private bind;
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AACnE,OAAO,EAEH,KAAK,gBAAgB,EAGxB,MAAM,kBAAkB,CAAC;AAyO1B,cAAM,YAAY;IACd,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,OAAO,CAA8B;gBAEjC,QAAQ,EAAE,kBAAkB,EAAE,OAAO,GAAE,gBAA4C;IAM/F,OAAO,CAAC,MAAM;YAoBA,eAAe;YASf,IAAI;IAgClB,OAAO,CAAC,IAAI;YAWE,aAAa;YASb,OAAO;IAmBf,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAetB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAW9B;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
package/dist/socket-server.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as net from "node:net";
|
|
4
4
|
import { basename, dirname, join, resolve as resolvePath } from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { cleanupMcpSocketAddress, prepareMcpSocketAddress, resolveMcpSocketAddress, } from "./socket-path.js";
|
|
6
6
|
import { connectionErrorEvent } from "./transport.js";
|
|
7
7
|
const PROBE_TIMEOUT_MS = 1000;
|
|
8
8
|
const PROBE_ATTEMPTS = 3;
|
|
@@ -49,11 +49,6 @@ const acquireClaimLock = async (socketPath) => {
|
|
|
49
49
|
}
|
|
50
50
|
return lock;
|
|
51
51
|
};
|
|
52
|
-
const releaseClaimLock = async (lock) => {
|
|
53
|
-
if (lock) {
|
|
54
|
-
await closeServer(lock);
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
52
|
const withClaimLock = async (socketPath, action) => {
|
|
58
53
|
const lock = await acquireClaimLock(socketPath);
|
|
59
54
|
if (lock === null) {
|
|
@@ -110,8 +105,8 @@ const alreadyOwnedError = (socketPath) => new Error(`Another GTKX MCP server alr
|
|
|
110
105
|
const undecidedOwnerError = (socketPath, code) => new Error(`Could not tell whether another GTKX MCP server owns ${socketPath}: probing it failed with ${code}. ` +
|
|
111
106
|
"Leaving the socket in place instead of removing one that may still be serving another session. " +
|
|
112
107
|
"Retry, or delete the file by hand once no server is running.");
|
|
113
|
-
const
|
|
114
|
-
"
|
|
108
|
+
const invalidPathError = (socketPath) => new Error(`The GTKX MCP socket path ${socketPath} exists and is not a socket. ` +
|
|
109
|
+
"Move it, or point XDG_RUNTIME_DIR at a directory where GTKX can create its socket.");
|
|
115
110
|
const listenFailureError = (socketPath, code) => new Error(`Could not create the GTKX MCP socket at ${socketPath}: listening failed with ${code}. ` +
|
|
116
111
|
"Check that its directory exists and is writable.");
|
|
117
112
|
const removeEntry = (target, inode) => {
|
|
@@ -124,8 +119,8 @@ const clearStalePath = async (target) => {
|
|
|
124
119
|
if (entry === null) {
|
|
125
120
|
return { kind: "vacant" };
|
|
126
121
|
}
|
|
127
|
-
if (entry.
|
|
128
|
-
return { kind: "
|
|
122
|
+
if (!entry.isSocket()) {
|
|
123
|
+
return { kind: "invalid" };
|
|
129
124
|
}
|
|
130
125
|
const outcome = await probeUntilConclusive(target);
|
|
131
126
|
if (outcome.kind === "vacant") {
|
|
@@ -138,8 +133,8 @@ const requireVacantPath = async (socketPath) => {
|
|
|
138
133
|
if (verdict.kind === "live") {
|
|
139
134
|
throw alreadyOwnedError(socketPath);
|
|
140
135
|
}
|
|
141
|
-
if (verdict.kind === "
|
|
142
|
-
throw
|
|
136
|
+
if (verdict.kind === "invalid") {
|
|
137
|
+
throw invalidPathError(socketPath);
|
|
143
138
|
}
|
|
144
139
|
if (verdict.kind === "unknown") {
|
|
145
140
|
throw undecidedOwnerError(socketPath, verdict.code);
|
|
@@ -168,24 +163,17 @@ const publishSocket = async (privatePath, socketPath) => {
|
|
|
168
163
|
}
|
|
169
164
|
throw alreadyOwnedError(socketPath);
|
|
170
165
|
};
|
|
171
|
-
const releaseSocketPath = async (socketPath, inode) => {
|
|
172
|
-
const lock = await acquireClaimLock(socketPath);
|
|
173
|
-
try {
|
|
174
|
-
removeEntry(socketPath, inode);
|
|
175
|
-
}
|
|
176
|
-
finally {
|
|
177
|
-
await releaseClaimLock(lock);
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
166
|
class SocketServer {
|
|
181
167
|
server = null;
|
|
182
168
|
socketPath;
|
|
183
169
|
registry;
|
|
170
|
+
address;
|
|
184
171
|
boundInode = null;
|
|
185
172
|
startup = null;
|
|
186
|
-
constructor(registry,
|
|
173
|
+
constructor(registry, address = resolveMcpSocketAddress()) {
|
|
187
174
|
this.registry = registry;
|
|
188
|
-
this.
|
|
175
|
+
this.address = address;
|
|
176
|
+
this.socketPath = address.path;
|
|
189
177
|
}
|
|
190
178
|
listen(privatePath) {
|
|
191
179
|
return new Promise((resolve, reject) => {
|
|
@@ -213,20 +201,41 @@ class SocketServer {
|
|
|
213
201
|
}
|
|
214
202
|
}
|
|
215
203
|
async bind() {
|
|
204
|
+
prepareMcpSocketAddress(this.address);
|
|
216
205
|
const privatePath = privatePathFor(this.socketPath);
|
|
217
206
|
await clearStalePath(privatePath);
|
|
218
207
|
const server = await this.listenPrivately(privatePath);
|
|
208
|
+
const privateInode = inodeFor(privatePath);
|
|
219
209
|
try {
|
|
220
|
-
|
|
210
|
+
if (privateInode === null) {
|
|
211
|
+
throw listenFailureError(this.socketPath, "ENOENT");
|
|
212
|
+
}
|
|
213
|
+
const publishedInode = await publishSocket(privatePath, this.socketPath);
|
|
214
|
+
if (publishedInode !== privateInode) {
|
|
215
|
+
throw listenFailureError(this.socketPath, "ESTALE");
|
|
216
|
+
}
|
|
217
|
+
this.boundInode = privateInode;
|
|
221
218
|
this.server = server;
|
|
222
219
|
}
|
|
223
220
|
catch (error) {
|
|
224
221
|
await closeServer(server);
|
|
222
|
+
if (privateInode !== null) {
|
|
223
|
+
removeEntry(privatePath, privateInode);
|
|
224
|
+
removeEntry(this.socketPath, privateInode);
|
|
225
|
+
}
|
|
225
226
|
throw error;
|
|
226
227
|
}
|
|
227
228
|
}
|
|
228
229
|
open() {
|
|
229
|
-
return withClaimLock(this.socketPath, () =>
|
|
230
|
+
return withClaimLock(this.socketPath, async () => {
|
|
231
|
+
try {
|
|
232
|
+
await this.bind();
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
cleanupMcpSocketAddress(this.address);
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
});
|
|
230
239
|
}
|
|
231
240
|
async settleStartup() {
|
|
232
241
|
const startup = this.startup;
|
|
@@ -235,12 +244,21 @@ class SocketServer {
|
|
|
235
244
|
await Promise.allSettled([startup]);
|
|
236
245
|
}
|
|
237
246
|
}
|
|
238
|
-
async release() {
|
|
247
|
+
async release(server) {
|
|
239
248
|
const inode = this.boundInode;
|
|
249
|
+
await withClaimLock(this.socketPath, async () => {
|
|
250
|
+
this.registry.dispose();
|
|
251
|
+
await closeServer(server);
|
|
252
|
+
try {
|
|
253
|
+
if (inode !== null) {
|
|
254
|
+
removeEntry(this.socketPath, inode);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
finally {
|
|
258
|
+
cleanupMcpSocketAddress(this.address);
|
|
259
|
+
}
|
|
260
|
+
});
|
|
240
261
|
this.boundInode = null;
|
|
241
|
-
if (inode !== null) {
|
|
242
|
-
await releaseSocketPath(this.socketPath, inode);
|
|
243
|
-
}
|
|
244
262
|
}
|
|
245
263
|
async start() {
|
|
246
264
|
this.startup ??= this.open();
|
|
@@ -261,10 +279,8 @@ class SocketServer {
|
|
|
261
279
|
if (!server) {
|
|
262
280
|
return;
|
|
263
281
|
}
|
|
282
|
+
await this.release(server);
|
|
264
283
|
this.server = null;
|
|
265
|
-
this.registry.dispose();
|
|
266
|
-
await closeServer(server);
|
|
267
|
-
await this.release();
|
|
268
284
|
}
|
|
269
285
|
}
|
|
270
286
|
export { SocketServer };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket-server.js","sourceRoot":"","sources":["../src/socket-server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as net from \"node:net\";\nimport { basename, dirname, join, resolve as resolvePath } from \"node:path\";\nimport type { ConnectionRegistry } from \"./connection-registry.js\";\nimport { DEFAULT_SOCKET_PATH } from \"./protocol/schemas.js\";\nimport { connectionErrorEvent } from \"./transport.js\";\n\ntype ProbeOutcome = { kind: \"live\" } | { kind: \"unknown\"; code: string } | { kind: \"vacant\" };\ntype PathVerdict = ProbeOutcome | { kind: \"directory\" };\ntype ClaimOutcome = \"occupied\" | \"published\";\n\nconst PROBE_TIMEOUT_MS = 1000;\nconst PROBE_ATTEMPTS = 3;\nconst PROBE_RETRY_DELAY_MS = 50;\nconst CLAIM_ATTEMPTS = 3;\nconst CLAIM_LOCK_PREFIX = \"\\0gtkx-mcp-claim-\";\nconst CLAIM_LOCK_RETRY_DELAY_MS = 25;\nconst CLAIM_LOCK_TIMEOUT_MS = 15_000;\n\nconst delay = (ms: number): Promise<void> =>\n new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n\nconst closeServer = (server: net.Server): Promise<void> =>\n new Promise((resolve) => {\n server.close(() => {\n resolve();\n });\n });\n\nconst digestFor = (socketPath: string): string =>\n createHash(\"sha256\").update(resolvePath(socketPath)).digest(\"hex\");\n\nconst privatePathFor = (socketPath: string): string => {\n const width = Math.max(1, basename(socketPath).length - 1);\n\n return join(dirname(socketPath), `.${digestFor(socketPath).slice(0, width)}`);\n};\n\nconst bindLock = (address: string): Promise<net.Server | null> =>\n new Promise((resolve) => {\n const lock = net.createServer();\n let isBound = false;\n\n lock.on(\"error\", () => {\n if (!isBound) {\n resolve(null);\n }\n });\n\n lock.listen(address, () => {\n isBound = true;\n resolve(lock);\n });\n });\n\nconst claimBlockedError = (socketPath: string): Error =>\n new Error(\n `Timed out waiting for another GTKX MCP server to finish claiming ${socketPath}. ` +\n \"Retry once no other server is starting on that path.\",\n );\n\nconst acquireClaimLock = async (socketPath: string): Promise<net.Server | null> => {\n const address = `${CLAIM_LOCK_PREFIX}${digestFor(socketPath)}`;\n const deadline = Date.now() + CLAIM_LOCK_TIMEOUT_MS;\n let lock = await bindLock(address);\n\n while (lock === null && Date.now() < deadline) {\n await delay(CLAIM_LOCK_RETRY_DELAY_MS);\n lock = await bindLock(address);\n }\n\n return lock;\n};\n\nconst releaseClaimLock = async (lock: net.Server | null): Promise<void> => {\n if (lock) {\n await closeServer(lock);\n }\n};\n\nconst withClaimLock = async <T>(socketPath: string, action: () => Promise<T> | T): Promise<T> => {\n const lock = await acquireClaimLock(socketPath);\n\n if (lock === null) {\n throw claimBlockedError(socketPath);\n }\n\n try {\n return await action();\n } finally {\n await closeServer(lock);\n }\n};\n\nconst entryFor = (target: string): fs.Stats | null => {\n try {\n return fs.lstatSync(target);\n } catch {\n return null;\n }\n};\n\nconst inodeFor = (target: string): number | null => entryFor(target)?.ino ?? null;\n\nconst outcomeForProbeError = (error: NodeJS.ErrnoException): ProbeOutcome => {\n if (error.code === \"ECONNREFUSED\" || error.code === \"ENOENT\") {\n return { kind: \"vacant\" };\n }\n\n return { kind: \"unknown\", code: error.code ?? error.message };\n};\n\nconst probeSocket = (target: string): Promise<ProbeOutcome> =>\n new Promise((resolve) => {\n const probe = net.connect({ path: target, timeout: PROBE_TIMEOUT_MS });\n\n const settleWith = (outcome: ProbeOutcome): void => {\n probe.destroy();\n resolve(outcome);\n };\n\n probe.once(\"connect\", () => {\n settleWith({ kind: \"live\" });\n });\n\n probe.once(\"timeout\", () => {\n settleWith({ kind: \"unknown\", code: \"ETIMEDOUT\" });\n });\n\n probe.once(\"error\", (error: NodeJS.ErrnoException) => {\n settleWith(outcomeForProbeError(error));\n });\n });\n\nconst probeUntilConclusive = async (target: string): Promise<ProbeOutcome> => {\n let outcome = await probeSocket(target);\n\n for (let attempt = 1; attempt < PROBE_ATTEMPTS && outcome.kind === \"unknown\"; attempt += 1) {\n await delay(PROBE_RETRY_DELAY_MS);\n outcome = await probeSocket(target);\n }\n\n return outcome;\n};\n\nconst alreadyOwnedError = (socketPath: string): Error =>\n new Error(\n `Another GTKX MCP server already owns ${socketPath}. ` +\n \"Stop the other server (for example, the GTKX MCP server of another active session) and reconnect.\",\n );\n\nconst undecidedOwnerError = (socketPath: string, code: string): Error =>\n new Error(\n `Could not tell whether another GTKX MCP server owns ${socketPath}: probing it failed with ${code}. ` +\n \"Leaving the socket in place instead of removing one that may still be serving another session. \" +\n \"Retry, or delete the file by hand once no server is running.\",\n );\n\nconst directoryPathError = (socketPath: string): Error =>\n new Error(\n `The GTKX MCP socket path ${socketPath} is a directory, not a socket. ` +\n \"Remove it, or point XDG_RUNTIME_DIR at a directory where GTKX can create its socket.\",\n );\n\nconst listenFailureError = (socketPath: string, code: string): Error =>\n new Error(\n `Could not create the GTKX MCP socket at ${socketPath}: listening failed with ${code}. ` +\n \"Check that its directory exists and is writable.\",\n );\n\nconst removeEntry = (target: string, inode: number): void => {\n if (inodeFor(target) === inode) {\n fs.rmSync(target, { force: true });\n }\n};\n\nconst clearStalePath = async (target: string): Promise<PathVerdict> => {\n const entry = entryFor(target);\n\n if (entry === null) {\n return { kind: \"vacant\" };\n }\n\n if (entry.isDirectory()) {\n return { kind: \"directory\" };\n }\n\n const outcome = await probeUntilConclusive(target);\n\n if (outcome.kind === \"vacant\") {\n removeEntry(target, entry.ino);\n }\n\n return outcome;\n};\n\nconst requireVacantPath = async (socketPath: string): Promise<void> => {\n const verdict = await clearStalePath(socketPath);\n\n if (verdict.kind === \"live\") {\n throw alreadyOwnedError(socketPath);\n }\n\n if (verdict.kind === \"directory\") {\n throw directoryPathError(socketPath);\n }\n\n if (verdict.kind === \"unknown\") {\n throw undecidedOwnerError(socketPath, verdict.code);\n }\n};\n\nconst claimSocketPath = (privatePath: string, socketPath: string): ClaimOutcome => {\n try {\n fs.linkSync(privatePath, socketPath);\n\n return \"published\";\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n return \"occupied\";\n }\n\n throw error;\n }\n};\n\nconst publishSocket = async (privatePath: string, socketPath: string): Promise<number | null> => {\n for (let attempt = 1; attempt <= CLAIM_ATTEMPTS; attempt += 1) {\n await requireVacantPath(socketPath);\n\n if (claimSocketPath(privatePath, socketPath) === \"published\") {\n const inode = inodeFor(socketPath);\n fs.rmSync(privatePath, { force: true });\n\n return inode;\n }\n }\n\n throw alreadyOwnedError(socketPath);\n};\n\nconst releaseSocketPath = async (socketPath: string, inode: number): Promise<void> => {\n const lock = await acquireClaimLock(socketPath);\n\n try {\n removeEntry(socketPath, inode);\n } finally {\n await releaseClaimLock(lock);\n }\n};\n\nclass SocketServer {\n private server: net.Server | null = null;\n private socketPath: string;\n private registry: ConnectionRegistry;\n private boundInode: number | null = null;\n private startup: Promise<void> | null = null;\n\n constructor(registry: ConnectionRegistry, socketPath: string = DEFAULT_SOCKET_PATH) {\n this.registry = registry;\n this.socketPath = socketPath;\n }\n\n private listen(privatePath: string): Promise<net.Server> {\n return new Promise((resolve, reject) => {\n const server = net.createServer((socket) => this.registry.register(socket));\n let isListening = false;\n\n server.on(\"error\", (error) => {\n this.registry.dispatchEvent(connectionErrorEvent(error));\n\n if (!isListening) {\n reject(error);\n }\n });\n\n server.listen(privatePath, () => {\n isListening = true;\n resolve(server);\n });\n });\n }\n\n private async listenPrivately(privatePath: string): Promise<net.Server> {\n try {\n return await this.listen(privatePath);\n } catch (error) {\n const failure = error as NodeJS.ErrnoException;\n throw listenFailureError(this.socketPath, failure.code ?? failure.message);\n }\n }\n\n private async bind(): Promise<void> {\n const privatePath = privatePathFor(this.socketPath);\n await clearStalePath(privatePath);\n const server = await this.listenPrivately(privatePath);\n\n try {\n this.boundInode = await publishSocket(privatePath, this.socketPath);\n this.server = server;\n } catch (error) {\n await closeServer(server);\n throw error;\n }\n }\n\n private open(): Promise<void> {\n return withClaimLock(this.socketPath, () => this.bind());\n }\n\n private async settleStartup(): Promise<void> {\n const startup = this.startup;\n this.startup = null;\n\n if (startup) {\n await Promise.allSettled([startup]);\n }\n }\n\n private async release(): Promise<void> {\n const inode = this.boundInode;\n this.boundInode = null;\n\n if (inode !== null) {\n await releaseSocketPath(this.socketPath, inode);\n }\n }\n\n async start(): Promise<void> {\n this.startup ??= this.open();\n const startup = this.startup;\n\n try {\n await startup;\n } catch (error) {\n if (this.startup === startup) {\n this.startup = null;\n }\n\n throw error;\n }\n }\n\n async stop(): Promise<void> {\n await this.settleStartup();\n const server = this.server;\n\n if (!server) {\n return;\n }\n\n this.server = null;\n this.registry.dispose();\n await closeServer(server);\n await this.release();\n }\n}\n\nexport { SocketServer };\n"]}
|
|
1
|
+
{"version":3,"file":"socket-server.js","sourceRoot":"","sources":["../src/socket-server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as net from \"node:net\";\nimport { basename, dirname, join, resolve as resolvePath } from \"node:path\";\nimport type { ConnectionRegistry } from \"./connection-registry.js\";\nimport {\n cleanupMcpSocketAddress,\n type McpSocketAddress,\n prepareMcpSocketAddress,\n resolveMcpSocketAddress,\n} from \"./socket-path.js\";\nimport { connectionErrorEvent } from \"./transport.js\";\n\ntype ProbeOutcome = { kind: \"live\" } | { kind: \"unknown\"; code: string } | { kind: \"vacant\" };\ntype PathVerdict = ProbeOutcome | { kind: \"invalid\" };\ntype ClaimOutcome = \"occupied\" | \"published\";\n\nconst PROBE_TIMEOUT_MS = 1000;\nconst PROBE_ATTEMPTS = 3;\nconst PROBE_RETRY_DELAY_MS = 50;\nconst CLAIM_ATTEMPTS = 3;\nconst CLAIM_LOCK_PREFIX = \"\\0gtkx-mcp-claim-\";\nconst CLAIM_LOCK_RETRY_DELAY_MS = 25;\nconst CLAIM_LOCK_TIMEOUT_MS = 15_000;\n\nconst delay = (ms: number): Promise<void> =>\n new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n\nconst closeServer = (server: net.Server): Promise<void> =>\n new Promise((resolve) => {\n server.close(() => {\n resolve();\n });\n });\n\nconst digestFor = (socketPath: string): string =>\n createHash(\"sha256\").update(resolvePath(socketPath)).digest(\"hex\");\n\nconst privatePathFor = (socketPath: string): string => {\n const width = Math.max(1, basename(socketPath).length - 1);\n\n return join(dirname(socketPath), `.${digestFor(socketPath).slice(0, width)}`);\n};\n\nconst bindLock = (address: string): Promise<net.Server | null> =>\n new Promise((resolve) => {\n const lock = net.createServer();\n let isBound = false;\n\n lock.on(\"error\", () => {\n if (!isBound) {\n resolve(null);\n }\n });\n\n lock.listen(address, () => {\n isBound = true;\n resolve(lock);\n });\n });\n\nconst claimBlockedError = (socketPath: string): Error =>\n new Error(\n `Timed out waiting for another GTKX MCP server to finish claiming ${socketPath}. ` +\n \"Retry once no other server is starting on that path.\",\n );\n\nconst acquireClaimLock = async (socketPath: string): Promise<net.Server | null> => {\n const address = `${CLAIM_LOCK_PREFIX}${digestFor(socketPath)}`;\n const deadline = Date.now() + CLAIM_LOCK_TIMEOUT_MS;\n let lock = await bindLock(address);\n\n while (lock === null && Date.now() < deadline) {\n await delay(CLAIM_LOCK_RETRY_DELAY_MS);\n lock = await bindLock(address);\n }\n\n return lock;\n};\n\nconst withClaimLock = async <T>(socketPath: string, action: () => Promise<T> | T): Promise<T> => {\n const lock = await acquireClaimLock(socketPath);\n\n if (lock === null) {\n throw claimBlockedError(socketPath);\n }\n\n try {\n return await action();\n } finally {\n await closeServer(lock);\n }\n};\n\nconst entryFor = (target: string): fs.Stats | null => {\n try {\n return fs.lstatSync(target);\n } catch {\n return null;\n }\n};\n\nconst inodeFor = (target: string): number | null => entryFor(target)?.ino ?? null;\n\nconst outcomeForProbeError = (error: NodeJS.ErrnoException): ProbeOutcome => {\n if (error.code === \"ECONNREFUSED\" || error.code === \"ENOENT\") {\n return { kind: \"vacant\" };\n }\n\n return { kind: \"unknown\", code: error.code ?? error.message };\n};\n\nconst probeSocket = (target: string): Promise<ProbeOutcome> =>\n new Promise((resolve) => {\n const probe = net.connect({ path: target, timeout: PROBE_TIMEOUT_MS });\n\n const settleWith = (outcome: ProbeOutcome): void => {\n probe.destroy();\n resolve(outcome);\n };\n\n probe.once(\"connect\", () => {\n settleWith({ kind: \"live\" });\n });\n\n probe.once(\"timeout\", () => {\n settleWith({ kind: \"unknown\", code: \"ETIMEDOUT\" });\n });\n\n probe.once(\"error\", (error: NodeJS.ErrnoException) => {\n settleWith(outcomeForProbeError(error));\n });\n });\n\nconst probeUntilConclusive = async (target: string): Promise<ProbeOutcome> => {\n let outcome = await probeSocket(target);\n\n for (let attempt = 1; attempt < PROBE_ATTEMPTS && outcome.kind === \"unknown\"; attempt += 1) {\n await delay(PROBE_RETRY_DELAY_MS);\n outcome = await probeSocket(target);\n }\n\n return outcome;\n};\n\nconst alreadyOwnedError = (socketPath: string): Error =>\n new Error(\n `Another GTKX MCP server already owns ${socketPath}. ` +\n \"Stop the other server (for example, the GTKX MCP server of another active session) and reconnect.\",\n );\n\nconst undecidedOwnerError = (socketPath: string, code: string): Error =>\n new Error(\n `Could not tell whether another GTKX MCP server owns ${socketPath}: probing it failed with ${code}. ` +\n \"Leaving the socket in place instead of removing one that may still be serving another session. \" +\n \"Retry, or delete the file by hand once no server is running.\",\n );\n\nconst invalidPathError = (socketPath: string): Error =>\n new Error(\n `The GTKX MCP socket path ${socketPath} exists and is not a socket. ` +\n \"Move it, or point XDG_RUNTIME_DIR at a directory where GTKX can create its socket.\",\n );\n\nconst listenFailureError = (socketPath: string, code: string): Error =>\n new Error(\n `Could not create the GTKX MCP socket at ${socketPath}: listening failed with ${code}. ` +\n \"Check that its directory exists and is writable.\",\n );\n\nconst removeEntry = (target: string, inode: number): void => {\n if (inodeFor(target) === inode) {\n fs.rmSync(target, { force: true });\n }\n};\n\nconst clearStalePath = async (target: string): Promise<PathVerdict> => {\n const entry = entryFor(target);\n\n if (entry === null) {\n return { kind: \"vacant\" };\n }\n\n if (!entry.isSocket()) {\n return { kind: \"invalid\" };\n }\n\n const outcome = await probeUntilConclusive(target);\n\n if (outcome.kind === \"vacant\") {\n removeEntry(target, entry.ino);\n }\n\n return outcome;\n};\n\nconst requireVacantPath = async (socketPath: string): Promise<void> => {\n const verdict = await clearStalePath(socketPath);\n\n if (verdict.kind === \"live\") {\n throw alreadyOwnedError(socketPath);\n }\n\n if (verdict.kind === \"invalid\") {\n throw invalidPathError(socketPath);\n }\n\n if (verdict.kind === \"unknown\") {\n throw undecidedOwnerError(socketPath, verdict.code);\n }\n};\n\nconst claimSocketPath = (privatePath: string, socketPath: string): ClaimOutcome => {\n try {\n fs.linkSync(privatePath, socketPath);\n\n return \"published\";\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n return \"occupied\";\n }\n\n throw error;\n }\n};\n\nconst publishSocket = async (privatePath: string, socketPath: string): Promise<number | null> => {\n for (let attempt = 1; attempt <= CLAIM_ATTEMPTS; attempt += 1) {\n await requireVacantPath(socketPath);\n\n if (claimSocketPath(privatePath, socketPath) === \"published\") {\n const inode = inodeFor(socketPath);\n fs.rmSync(privatePath, { force: true });\n\n return inode;\n }\n }\n\n throw alreadyOwnedError(socketPath);\n};\n\nclass SocketServer {\n private server: net.Server | null = null;\n private socketPath: string;\n private registry: ConnectionRegistry;\n private address: McpSocketAddress;\n private boundInode: number | null = null;\n private startup: Promise<void> | null = null;\n\n constructor(registry: ConnectionRegistry, address: McpSocketAddress = resolveMcpSocketAddress()) {\n this.registry = registry;\n this.address = address;\n this.socketPath = address.path;\n }\n\n private listen(privatePath: string): Promise<net.Server> {\n return new Promise((resolve, reject) => {\n const server = net.createServer((socket) => this.registry.register(socket));\n let isListening = false;\n\n server.on(\"error\", (error) => {\n this.registry.dispatchEvent(connectionErrorEvent(error));\n\n if (!isListening) {\n reject(error);\n }\n });\n\n server.listen(privatePath, () => {\n isListening = true;\n resolve(server);\n });\n });\n }\n\n private async listenPrivately(privatePath: string): Promise<net.Server> {\n try {\n return await this.listen(privatePath);\n } catch (error) {\n const failure = error as NodeJS.ErrnoException;\n throw listenFailureError(this.socketPath, failure.code ?? failure.message);\n }\n }\n\n private async bind(): Promise<void> {\n prepareMcpSocketAddress(this.address);\n const privatePath = privatePathFor(this.socketPath);\n await clearStalePath(privatePath);\n const server = await this.listenPrivately(privatePath);\n const privateInode = inodeFor(privatePath);\n\n try {\n if (privateInode === null) {\n throw listenFailureError(this.socketPath, \"ENOENT\");\n }\n\n const publishedInode = await publishSocket(privatePath, this.socketPath);\n\n if (publishedInode !== privateInode) {\n throw listenFailureError(this.socketPath, \"ESTALE\");\n }\n\n this.boundInode = privateInode;\n this.server = server;\n } catch (error) {\n await closeServer(server);\n\n if (privateInode !== null) {\n removeEntry(privatePath, privateInode);\n removeEntry(this.socketPath, privateInode);\n }\n\n throw error;\n }\n }\n\n private open(): Promise<void> {\n return withClaimLock(this.socketPath, async () => {\n try {\n await this.bind();\n } catch (error) {\n cleanupMcpSocketAddress(this.address);\n throw error;\n }\n });\n }\n\n private async settleStartup(): Promise<void> {\n const startup = this.startup;\n this.startup = null;\n\n if (startup) {\n await Promise.allSettled([startup]);\n }\n }\n\n private async release(server: net.Server): Promise<void> {\n const inode = this.boundInode;\n\n await withClaimLock(this.socketPath, async () => {\n this.registry.dispose();\n await closeServer(server);\n\n try {\n if (inode !== null) {\n removeEntry(this.socketPath, inode);\n }\n } finally {\n cleanupMcpSocketAddress(this.address);\n }\n });\n\n this.boundInode = null;\n }\n\n async start(): Promise<void> {\n this.startup ??= this.open();\n const startup = this.startup;\n\n try {\n await startup;\n } catch (error) {\n if (this.startup === startup) {\n this.startup = null;\n }\n\n throw error;\n }\n }\n\n async stop(): Promise<void> {\n await this.settleStartup();\n const server = this.server;\n\n if (!server) {\n return;\n }\n\n await this.release(server);\n this.server = null;\n }\n}\n\nexport { SocketServer };\n"]}
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gtkx/mcp",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "MCP server
|
|
3
|
+
"version": "2.0.0-beta.10",
|
|
4
|
+
"description": "MCP server for GTKX GNOME references and live Adwaita apps.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gtkx",
|
|
7
7
|
"gtk",
|
|
8
8
|
"gtk4",
|
|
9
|
+
"adwaita",
|
|
10
|
+
"gnome",
|
|
9
11
|
"mcp",
|
|
10
12
|
"model-context-protocol",
|
|
11
13
|
"ai",
|
|
@@ -29,10 +31,14 @@
|
|
|
29
31
|
"./package.json": "./package.json",
|
|
30
32
|
"./server": {
|
|
31
33
|
"types": "./dist/server.d.ts",
|
|
34
|
+
"import": "./dist/server.js",
|
|
35
|
+
"require": null,
|
|
32
36
|
"default": "./dist/server.js"
|
|
33
37
|
},
|
|
34
38
|
"./internal": {
|
|
35
39
|
"types": "./dist/internal.d.ts",
|
|
40
|
+
"import": "./dist/internal.js",
|
|
41
|
+
"require": null,
|
|
36
42
|
"default": "./dist/internal.js"
|
|
37
43
|
}
|
|
38
44
|
},
|
|
@@ -56,18 +62,18 @@
|
|
|
56
62
|
}
|
|
57
63
|
},
|
|
58
64
|
"engines": {
|
|
59
|
-
"node": ">=
|
|
65
|
+
"node": ">=26.7.0"
|
|
60
66
|
},
|
|
61
67
|
"dependencies": {
|
|
68
|
+
"@gtkx/codegen": "2.0.0-beta.10",
|
|
69
|
+
"@gtkx/config": "2.0.0-beta.10",
|
|
70
|
+
"@gtkx/utils": "2.0.0-beta.10",
|
|
62
71
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
63
|
-
"zod": "^4.4
|
|
64
|
-
"@gtkx/config": "1.6.0",
|
|
65
|
-
"@gtkx/utils": "1.6.0",
|
|
66
|
-
"@gtkx/codegen": "1.6.0"
|
|
72
|
+
"zod": "^4.5.4"
|
|
67
73
|
},
|
|
68
74
|
"devDependencies": {
|
|
69
|
-
"vitest": "
|
|
70
|
-
"
|
|
75
|
+
"@gtkx/vitest": "2.0.0-beta.10",
|
|
76
|
+
"vitest": "^5.0.0"
|
|
71
77
|
},
|
|
72
78
|
"scripts": {
|
|
73
79
|
"release": "tsx ../../scripts/release-package.ts"
|