@gtkx/mcp 0.20.0 → 1.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +122 -55
  2. package/bin/gtkx-mcp.js +8 -1
  3. package/dist/app-router.d.ts +35 -0
  4. package/dist/app-router.d.ts.map +1 -0
  5. package/dist/app-router.js +130 -0
  6. package/dist/app-router.js.map +1 -0
  7. package/dist/connection-registry.d.ts +12 -0
  8. package/dist/connection-registry.d.ts.map +1 -0
  9. package/dist/connection-registry.js +38 -0
  10. package/dist/connection-registry.js.map +1 -0
  11. package/dist/internal.d.ts +4 -0
  12. package/dist/internal.d.ts.map +1 -0
  13. package/dist/internal.js +4 -0
  14. package/dist/internal.js.map +1 -0
  15. package/dist/protocol/errors.d.ts +24 -87
  16. package/dist/protocol/errors.d.ts.map +1 -1
  17. package/dist/protocol/errors.js +27 -91
  18. package/dist/protocol/errors.js.map +1 -1
  19. package/dist/protocol/schemas.d.ts +89 -0
  20. package/dist/protocol/schemas.d.ts.map +1 -0
  21. package/dist/protocol/schemas.js +56 -0
  22. package/dist/protocol/schemas.js.map +1 -0
  23. package/dist/reference.d.ts +13 -0
  24. package/dist/reference.d.ts.map +1 -0
  25. package/dist/reference.js +250 -0
  26. package/dist/reference.js.map +1 -0
  27. package/dist/server.d.ts +14 -0
  28. package/dist/server.d.ts.map +1 -0
  29. package/dist/server.js +220 -0
  30. package/dist/server.js.map +1 -0
  31. package/dist/socket-server.d.ts +4 -38
  32. package/dist/socket-server.d.ts.map +1 -1
  33. package/dist/socket-server.js +26 -109
  34. package/dist/socket-server.js.map +1 -1
  35. package/dist/tool.d.ts +22 -0
  36. package/dist/tool.d.ts.map +1 -0
  37. package/dist/tool.js +36 -0
  38. package/dist/tool.js.map +1 -0
  39. package/dist/transport.d.ts +41 -0
  40. package/dist/transport.d.ts.map +1 -0
  41. package/dist/transport.js +121 -0
  42. package/dist/transport.js.map +1 -0
  43. package/package.json +17 -11
  44. package/src/app-router.ts +172 -0
  45. package/src/connection-registry.ts +42 -0
  46. package/src/internal.ts +17 -0
  47. package/src/protocol/errors.ts +44 -100
  48. package/src/protocol/schemas.ts +148 -0
  49. package/src/reference.ts +340 -0
  50. package/src/server.ts +281 -0
  51. package/src/socket-server.ts +30 -154
  52. package/src/tool.ts +66 -0
  53. package/src/transport.ts +165 -0
  54. package/dist/cli.d.ts +0 -3
  55. package/dist/cli.d.ts.map +0 -1
  56. package/dist/cli.js +0 -399
  57. package/dist/cli.js.map +0 -1
  58. package/dist/connection-manager.d.ts +0 -48
  59. package/dist/connection-manager.d.ts.map +0 -1
  60. package/dist/connection-manager.js +0 -185
  61. package/dist/connection-manager.js.map +0 -1
  62. package/dist/index.d.ts +0 -5
  63. package/dist/index.d.ts.map +0 -1
  64. package/dist/index.js +0 -5
  65. package/dist/index.js.map +0 -1
  66. package/dist/protocol/types.d.ts +0 -132
  67. package/dist/protocol/types.d.ts.map +0 -1
  68. package/dist/protocol/types.js +0 -46
  69. package/dist/protocol/types.js.map +0 -1
  70. package/src/cli.ts +0 -449
  71. package/src/connection-manager.ts +0 -247
  72. package/src/index.ts +0 -27
  73. package/src/protocol/types.ts +0 -153
@@ -0,0 +1,250 @@
1
+ import { statSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { loadApiReference, resolveGirPath, resolveLibraries } from "@gtkx/codegen";
4
+ import { loadConfig } from "@gtkx/config";
5
+ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
6
+ import { ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
7
+ import { z } from "zod";
8
+ import { defineTool, textContent, textError } from "./tool.js";
9
+ const watchFile = (path) => {
10
+ try {
11
+ const stats = statSync(path);
12
+ return { path, mtimeMs: stats.mtimeMs, size: stats.size };
13
+ }
14
+ catch {
15
+ return { path, mtimeMs: -1, size: -1 };
16
+ }
17
+ };
18
+ const isFresh = (loaded) => loaded.watched.every((file) => {
19
+ const current = watchFile(file.path);
20
+ return current.mtimeMs === file.mtimeMs && current.size === file.size;
21
+ });
22
+ const loadReference = async (root) => {
23
+ const { config, configFile } = await loadConfig(root);
24
+ if (config.codegen === false) {
25
+ throw new Error(`codegen is disabled for the project at ${root}, so there are no generated bindings to document. Remove \`codegen: false\` from gtkx.config.ts to use the API reference.`);
26
+ }
27
+ const girPath = resolveGirPath(config.girPath);
28
+ if (girPath.length === 0) {
29
+ throw new Error("No GIR search paths available. Install gobject-introspection (Linux: `sudo dnf install gobject-introspection-devel` or `sudo apt install libgirepository1.0-dev`), or set `girPath` in gtkx.config.ts.");
30
+ }
31
+ const libraries = resolveLibraries(config.libraries, girPath);
32
+ const reference = loadApiReference({ libraries, girPath, elementProps: config.elementProps ?? {} });
33
+ const watched = [
34
+ ...(configFile === undefined ? [] : [watchFile(resolve(root, configFile))]),
35
+ ...reference.girFiles.map(watchFile),
36
+ ];
37
+ return { reference, watched };
38
+ };
39
+ const FRESHNESS_INTERVAL_MS = 2000;
40
+ const FAILURE_RETRY_MS = 5000;
41
+ export const createReferenceProvider = (resolveRoot) => {
42
+ const cache = new Map();
43
+ const startLoad = (root) => {
44
+ const entry = { pending: loadReference(root), verifiedAt: Date.now(), failedAt: undefined };
45
+ entry.pending.catch(() => {
46
+ entry.failedAt = Date.now();
47
+ });
48
+ cache.set(root, entry);
49
+ return entry;
50
+ };
51
+ return {
52
+ async get() {
53
+ const root = resolve(resolveRoot());
54
+ let entry = cache.get(root) ?? startLoad(root);
55
+ if (entry.failedAt !== undefined && Date.now() - entry.failedAt >= FAILURE_RETRY_MS) {
56
+ entry = startLoad(root);
57
+ }
58
+ const loaded = await entry.pending;
59
+ if (Date.now() - entry.verifiedAt < FRESHNESS_INTERVAL_MS)
60
+ return loaded.reference;
61
+ if (isFresh(loaded)) {
62
+ entry.verifiedAt = Date.now();
63
+ return loaded.reference;
64
+ }
65
+ const current = cache.get(root);
66
+ const replacement = current === undefined || current === entry ? startLoad(root) : current;
67
+ return (await replacement.pending).reference;
68
+ },
69
+ };
70
+ };
71
+ const SYMBOL_KIND = z.enum([
72
+ "element",
73
+ "class",
74
+ "interface",
75
+ "record",
76
+ "enum",
77
+ "callback",
78
+ "alias",
79
+ "function",
80
+ "constant",
81
+ ]);
82
+ const SYMBOL_DESCRIPTION = "Qualified symbol name (`Gtk.Button`, `Gtk.Orientation`, `GLib.idleAdd`), JSX element name (`GtkButton`), or bare symbol name when unambiguous (`Button`).";
83
+ const listApiShape = {
84
+ namespace: z
85
+ .string()
86
+ .optional()
87
+ .describe("Namespace to list (e.g. `Gtk`, `Adw`, `Gio`). Omit for an overview of all namespaces."),
88
+ };
89
+ const searchApiShape = {
90
+ query: z.string().describe("Case-insensitive substring of a symbol name, e.g. `headerbar` or `orientation`."),
91
+ namespace: z.string().optional().describe("Restrict matches to one namespace (e.g. `Gtk`)."),
92
+ kind: SYMBOL_KIND.optional().describe("Restrict matches to one symbol kind."),
93
+ limit: z.number().int().min(1).optional().describe("Maximum number of results (default: 20)."),
94
+ };
95
+ const getApiDocsShape = {
96
+ symbol: z.string().describe(SYMBOL_DESCRIPTION),
97
+ kind: SYMBOL_KIND.optional().describe("Disambiguate when several kinds share the symbol name."),
98
+ };
99
+ const formatCandidates = (candidates) => candidates.map((candidate) => `- ${candidate.namespace}.${candidate.name} (${candidate.kind})`).join("\n");
100
+ const listApiTool = (provider) => defineTool({
101
+ name: "gtkx_list_api",
102
+ title: "List API reference",
103
+ kind: "readOnly",
104
+ description: "List the project's generated GTK4 bindings API (`@gtkx/gi` and `@gtkx/jsx`). Without a namespace, returns every namespace with symbol counts; with a namespace, lists all of its symbols grouped by kind.",
105
+ inputSchema: listApiShape,
106
+ handler: async ({ namespace }) => {
107
+ const reference = await provider.get();
108
+ if (namespace === undefined)
109
+ return textContent(reference.overview());
110
+ const overview = reference.namespaceOverview(namespace);
111
+ if (overview === undefined) {
112
+ const names = reference
113
+ .namespaces()
114
+ .map((summary) => summary.name)
115
+ .join(", ");
116
+ return textError(`Unknown namespace "${namespace}". Available namespaces: ${names}`);
117
+ }
118
+ return textContent(overview);
119
+ },
120
+ });
121
+ const searchApiTool = (provider) => defineTool({
122
+ name: "gtkx_search_api",
123
+ title: "Search API reference",
124
+ kind: "readOnly",
125
+ description: "Search the project's generated GTK4 bindings API by symbol name. Returns matching symbols with their namespace, kind, and a one-line summary; fetch full pages with `gtkx_get_api_docs`.",
126
+ inputSchema: searchApiShape,
127
+ handler: async ({ query, namespace, kind, limit }) => {
128
+ const reference = await provider.get();
129
+ const results = reference.search({
130
+ query,
131
+ ...(namespace === undefined ? {} : { namespace }),
132
+ ...(kind === undefined ? {} : { kinds: [kind] }),
133
+ ...(limit === undefined ? {} : { limit }),
134
+ });
135
+ if (results.length === 0) {
136
+ return textContent(`No symbols matched "${query}". Try a shorter substring or \`gtkx_list_api\`.`);
137
+ }
138
+ return textContent(JSON.stringify(results, null, 2));
139
+ },
140
+ });
141
+ const getApiDocsTool = (provider) => defineTool({
142
+ name: "gtkx_get_api_docs",
143
+ title: "Get API docs",
144
+ kind: "readOnly",
145
+ description: "Get the full reference page for one symbol of the project's generated GTK4 bindings: JSX elements (props, signals, methods) or `@gtkx/gi` classes, interfaces, records, enums, callbacks, aliases, functions, and constants.",
146
+ inputSchema: getApiDocsShape,
147
+ handler: async ({ symbol, kind }) => {
148
+ const reference = await provider.get();
149
+ const result = reference.lookup(symbol, kind);
150
+ if (result.outcome === "notFound") {
151
+ return textError(`No symbol named "${symbol}". Use \`gtkx_search_api\` to find the right name.`);
152
+ }
153
+ if (result.outcome === "ambiguous") {
154
+ return textError(`"${symbol}" matches several symbols. Pass a qualified name or a kind:\n${formatCandidates(result.candidates)}`);
155
+ }
156
+ return textContent(result.markdown);
157
+ },
158
+ });
159
+ export const buildReferenceTools = (provider) => [
160
+ listApiTool(provider),
161
+ searchApiTool(provider),
162
+ getApiDocsTool(provider),
163
+ ];
164
+ const markdownResource = (uri, text) => ({
165
+ contents: [{ uri: uri.href, mimeType: "text/markdown", text }],
166
+ });
167
+ const variableValue = (value) => Array.isArray(value) ? (value[0] ?? "") : (value ?? "");
168
+ const swallowLoadFailure = (fallback) => () => fallback;
169
+ const namespaceCompleter = (provider) => (value) => provider
170
+ .get()
171
+ .then((reference) => reference
172
+ .namespaces()
173
+ .map((summary) => summary.name)
174
+ .filter((name) => name.toLowerCase().startsWith(value.toLowerCase())))
175
+ .catch(swallowLoadFailure([]));
176
+ const resourceNotFound = (message) => new McpError(ErrorCode.InvalidParams, message);
177
+ const registerIndexResource = (server, provider) => {
178
+ server.registerResource("gtkx-api-reference", "gtkx://reference/index", {
179
+ title: "GTKX API reference index",
180
+ description: "Namespaces of the project's generated GTK4 bindings, with symbol and JSX element counts.",
181
+ mimeType: "text/markdown",
182
+ }, async (uri) => markdownResource(uri, (await provider.get()).overview()));
183
+ };
184
+ const registerNamespaceResource = (server, provider) => {
185
+ server.registerResource("gtkx-api-namespace", new ResourceTemplate("gtkx://reference/{namespace}", {
186
+ list: () => provider
187
+ .get()
188
+ .then((reference) => ({
189
+ resources: reference.namespaces().map((summary) => ({
190
+ uri: `gtkx://reference/${summary.name}`,
191
+ name: `${summary.name} namespace reference`,
192
+ mimeType: "text/markdown",
193
+ })),
194
+ }))
195
+ .catch(swallowLoadFailure({ resources: [] })),
196
+ complete: {
197
+ namespace: namespaceCompleter(provider),
198
+ },
199
+ }), {
200
+ title: "GTKX namespace reference",
201
+ description: "All symbols of one namespace of the project's generated GTK4 bindings, grouped by kind.",
202
+ mimeType: "text/markdown",
203
+ }, async (uri, variables) => {
204
+ const namespace = variableValue(variables.namespace);
205
+ const overview = (await provider.get()).namespaceOverview(namespace);
206
+ if (overview === undefined)
207
+ throw resourceNotFound(`Unknown namespace "${namespace}"`);
208
+ return markdownResource(uri, overview);
209
+ });
210
+ };
211
+ const registerSymbolResource = (server, provider) => {
212
+ server.registerResource("gtkx-api-symbol", new ResourceTemplate("gtkx://reference/{namespace}/{symbol}", {
213
+ list: undefined,
214
+ complete: {
215
+ namespace: namespaceCompleter(provider),
216
+ symbol: (value, context) => {
217
+ const namespace = variableValue(context?.arguments?.namespace);
218
+ if (namespace.length === 0)
219
+ return [];
220
+ return provider
221
+ .get()
222
+ .then((reference) => reference
223
+ .symbolNames(namespace)
224
+ .filter((name) => name.toLowerCase().startsWith(value.toLowerCase())))
225
+ .catch(swallowLoadFailure([]));
226
+ },
227
+ },
228
+ }), {
229
+ title: "GTKX symbol reference",
230
+ description: "Reference page for one symbol of the project's generated GTK4 bindings: a JSX element or a class, interface, record, enum, callback, alias, function, or constant.",
231
+ mimeType: "text/markdown",
232
+ }, async (uri, variables) => {
233
+ const namespace = variableValue(variables.namespace);
234
+ const symbol = variableValue(variables.symbol);
235
+ const reference = await provider.get();
236
+ const result = reference.lookup(`${namespace}.${symbol}`);
237
+ if (result.outcome === "page")
238
+ return markdownResource(uri, result.markdown);
239
+ if (result.outcome === "ambiguous") {
240
+ throw resourceNotFound(`"${namespace}.${symbol}" matches several symbols:\n${formatCandidates(result.candidates)}`);
241
+ }
242
+ throw resourceNotFound(`No symbol named "${namespace}.${symbol}"`);
243
+ });
244
+ };
245
+ export const registerReferenceResources = (server, provider) => {
246
+ registerIndexResource(server, provider);
247
+ registerNamespaceResource(server, provider);
248
+ registerSymbolResource(server, provider);
249
+ };
250
+ //# sourceMappingURL=reference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reference.js","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"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","sourcesContent":["import { statSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { type ApiReference, type ApiSymbol, loadApiReference, resolveGirPath, resolveLibraries } from \"@gtkx/codegen\";\nimport { loadConfig } from \"@gtkx/config\";\nimport { type McpServer, ResourceTemplate } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { ErrorCode, McpError, type ReadResourceResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\nimport { defineTool, type Tool, textContent, textError } from \"./tool.js\";\n\nexport type ReferenceApi = Pick<\n ApiReference,\n \"lookup\" | \"namespaceOverview\" | \"namespaces\" | \"overview\" | \"search\" | \"symbolNames\"\n>;\n\nexport type ReferenceProvider = {\n get(): Promise<ReferenceApi>;\n};\n\ntype WatchedFile = {\n path: string;\n mtimeMs: number;\n size: number;\n};\n\ntype LoadedReference = {\n reference: ApiReference;\n watched: WatchedFile[];\n};\n\nconst watchFile = (path: string): WatchedFile => {\n try {\n const stats = statSync(path);\n return { path, mtimeMs: stats.mtimeMs, size: stats.size };\n } catch {\n return { path, mtimeMs: -1, size: -1 };\n }\n};\n\nconst isFresh = (loaded: LoadedReference): boolean =>\n loaded.watched.every((file) => {\n const current = watchFile(file.path);\n return current.mtimeMs === file.mtimeMs && current.size === file.size;\n });\n\nconst loadReference = async (root: string): Promise<LoadedReference> => {\n const { config, configFile } = await loadConfig(root);\n if (config.codegen === false) {\n throw new Error(\n `codegen is disabled for the project at ${root}, so there are no generated bindings to document. Remove \\`codegen: false\\` from gtkx.config.ts to use the API reference.`,\n );\n }\n const girPath = resolveGirPath(config.girPath);\n if (girPath.length === 0) {\n throw new Error(\n \"No GIR search paths available. Install gobject-introspection (Linux: `sudo dnf install gobject-introspection-devel` or `sudo apt install libgirepository1.0-dev`), or set `girPath` in gtkx.config.ts.\",\n );\n }\n const libraries = resolveLibraries(config.libraries, girPath);\n const reference = loadApiReference({ libraries, girPath, elementProps: config.elementProps ?? {} });\n const watched = [\n ...(configFile === undefined ? [] : [watchFile(resolve(root, configFile))]),\n ...reference.girFiles.map(watchFile),\n ];\n return { reference, watched };\n};\n\nconst FRESHNESS_INTERVAL_MS = 2000;\nconst FAILURE_RETRY_MS = 5000;\n\ntype CacheEntry = {\n pending: Promise<LoadedReference>;\n verifiedAt: number;\n failedAt: number | undefined;\n};\n\nexport const createReferenceProvider = (resolveRoot: () => string): ReferenceProvider => {\n const cache = new Map<string, CacheEntry>();\n const startLoad = (root: string): CacheEntry => {\n const entry: CacheEntry = { pending: loadReference(root), verifiedAt: Date.now(), failedAt: undefined };\n entry.pending.catch(() => {\n entry.failedAt = Date.now();\n });\n cache.set(root, entry);\n return entry;\n };\n return {\n async get(): Promise<ReferenceApi> {\n const root = resolve(resolveRoot());\n let entry = cache.get(root) ?? startLoad(root);\n if (entry.failedAt !== undefined && Date.now() - entry.failedAt >= FAILURE_RETRY_MS) {\n entry = startLoad(root);\n }\n const loaded = await entry.pending;\n if (Date.now() - entry.verifiedAt < FRESHNESS_INTERVAL_MS) return loaded.reference;\n if (isFresh(loaded)) {\n entry.verifiedAt = Date.now();\n return loaded.reference;\n }\n const current = cache.get(root);\n const replacement = current === undefined || current === entry ? startLoad(root) : current;\n return (await replacement.pending).reference;\n },\n };\n};\n\nconst SYMBOL_KIND = z.enum([\n \"element\",\n \"class\",\n \"interface\",\n \"record\",\n \"enum\",\n \"callback\",\n \"alias\",\n \"function\",\n \"constant\",\n]);\n\nconst SYMBOL_DESCRIPTION =\n \"Qualified symbol name (`Gtk.Button`, `Gtk.Orientation`, `GLib.idleAdd`), JSX element name (`GtkButton`), or bare symbol name when unambiguous (`Button`).\";\n\nconst listApiShape = {\n namespace: z\n .string()\n .optional()\n .describe(\"Namespace to list (e.g. `Gtk`, `Adw`, `Gio`). Omit for an overview of all namespaces.\"),\n};\n\nconst searchApiShape = {\n query: z.string().describe(\"Case-insensitive substring of a symbol name, e.g. `headerbar` or `orientation`.\"),\n namespace: z.string().optional().describe(\"Restrict matches to one namespace (e.g. `Gtk`).\"),\n kind: SYMBOL_KIND.optional().describe(\"Restrict matches to one symbol kind.\"),\n limit: z.number().int().min(1).optional().describe(\"Maximum number of results (default: 20).\"),\n};\n\nconst getApiDocsShape = {\n symbol: z.string().describe(SYMBOL_DESCRIPTION),\n kind: SYMBOL_KIND.optional().describe(\"Disambiguate when several kinds share the symbol name.\"),\n};\n\nconst formatCandidates = (candidates: ApiSymbol[]): string =>\n candidates.map((candidate) => `- ${candidate.namespace}.${candidate.name} (${candidate.kind})`).join(\"\\n\");\n\nconst listApiTool = (provider: ReferenceProvider): Tool =>\n defineTool({\n name: \"gtkx_list_api\",\n title: \"List API reference\",\n kind: \"readOnly\",\n description:\n \"List the project's generated GTK4 bindings API (`@gtkx/gi` and `@gtkx/jsx`). Without a namespace, returns every namespace with symbol counts; with a namespace, lists all of its symbols grouped by kind.\",\n inputSchema: listApiShape,\n handler: async ({ namespace }) => {\n const reference = await provider.get();\n if (namespace === undefined) return textContent(reference.overview());\n const overview = reference.namespaceOverview(namespace);\n if (overview === undefined) {\n const names = reference\n .namespaces()\n .map((summary) => summary.name)\n .join(\", \");\n return textError(`Unknown namespace \"${namespace}\". Available namespaces: ${names}`);\n }\n return textContent(overview);\n },\n });\n\nconst searchApiTool = (provider: ReferenceProvider): Tool =>\n defineTool({\n name: \"gtkx_search_api\",\n title: \"Search API reference\",\n kind: \"readOnly\",\n description:\n \"Search the project's generated GTK4 bindings API by symbol name. Returns matching symbols with their namespace, kind, and a one-line summary; fetch full pages with `gtkx_get_api_docs`.\",\n inputSchema: searchApiShape,\n handler: async ({ query, namespace, kind, limit }) => {\n const reference = await provider.get();\n const results = reference.search({\n query,\n ...(namespace === undefined ? {} : { namespace }),\n ...(kind === undefined ? {} : { kinds: [kind] }),\n ...(limit === undefined ? {} : { limit }),\n });\n if (results.length === 0) {\n return textContent(`No symbols matched \"${query}\". Try a shorter substring or \\`gtkx_list_api\\`.`);\n }\n return textContent(JSON.stringify(results, null, 2));\n },\n });\n\nconst getApiDocsTool = (provider: ReferenceProvider): Tool =>\n defineTool({\n name: \"gtkx_get_api_docs\",\n title: \"Get API docs\",\n kind: \"readOnly\",\n description:\n \"Get the full reference page for one symbol of the project's generated GTK4 bindings: JSX elements (props, signals, methods) or `@gtkx/gi` classes, interfaces, records, enums, callbacks, aliases, functions, and constants.\",\n inputSchema: getApiDocsShape,\n handler: async ({ symbol, kind }) => {\n const reference = await provider.get();\n const result = reference.lookup(symbol, kind);\n if (result.outcome === \"notFound\") {\n return textError(`No symbol named \"${symbol}\". Use \\`gtkx_search_api\\` to find the right name.`);\n }\n if (result.outcome === \"ambiguous\") {\n return textError(\n `\"${symbol}\" matches several symbols. Pass a qualified name or a kind:\\n${formatCandidates(result.candidates)}`,\n );\n }\n return textContent(result.markdown);\n },\n });\n\nexport const buildReferenceTools = (provider: ReferenceProvider): Tool[] => [\n listApiTool(provider),\n searchApiTool(provider),\n getApiDocsTool(provider),\n];\n\nconst markdownResource = (uri: URL, text: string): ReadResourceResult => ({\n contents: [{ uri: uri.href, mimeType: \"text/markdown\", text }],\n});\n\nconst variableValue = (value: string | string[] | undefined): string =>\n Array.isArray(value) ? (value[0] ?? \"\") : (value ?? \"\");\n\ntype ResourceServer = Pick<McpServer, \"registerResource\">;\n\nconst swallowLoadFailure =\n <T>(fallback: T) =>\n (): T =>\n fallback;\n\nconst namespaceCompleter =\n (provider: ReferenceProvider) =>\n (value: string): Promise<string[]> =>\n provider\n .get()\n .then((reference) =>\n reference\n .namespaces()\n .map((summary) => summary.name)\n .filter((name) => name.toLowerCase().startsWith(value.toLowerCase())),\n )\n .catch(swallowLoadFailure<string[]>([]));\n\nconst resourceNotFound = (message: string): McpError => new McpError(ErrorCode.InvalidParams, message);\n\nconst registerIndexResource = (server: ResourceServer, provider: ReferenceProvider): void => {\n server.registerResource(\n \"gtkx-api-reference\",\n \"gtkx://reference/index\",\n {\n title: \"GTKX API reference index\",\n description: \"Namespaces of the project's generated GTK4 bindings, with symbol and JSX element counts.\",\n mimeType: \"text/markdown\",\n },\n async (uri) => markdownResource(uri, (await provider.get()).overview()),\n );\n};\n\nconst registerNamespaceResource = (server: ResourceServer, provider: ReferenceProvider): void => {\n server.registerResource(\n \"gtkx-api-namespace\",\n new ResourceTemplate(\"gtkx://reference/{namespace}\", {\n list: () =>\n provider\n .get()\n .then((reference) => ({\n resources: reference.namespaces().map((summary) => ({\n uri: `gtkx://reference/${summary.name}`,\n name: `${summary.name} namespace reference`,\n mimeType: \"text/markdown\",\n })),\n }))\n .catch(swallowLoadFailure({ resources: [] })),\n complete: {\n namespace: namespaceCompleter(provider),\n },\n }),\n {\n title: \"GTKX namespace reference\",\n description: \"All symbols of one namespace of the project's generated GTK4 bindings, grouped by kind.\",\n mimeType: \"text/markdown\",\n },\n async (uri, variables) => {\n const namespace = variableValue(variables.namespace);\n const overview = (await provider.get()).namespaceOverview(namespace);\n if (overview === undefined) throw resourceNotFound(`Unknown namespace \"${namespace}\"`);\n return markdownResource(uri, overview);\n },\n );\n};\n\nconst registerSymbolResource = (server: ResourceServer, provider: ReferenceProvider): void => {\n server.registerResource(\n \"gtkx-api-symbol\",\n new ResourceTemplate(\"gtkx://reference/{namespace}/{symbol}\", {\n list: undefined,\n complete: {\n namespace: namespaceCompleter(provider),\n symbol: (value, context) => {\n const namespace = variableValue(context?.arguments?.namespace);\n if (namespace.length === 0) return [];\n return provider\n .get()\n .then((reference) =>\n reference\n .symbolNames(namespace)\n .filter((name) => name.toLowerCase().startsWith(value.toLowerCase())),\n )\n .catch(swallowLoadFailure<string[]>([]));\n },\n },\n }),\n {\n title: \"GTKX symbol reference\",\n description:\n \"Reference page for one symbol of the project's generated GTK4 bindings: a JSX element or a class, interface, record, enum, callback, alias, function, or constant.\",\n mimeType: \"text/markdown\",\n },\n async (uri, variables) => {\n const namespace = variableValue(variables.namespace);\n const symbol = variableValue(variables.symbol);\n const reference = await provider.get();\n const result = reference.lookup(`${namespace}.${symbol}`);\n if (result.outcome === \"page\") return markdownResource(uri, result.markdown);\n if (result.outcome === \"ambiguous\") {\n throw resourceNotFound(\n `\"${namespace}.${symbol}\" matches several symbols:\\n${formatCandidates(result.candidates)}`,\n );\n }\n throw resourceNotFound(`No symbol named \"${namespace}.${symbol}\"`);\n },\n );\n};\n\nexport const registerReferenceResources = (server: ResourceServer, provider: ReferenceProvider): void => {\n registerIndexResource(server, provider);\n registerNamespaceResource(server, provider);\n registerSymbolResource(server, provider);\n};\n"]}
@@ -0,0 +1,14 @@
1
+ import { type Logger } from "@gtkx/utils";
2
+ export declare const log: Logger;
3
+ type CreateMcpServerOptions = {
4
+ socketPath?: string;
5
+ version: string;
6
+ };
7
+ type McpServerHandle = {
8
+ start(): Promise<void>;
9
+ stop(): Promise<void>;
10
+ };
11
+ export declare const createMcpServer: (options: CreateMcpServerOptions) => McpServerHandle;
12
+ export declare function main(): Promise<void>;
13
+ export {};
14
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAyC,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAqBjF,eAAO,MAAM,GAAG,EAAE,MAA4B,CAAC;AA+L/C,KAAK,sBAAsB,GAAG;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,eAAe,GAAG;IACnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,eAAe,YAAa,sBAAsB,KAAG,eAiDjE,CAAC;AAEF,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAM1C"}
package/dist/server.js ADDED
@@ -0,0 +1,220 @@
1
+ import { createRequire } from "node:module";
2
+ import { createLogger, installGracefulShutdown } from "@gtkx/utils";
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { z } from "zod";
6
+ import { AppRouter } from "./app-router.js";
7
+ import { ConnectionRegistry } from "./connection-registry.js";
8
+ import { DEFAULT_SOCKET_PATH, fireEventParams, queryParams, screenshotParams, typeParams, widgetIdParams, } from "./protocol/schemas.js";
9
+ import { buildReferenceTools, createReferenceProvider, registerReferenceResources } from "./reference.js";
10
+ import { SocketServer } from "./socket-server.js";
11
+ import { defineTool, imageContent, registerTool, textContent } from "./tool.js";
12
+ const require = createRequire(import.meta.url);
13
+ const { version } = require("../package.json");
14
+ export const log = createLogger("mcp");
15
+ const APPLICATION_ID_DESCRIPTION = "Application ID to query. If not specified, uses the first connected app.";
16
+ const WIDGET_ID_DESCRIPTION = "Widget ID obtained from `gtkx_get_widget_tree`, `gtkx_query_widgets`, or `gtkx_get_widget_props`. IDs are scoped to a single app. An ID stays valid for as long as its widget is mounted and stops resolving once the widget is unmounted.";
17
+ const applicationIdShape = { applicationId: z.string().optional().describe(APPLICATION_ID_DESCRIPTION) };
18
+ const widgetIdShape = {
19
+ ...applicationIdShape,
20
+ widgetId: widgetIdParams.shape.widgetId.describe(WIDGET_ID_DESCRIPTION),
21
+ };
22
+ const listAppsShape = {
23
+ waitForApps: z
24
+ .boolean()
25
+ .optional()
26
+ .describe("If true, wait for at least one app to register before returning. Useful when app is still starting."),
27
+ timeout: z.number().optional().describe("Timeout in milliseconds when waitForApps is true (default: 10000)"),
28
+ };
29
+ const queryWidgetsShape = {
30
+ ...applicationIdShape,
31
+ by: queryParams.shape.by.describe("Query type"),
32
+ value: queryParams.shape.value.describe("Value to search for"),
33
+ options: queryParams.shape.options.describe("Additional query options"),
34
+ };
35
+ const typeShape = {
36
+ ...widgetIdShape,
37
+ text: typeParams.shape.text.describe("Text to type"),
38
+ clear: typeParams.shape.clear.describe("Clear existing text before typing"),
39
+ };
40
+ const fireEventShape = {
41
+ ...widgetIdShape,
42
+ signal: fireEventParams.shape.signal.describe("GTK4 signal name to emit"),
43
+ args: fireEventParams.shape.args.describe("Arguments to pass to the signal"),
44
+ };
45
+ const screenshotShape = {
46
+ ...applicationIdShape,
47
+ windowId: screenshotParams.shape.windowId.describe("Window ID to capture. If not specified, captures the first window."),
48
+ path: screenshotParams.shape.path.describe("Absolute path to write the PNG to on the app's machine. If set, the screenshot is saved there in addition to being returned."),
49
+ };
50
+ const listAppsTool = (appRouter) => defineTool({
51
+ name: "gtkx_list_apps",
52
+ title: "List apps",
53
+ kind: "readOnly",
54
+ description: "List all connected GTKX applications and their open windows.",
55
+ inputSchema: listAppsShape,
56
+ handler: async ({ waitForApps, timeout }) => {
57
+ if (waitForApps && !appRouter.hasConnectedApps()) {
58
+ await appRouter.waitForApp(timeout);
59
+ }
60
+ const apps = appRouter.getApps();
61
+ const appsWithWindows = await Promise.all(apps.map(async (app) => {
62
+ try {
63
+ const result = await appRouter.sendToApp(app.applicationId, "app.getWindows", {});
64
+ return { ...app, windows: result.windows };
65
+ }
66
+ catch {
67
+ return app;
68
+ }
69
+ }));
70
+ return textContent(JSON.stringify(appsWithWindows, null, 2));
71
+ },
72
+ });
73
+ const screenshotTool = (appRouter) => defineTool({
74
+ name: "gtkx_take_screenshot",
75
+ title: "Take screenshot",
76
+ kind: "readOnly",
77
+ description: "Capture a screenshot of a window. Returns base64-encoded PNG image data, and optionally writes the PNG to `path` on the app's machine. You can't target widgets from a screenshot; use `gtkx_get_widget_tree` to find widget IDs for interaction.",
78
+ inputSchema: screenshotShape,
79
+ handler: async ({ applicationId, ...params }) => {
80
+ const result = await appRouter.sendToApp(applicationId, "widget.screenshot", params);
81
+ if (result.savedPath) {
82
+ return {
83
+ content: [
84
+ { type: "text", text: `Screenshot saved to ${result.savedPath}` },
85
+ { type: "image", data: result.data, mimeType: result.mimeType },
86
+ ],
87
+ };
88
+ }
89
+ return imageContent(result.data, result.mimeType);
90
+ },
91
+ });
92
+ function buildInspectionTools(appRouter) {
93
+ return [
94
+ listAppsTool(appRouter),
95
+ defineTool({
96
+ name: "gtkx_get_widget_tree",
97
+ title: "Widget tree",
98
+ kind: "readOnly",
99
+ description: "Get the widget hierarchy for a connected GTKX app. Returns a tree of all widgets with their IDs, types, roles, and properties.",
100
+ inputSchema: applicationIdShape,
101
+ handler: async ({ applicationId }) => {
102
+ const result = await appRouter.sendToApp(applicationId, "widget.getTree", {});
103
+ return textContent(result.tree);
104
+ },
105
+ }),
106
+ defineTool({
107
+ name: "gtkx_query_widgets",
108
+ title: "Query widgets",
109
+ kind: "readOnly",
110
+ description: "Find widgets by role, text, name, or label. Returns matching widgets with their IDs and properties.",
111
+ inputSchema: queryWidgetsShape,
112
+ handler: async ({ applicationId, ...params }) => {
113
+ const result = await appRouter.sendToApp(applicationId, "widget.query", params);
114
+ return textContent(JSON.stringify(result, null, 2));
115
+ },
116
+ }),
117
+ defineTool({
118
+ name: "gtkx_get_widget_props",
119
+ title: "Get widget properties",
120
+ kind: "readOnly",
121
+ description: "Get a fixed summary of one widget by ID: type, accessible role, name, text, sensitivity, visibility, CSS classes, and the full subtree of descendant widgets. It does not return arbitrary GObject properties.",
122
+ inputSchema: widgetIdShape,
123
+ handler: async ({ applicationId, ...params }) => {
124
+ const result = await appRouter.sendToApp(applicationId, "widget.getProps", params);
125
+ return textContent(JSON.stringify(result, null, 2));
126
+ },
127
+ }),
128
+ screenshotTool(appRouter),
129
+ ];
130
+ }
131
+ function buildInteractionTools(appRouter) {
132
+ return [
133
+ defineTool({
134
+ name: "gtkx_click",
135
+ title: "Click widget",
136
+ kind: "action",
137
+ description: "Click a widget. Works with buttons, checkboxes, and other interactive widgets.",
138
+ inputSchema: widgetIdShape,
139
+ handler: async ({ applicationId, ...params }) => {
140
+ await appRouter.sendToApp(applicationId, "widget.click", params);
141
+ return textContent("Clicked");
142
+ },
143
+ }),
144
+ defineTool({
145
+ name: "gtkx_type",
146
+ title: "Type text",
147
+ kind: "action",
148
+ description: "Type text into an editable widget like Entry or TextView",
149
+ inputSchema: typeShape,
150
+ handler: async ({ applicationId, ...params }) => {
151
+ await appRouter.sendToApp(applicationId, "widget.type", params);
152
+ return textContent("Typed text");
153
+ },
154
+ }),
155
+ defineTool({
156
+ name: "gtkx_fire_event",
157
+ title: "Fire event",
158
+ kind: "action",
159
+ description: "Emit a GTK4 signal on a widget. Use this for custom interactions.",
160
+ inputSchema: fireEventShape,
161
+ handler: async ({ applicationId, ...params }) => {
162
+ await appRouter.sendToApp(applicationId, "widget.fireEvent", params);
163
+ return textContent("Fired event");
164
+ },
165
+ }),
166
+ ];
167
+ }
168
+ function buildTools(appRouter) {
169
+ return [...buildInspectionTools(appRouter), ...buildInteractionTools(appRouter)];
170
+ }
171
+ export const createMcpServer = (options) => {
172
+ const socketPath = options.socketPath ?? DEFAULT_SOCKET_PATH;
173
+ const registry = new ConnectionRegistry();
174
+ const socketServer = new SocketServer(registry, socketPath);
175
+ const appRouter = new AppRouter(registry);
176
+ registry.on("error", (error) => {
177
+ const code = error.code;
178
+ if (code !== "EPIPE" && code !== "ECONNRESET") {
179
+ log.error(`socket error: ${error.message}`);
180
+ }
181
+ });
182
+ appRouter.on("appRegistered", (appInfo) => {
183
+ log.info(`app registered: ${appInfo.applicationId} (PID: ${appInfo.pid})`);
184
+ });
185
+ appRouter.on("appUnregistered", (applicationId) => {
186
+ log.info(`app unregistered: ${applicationId}`);
187
+ });
188
+ const mcpServer = new McpServer({ name: "gtkx-mcp", version: options.version });
189
+ const referenceProvider = createReferenceProvider(() => appRouter.getProjectRoot() ?? process.cwd());
190
+ for (const tool of [...buildTools(appRouter), ...buildReferenceTools(referenceProvider)]) {
191
+ registerTool(mcpServer, tool);
192
+ }
193
+ registerReferenceResources(mcpServer, referenceProvider);
194
+ let stopped = false;
195
+ return {
196
+ async start() {
197
+ await socketServer.start();
198
+ log.info(`socket server listening on ${socketPath}`);
199
+ const transport = new StdioServerTransport();
200
+ process.stdin.on("end", () => void this.stop());
201
+ process.stdin.on("close", () => void this.stop());
202
+ await mcpServer.connect(transport);
203
+ },
204
+ async stop() {
205
+ if (stopped)
206
+ return;
207
+ stopped = true;
208
+ await socketServer.stop();
209
+ await mcpServer.close();
210
+ },
211
+ };
212
+ };
213
+ export async function main() {
214
+ const server = createMcpServer({ version });
215
+ installGracefulShutdown({
216
+ onSignal: () => server.stop(),
217
+ });
218
+ await server.start();
219
+ }
220
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createRequire } from \"node:module\";\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 { z } from \"zod\";\nimport { AppRouter } from \"./app-router.js\";\nimport { ConnectionRegistry } from \"./connection-registry.js\";\nimport {\n DEFAULT_SOCKET_PATH,\n fireEventParams,\n queryParams,\n screenshotParams,\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, type Tool, textContent } from \"./tool.js\";\n\nconst require = createRequire(import.meta.url);\nconst { version } = require(\"../package.json\") as { version: string };\n\nexport const log: Logger = createLogger(\"mcp\");\n\nconst APPLICATION_ID_DESCRIPTION = \"Application ID to query. If not specified, uses the first connected app.\";\nconst WIDGET_ID_DESCRIPTION =\n \"Widget ID obtained from `gtkx_get_widget_tree`, `gtkx_query_widgets`, or `gtkx_get_widget_props`. IDs are scoped to a single app. An ID stays valid for as long as its widget is mounted and stops resolving once the widget is unmounted.\";\n\nconst applicationIdShape = { applicationId: z.string().optional().describe(APPLICATION_ID_DESCRIPTION) };\nconst widgetIdShape = {\n ...applicationIdShape,\n widgetId: widgetIdParams.shape.widgetId.describe(WIDGET_ID_DESCRIPTION),\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 in addition to being returned.\",\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(\n apps.map(async (app) => {\n try {\n const result = await appRouter.sendToApp<{\n windows: Array<{ id: string; title: string | null }>;\n }>(app.applicationId, \"app.getWindows\", {});\n return { ...app, windows: result.windows };\n } catch {\n return app;\n }\n }),\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 the PNG to `path` on the app's machine. You can't target widgets from a screenshot; use `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 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 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 all widgets with their IDs, types, roles, and properties.\",\n inputSchema: applicationIdShape,\n handler: async ({ applicationId }) => {\n const result = await appRouter.sendToApp<{ tree: string }>(applicationId, \"widget.getTree\", {});\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 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, visibility, CSS classes, and the full subtree of descendant widgets. It does not return arbitrary GObject properties.\",\n inputSchema: widgetIdShape,\n handler: async ({ applicationId, ...params }) => {\n const result = await appRouter.sendToApp(applicationId, \"widget.getProps\", params);\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 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 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 return textContent(\"Fired event\");\n },\n }),\n ];\n}\n\nfunction buildTools(appRouter: AppRouter): Tool[] {\n return [...buildInspectionTools(appRouter), ...buildInteractionTools(appRouter)];\n}\n\ntype CreateMcpServerOptions = {\n socketPath?: string;\n version: string;\n};\n\ntype McpServerHandle = {\n start(): Promise<void>;\n stop(): Promise<void>;\n};\n\nexport const createMcpServer = (options: CreateMcpServerOptions): McpServerHandle => {\n const socketPath = options.socketPath ?? DEFAULT_SOCKET_PATH;\n\n const registry = new ConnectionRegistry();\n const socketServer = new SocketServer(registry, socketPath);\n const appRouter = new AppRouter(registry);\n\n registry.on(\"error\", (error) => {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"EPIPE\" && code !== \"ECONNRESET\") {\n log.error(`socket error: ${error.message}`);\n }\n });\n\n appRouter.on(\"appRegistered\", (appInfo) => {\n log.info(`app registered: ${appInfo.applicationId} (PID: ${appInfo.pid})`);\n });\n\n appRouter.on(\"appUnregistered\", (applicationId) => {\n log.info(`app unregistered: ${applicationId}`);\n });\n\n const mcpServer = new McpServer({ name: \"gtkx-mcp\", version: options.version });\n\n const referenceProvider = createReferenceProvider(() => appRouter.getProjectRoot() ?? process.cwd());\n\n for (const tool of [...buildTools(appRouter), ...buildReferenceTools(referenceProvider)]) {\n registerTool(mcpServer, tool);\n }\n registerReferenceResources(mcpServer, referenceProvider);\n\n let stopped = false;\n\n return {\n async start() {\n await socketServer.start();\n log.info(`socket server listening on ${socketPath}`);\n const transport = new StdioServerTransport();\n process.stdin.on(\"end\", () => void this.stop());\n process.stdin.on(\"close\", () => void this.stop());\n await mcpServer.connect(transport);\n },\n async stop() {\n if (stopped) return;\n stopped = true;\n await socketServer.stop();\n await mcpServer.close();\n },\n };\n};\n\nexport async function main(): Promise<void> {\n const server = createMcpServer({ version });\n installGracefulShutdown({\n onSignal: () => server.stop(),\n });\n await server.start();\n}\n"]}
@@ -1,44 +1,10 @@
1
- import EventEmitter from "node:events";
2
- import * as net from "node:net";
3
- import { type IpcMessage, type IpcRequest, type IpcResponse } from "./protocol/types.js";
4
- type SocketServerEventMap = {
5
- connection: [AppConnection];
6
- disconnection: [AppConnection];
7
- request: [AppConnection, IpcRequest];
8
- response: [AppConnection, IpcResponse];
9
- error: [Error];
10
- };
11
- /**
12
- * Represents a connected application.
13
- */
14
- export type AppConnection = {
15
- /** Unique connection identifier */
16
- id: string;
17
- /** The underlying socket */
18
- socket: net.Socket;
19
- /** Buffer for incomplete messages */
20
- buffer: string;
21
- };
22
- /**
23
- * Unix domain socket server for MCP communication.
24
- *
25
- * Manages connections from GTKX applications and handles IPC messaging.
26
- */
27
- export declare class SocketServer extends EventEmitter<SocketServerEventMap> {
1
+ import type { ConnectionRegistry } from "./connection-registry.js";
2
+ export declare class SocketServer {
28
3
  private server;
29
- private connections;
30
4
  private socketPath;
31
- constructor(socketPath?: string);
32
- get path(): string;
33
- get isListening(): boolean;
34
- getConnections(): AppConnection[];
35
- getConnection(id: string): AppConnection | undefined;
5
+ private registry;
6
+ constructor(registry: ConnectionRegistry, socketPath?: string);
36
7
  start(): Promise<void>;
37
8
  stop(): Promise<void>;
38
- send(connectionId: string, message: IpcMessage): boolean;
39
- private handleConnection;
40
- private handleData;
41
- private processMessage;
42
9
  }
43
- export {};
44
10
  //# sourceMappingURL=socket-server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"socket-server.d.ts","sourceRoot":"","sources":["../src/socket-server.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,aAAa,CAAC;AAEvC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,OAAO,EAEH,KAAK,UAAU,EACf,KAAK,UAAU,EAEf,KAAK,WAAW,EAEnB,MAAM,qBAAqB,CAAC;AAE7B,KAAK,oBAAoB,GAAG;IACxB,UAAU,EAAE,CAAC,aAAa,CAAC,CAAC;IAC5B,aAAa,EAAE,CAAC,aAAa,CAAC,CAAC;IAC/B,OAAO,EAAE,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IACrC,QAAQ,EAAE,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IACvC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IACxB,mCAAmC;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,4BAA4B;IAC5B,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC;IACnB,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IAChE,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,GAAE,MAA4B;IAKpD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,cAAc,IAAI,aAAa,EAAE;IAIjC,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB3B,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO;IAWxD,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,cAAc;CAoCzB"}
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;AAanE,qBAAa,YAAY;IACrB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAqB;IAErC,YAAY,QAAQ,EAAE,kBAAkB,EAAE,UAAU,GAAE,MAA4B,EAGjF;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CA2B3B;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAc1B;CACJ"}