@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.
- package/README.md +122 -55
- package/bin/gtkx-mcp.js +8 -1
- package/dist/app-router.d.ts +35 -0
- package/dist/app-router.d.ts.map +1 -0
- package/dist/app-router.js +130 -0
- package/dist/app-router.js.map +1 -0
- package/dist/connection-registry.d.ts +12 -0
- package/dist/connection-registry.d.ts.map +1 -0
- package/dist/connection-registry.js +38 -0
- package/dist/connection-registry.js.map +1 -0
- package/dist/internal.d.ts +4 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +4 -0
- package/dist/internal.js.map +1 -0
- package/dist/protocol/errors.d.ts +24 -87
- package/dist/protocol/errors.d.ts.map +1 -1
- package/dist/protocol/errors.js +27 -91
- package/dist/protocol/errors.js.map +1 -1
- package/dist/protocol/schemas.d.ts +89 -0
- package/dist/protocol/schemas.d.ts.map +1 -0
- package/dist/protocol/schemas.js +56 -0
- package/dist/protocol/schemas.js.map +1 -0
- package/dist/reference.d.ts +13 -0
- package/dist/reference.d.ts.map +1 -0
- package/dist/reference.js +250 -0
- package/dist/reference.js.map +1 -0
- package/dist/server.d.ts +14 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +220 -0
- package/dist/server.js.map +1 -0
- package/dist/socket-server.d.ts +4 -38
- package/dist/socket-server.d.ts.map +1 -1
- package/dist/socket-server.js +26 -109
- package/dist/socket-server.js.map +1 -1
- package/dist/tool.d.ts +22 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +36 -0
- package/dist/tool.js.map +1 -0
- package/dist/transport.d.ts +41 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +121 -0
- package/dist/transport.js.map +1 -0
- package/package.json +17 -11
- package/src/app-router.ts +172 -0
- package/src/connection-registry.ts +42 -0
- package/src/internal.ts +17 -0
- package/src/protocol/errors.ts +44 -100
- package/src/protocol/schemas.ts +148 -0
- package/src/reference.ts +340 -0
- package/src/server.ts +281 -0
- package/src/socket-server.ts +30 -154
- package/src/tool.ts +66 -0
- package/src/transport.ts +165 -0
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -399
- package/dist/cli.js.map +0 -1
- package/dist/connection-manager.d.ts +0 -48
- package/dist/connection-manager.d.ts.map +0 -1
- package/dist/connection-manager.js +0 -185
- package/dist/connection-manager.js.map +0 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -5
- package/dist/index.js.map +0 -1
- package/dist/protocol/types.d.ts +0 -132
- package/dist/protocol/types.d.ts.map +0 -1
- package/dist/protocol/types.js +0 -46
- package/dist/protocol/types.js.map +0 -1
- package/src/cli.ts +0 -449
- package/src/connection-manager.ts +0 -247
- package/src/index.ts +0 -27
- package/src/protocol/types.ts +0 -153
package/dist/index.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { ConnectionManager } from "./connection-manager.js";
|
|
2
|
-
export { appNotFoundError, invalidRequestError, ipcTimeoutError, McpError, McpErrorCode, methodNotFoundError, noAppConnectedError, widgetNotFoundError, } from "./protocol/errors.js";
|
|
3
|
-
export { type AppInfo, DEFAULT_SOCKET_PATH, getRuntimeDir, type IpcError, IpcErrorSchema, type IpcMessage, type IpcMethod, type IpcRequest, IpcRequestSchema, type IpcResponse, IpcResponseSchema, type QueryOptions, type SerializedWidget, } from "./protocol/types.js";
|
|
4
|
-
export { type AppConnection, SocketServer } from "./socket-server.js";
|
|
5
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACH,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACH,KAAK,OAAO,EACZ,mBAAmB,EACnB,aAAa,EACb,KAAK,QAAQ,EACb,cAAc,EACd,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,UAAU,EACf,gBAAgB,EAChB,KAAK,WAAW,EAChB,iBAAiB,EACjB,KAAK,YAAY,EACjB,KAAK,gBAAgB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,aAAa,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { ConnectionManager } from "./connection-manager.js";
|
|
2
|
-
export { appNotFoundError, invalidRequestError, ipcTimeoutError, McpError, McpErrorCode, methodNotFoundError, noAppConnectedError, widgetNotFoundError, } from "./protocol/errors.js";
|
|
3
|
-
export { DEFAULT_SOCKET_PATH, getRuntimeDir, IpcErrorSchema, IpcRequestSchema, IpcResponseSchema, } from "./protocol/types.js";
|
|
4
|
-
export { SocketServer } from "./socket-server.js";
|
|
5
|
-
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACH,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEH,mBAAmB,EACnB,aAAa,EAEb,cAAc,EAId,gBAAgB,EAEhB,iBAAiB,GAGpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAsB,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/protocol/types.d.ts
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
/**
|
|
3
|
-
* Zod schema for validating IPC requests.
|
|
4
|
-
*/
|
|
5
|
-
export declare const IpcRequestSchema: z.ZodObject<{
|
|
6
|
-
id: z.ZodString;
|
|
7
|
-
method: z.ZodString;
|
|
8
|
-
params: z.ZodOptional<z.ZodUnknown>;
|
|
9
|
-
}, z.core.$strip>;
|
|
10
|
-
/**
|
|
11
|
-
* An IPC request message.
|
|
12
|
-
*/
|
|
13
|
-
export type IpcRequest = z.infer<typeof IpcRequestSchema>;
|
|
14
|
-
/**
|
|
15
|
-
* An IPC error object.
|
|
16
|
-
*/
|
|
17
|
-
export type IpcError = {
|
|
18
|
-
/** Error code */
|
|
19
|
-
code: number;
|
|
20
|
-
/** Error message */
|
|
21
|
-
message: string;
|
|
22
|
-
/** Additional error data */
|
|
23
|
-
data?: unknown;
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* Zod schema for validating IPC errors.
|
|
27
|
-
*/
|
|
28
|
-
export declare const IpcErrorSchema: z.ZodObject<{
|
|
29
|
-
code: z.ZodNumber;
|
|
30
|
-
message: z.ZodString;
|
|
31
|
-
data: z.ZodOptional<z.ZodUnknown>;
|
|
32
|
-
}, z.core.$strip>;
|
|
33
|
-
/**
|
|
34
|
-
* Zod schema for validating IPC responses.
|
|
35
|
-
*/
|
|
36
|
-
export declare const IpcResponseSchema: z.ZodObject<{
|
|
37
|
-
id: z.ZodString;
|
|
38
|
-
result: z.ZodOptional<z.ZodUnknown>;
|
|
39
|
-
error: z.ZodOptional<z.ZodObject<{
|
|
40
|
-
code: z.ZodNumber;
|
|
41
|
-
message: z.ZodString;
|
|
42
|
-
data: z.ZodOptional<z.ZodUnknown>;
|
|
43
|
-
}, z.core.$strip>>;
|
|
44
|
-
}, z.core.$strip>;
|
|
45
|
-
/**
|
|
46
|
-
* An IPC response message.
|
|
47
|
-
*/
|
|
48
|
-
export type IpcResponse = z.infer<typeof IpcResponseSchema>;
|
|
49
|
-
/**
|
|
50
|
-
* A serialized representation of a GTK widget for IPC transfer.
|
|
51
|
-
*/
|
|
52
|
-
export type SerializedWidget = {
|
|
53
|
-
/** Unique widget identifier */
|
|
54
|
-
id: string;
|
|
55
|
-
/** Widget type name (e.g., "GtkButton") */
|
|
56
|
-
type: string;
|
|
57
|
-
/** Accessible role */
|
|
58
|
-
role: string;
|
|
59
|
-
/** Widget name (test ID) */
|
|
60
|
-
name: string | null;
|
|
61
|
-
/** Accessible label */
|
|
62
|
-
label: string | null;
|
|
63
|
-
/** Text content */
|
|
64
|
-
text: string | null;
|
|
65
|
-
/** Whether the widget is sensitive (interactive) */
|
|
66
|
-
sensitive: boolean;
|
|
67
|
-
/** Whether the widget is visible */
|
|
68
|
-
visible: boolean;
|
|
69
|
-
/** CSS class names */
|
|
70
|
-
cssClasses: string[];
|
|
71
|
-
/** Child widgets */
|
|
72
|
-
children: SerializedWidget[];
|
|
73
|
-
/** Widget bounds in window coordinates */
|
|
74
|
-
bounds?: {
|
|
75
|
-
x: number;
|
|
76
|
-
y: number;
|
|
77
|
-
width: number;
|
|
78
|
-
height: number;
|
|
79
|
-
};
|
|
80
|
-
};
|
|
81
|
-
/**
|
|
82
|
-
* Information about a connected GTKX application.
|
|
83
|
-
*/
|
|
84
|
-
export type AppInfo = {
|
|
85
|
-
/** Application ID (e.g., "com.example.myapp") */
|
|
86
|
-
appId: string;
|
|
87
|
-
/** Process ID */
|
|
88
|
-
pid: number;
|
|
89
|
-
/** Open windows */
|
|
90
|
-
windows: Array<{
|
|
91
|
-
id: string;
|
|
92
|
-
title: string | null;
|
|
93
|
-
}>;
|
|
94
|
-
};
|
|
95
|
-
/**
|
|
96
|
-
* Options for widget queries.
|
|
97
|
-
*/
|
|
98
|
-
export type QueryOptions = {
|
|
99
|
-
/** Widget name to match */
|
|
100
|
-
name?: string;
|
|
101
|
-
/** Require exact match */
|
|
102
|
-
exact?: boolean;
|
|
103
|
-
/** Query timeout in milliseconds */
|
|
104
|
-
timeout?: number;
|
|
105
|
-
};
|
|
106
|
-
/**
|
|
107
|
-
* Zod schema for app registration parameters.
|
|
108
|
-
* @internal
|
|
109
|
-
*/
|
|
110
|
-
export declare const RegisterParamsSchema: z.ZodObject<{
|
|
111
|
-
appId: z.ZodString;
|
|
112
|
-
pid: z.ZodNumber;
|
|
113
|
-
}, z.core.$strip>;
|
|
114
|
-
/**
|
|
115
|
-
* Available IPC methods.
|
|
116
|
-
*/
|
|
117
|
-
export type IpcMethod = "app.register" | "app.unregister" | "app.getWindows" | "widget.getTree" | "widget.query" | "widget.getProps" | "widget.click" | "widget.type" | "widget.fireEvent" | "widget.screenshot";
|
|
118
|
-
/**
|
|
119
|
-
* Union type for any IPC message (request or response).
|
|
120
|
-
*/
|
|
121
|
-
export type IpcMessage = IpcRequest | IpcResponse;
|
|
122
|
-
/**
|
|
123
|
-
* Gets the XDG runtime directory or falls back to system temp.
|
|
124
|
-
*
|
|
125
|
-
* @returns Path to the runtime directory
|
|
126
|
-
*/
|
|
127
|
-
export declare const getRuntimeDir: () => string;
|
|
128
|
-
/**
|
|
129
|
-
* Default path for the MCP socket file.
|
|
130
|
-
*/
|
|
131
|
-
export declare const DEFAULT_SOCKET_PATH: string;
|
|
132
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/protocol/types.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;iBAI3B,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACnB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc;;;;iBAIzB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;iBAI5B,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC3B,+BAA+B;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,uBAAuB;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,mBAAmB;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,oDAAoD;IACpD,SAAS,EAAE,OAAO,CAAC;IACnB,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,sBAAsB;IACtB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,oBAAoB;IACpB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,0CAA0C;IAC1C,MAAM,CAAC,EAAE;QACL,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAClB,CAAC;CACL,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG;IAClB,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,mBAAmB;IACnB,OAAO,EAAE,KAAK,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACxB,CAAC,CAAC;CACN,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACvB,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,oBAAoB;;;iBAG/B,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,SAAS,GACf,cAAc,GACd,gBAAgB,GAChB,gBAAgB,GAChB,gBAAgB,GAChB,cAAc,GACd,iBAAiB,GACjB,cAAc,GACd,aAAa,GACb,kBAAkB,GAClB,mBAAmB,CAAC;AAE1B;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,WAAW,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,aAAa,QAAO,MAAiD,CAAC;AAEnF;;GAEG;AACH,eAAO,MAAM,mBAAmB,QAAyC,CAAC"}
|
package/dist/protocol/types.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { tmpdir } from "node:os";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { z } from "zod";
|
|
4
|
-
/**
|
|
5
|
-
* Zod schema for validating IPC requests.
|
|
6
|
-
*/
|
|
7
|
-
export const IpcRequestSchema = z.object({
|
|
8
|
-
id: z.string(),
|
|
9
|
-
method: z.string(),
|
|
10
|
-
params: z.unknown().optional(),
|
|
11
|
-
});
|
|
12
|
-
/**
|
|
13
|
-
* Zod schema for validating IPC errors.
|
|
14
|
-
*/
|
|
15
|
-
export const IpcErrorSchema = z.object({
|
|
16
|
-
code: z.number(),
|
|
17
|
-
message: z.string(),
|
|
18
|
-
data: z.unknown().optional(),
|
|
19
|
-
});
|
|
20
|
-
/**
|
|
21
|
-
* Zod schema for validating IPC responses.
|
|
22
|
-
*/
|
|
23
|
-
export const IpcResponseSchema = z.object({
|
|
24
|
-
id: z.string(),
|
|
25
|
-
result: z.unknown().optional(),
|
|
26
|
-
error: IpcErrorSchema.optional(),
|
|
27
|
-
});
|
|
28
|
-
/**
|
|
29
|
-
* Zod schema for app registration parameters.
|
|
30
|
-
* @internal
|
|
31
|
-
*/
|
|
32
|
-
export const RegisterParamsSchema = z.object({
|
|
33
|
-
appId: z.string(),
|
|
34
|
-
pid: z.number(),
|
|
35
|
-
});
|
|
36
|
-
/**
|
|
37
|
-
* Gets the XDG runtime directory or falls back to system temp.
|
|
38
|
-
*
|
|
39
|
-
* @returns Path to the runtime directory
|
|
40
|
-
*/
|
|
41
|
-
export const getRuntimeDir = () => process.env.XDG_RUNTIME_DIR ?? tmpdir();
|
|
42
|
-
/**
|
|
43
|
-
* Default path for the MCP socket file.
|
|
44
|
-
*/
|
|
45
|
-
export const DEFAULT_SOCKET_PATH = join(getRuntimeDir(), "gtkx-mcp.sock");
|
|
46
|
-
//# sourceMappingURL=types.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/protocol/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC;AAmBH;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC9B,KAAK,EAAE,cAAc,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAmEH;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;CAClB,CAAC,CAAC;AAsBH;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,GAAW,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,MAAM,EAAE,CAAC;AAEnF;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC,aAAa,EAAE,EAAE,eAAe,CAAC,CAAC"}
|
package/src/cli.ts
DELETED
|
@@ -1,449 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { createRequire } from "node:module";
|
|
4
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
-
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
-
import { z } from "zod";
|
|
8
|
-
import { ConnectionManager } from "./connection-manager.js";
|
|
9
|
-
import { DEFAULT_SOCKET_PATH } from "./protocol/types.js";
|
|
10
|
-
import { SocketServer } from "./socket-server.js";
|
|
11
|
-
|
|
12
|
-
const require = createRequire(import.meta.url);
|
|
13
|
-
const { version } = require("../package.json") as { version: string };
|
|
14
|
-
|
|
15
|
-
const AppIdSchema = z.object({
|
|
16
|
-
appId: z.string().optional().describe("App ID to query. If not specified, uses the first connected app."),
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const ListAppsInputSchema = z.object({
|
|
20
|
-
waitForApps: z
|
|
21
|
-
.boolean()
|
|
22
|
-
.optional()
|
|
23
|
-
.describe(
|
|
24
|
-
"If true, wait for at least one app to register before returning. Useful when app is still starting.",
|
|
25
|
-
),
|
|
26
|
-
timeout: z.number().optional().describe("Timeout in milliseconds when waitForApps is true (default: 10000)"),
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
const GetWidgetTreeInputSchema = AppIdSchema;
|
|
30
|
-
|
|
31
|
-
const QueryWidgetsInputSchema = AppIdSchema.extend({
|
|
32
|
-
by: z.enum(["role", "text", "testId", "labelText"]).describe("Query type"),
|
|
33
|
-
value: z.union([z.string(), z.number()]).describe("Value to search for"),
|
|
34
|
-
options: z
|
|
35
|
-
.object({
|
|
36
|
-
name: z.string().optional(),
|
|
37
|
-
exact: z.boolean().optional(),
|
|
38
|
-
timeout: z.number().optional(),
|
|
39
|
-
})
|
|
40
|
-
.optional()
|
|
41
|
-
.describe("Additional query options"),
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
const WidgetIdSchema = AppIdSchema.extend({
|
|
45
|
-
widgetId: z.string().describe("Widget ID"),
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
const GetWidgetPropsInputSchema = WidgetIdSchema;
|
|
49
|
-
|
|
50
|
-
const ClickInputSchema = WidgetIdSchema;
|
|
51
|
-
|
|
52
|
-
const TypeInputSchema = WidgetIdSchema.extend({
|
|
53
|
-
text: z.string().describe("Text to type"),
|
|
54
|
-
clear: z.boolean().optional().describe("Clear existing text before typing"),
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const FireEventInputSchema = WidgetIdSchema.extend({
|
|
58
|
-
signal: z.string().describe("GTK signal name to emit"),
|
|
59
|
-
args: z.array(z.unknown()).optional().describe("Arguments to pass to the signal"),
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const TakeScreenshotInputSchema = AppIdSchema.extend({
|
|
63
|
-
windowId: z.string().optional().describe("Window ID to capture. If not specified, captures the first window."),
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
const tools = [
|
|
67
|
-
{
|
|
68
|
-
name: "gtkx_list_apps",
|
|
69
|
-
description: "List all connected GTKX applications",
|
|
70
|
-
inputSchema: {
|
|
71
|
-
type: "object" as const,
|
|
72
|
-
properties: {
|
|
73
|
-
waitForApps: {
|
|
74
|
-
type: "boolean",
|
|
75
|
-
description:
|
|
76
|
-
"If true, wait for at least one app to register before returning. Useful when app is still starting.",
|
|
77
|
-
},
|
|
78
|
-
timeout: {
|
|
79
|
-
type: "number",
|
|
80
|
-
description: "Timeout in milliseconds when waitForApps is true (default: 10000)",
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
required: [],
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
name: "gtkx_get_widget_tree",
|
|
88
|
-
description:
|
|
89
|
-
"Get the widget hierarchy for a connected GTKX app. Returns a tree of all widgets with their IDs, types, roles, and properties.",
|
|
90
|
-
inputSchema: {
|
|
91
|
-
type: "object" as const,
|
|
92
|
-
properties: {
|
|
93
|
-
appId: {
|
|
94
|
-
type: "string",
|
|
95
|
-
description: "App ID to query. If not specified, uses the first connected app.",
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
required: [],
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
name: "gtkx_query_widgets",
|
|
103
|
-
description:
|
|
104
|
-
"Find widgets by role, text, testId, or label. Returns matching widgets with their IDs and properties.",
|
|
105
|
-
inputSchema: {
|
|
106
|
-
type: "object" as const,
|
|
107
|
-
properties: {
|
|
108
|
-
appId: {
|
|
109
|
-
type: "string",
|
|
110
|
-
description: "App ID to query. If not specified, uses the first connected app.",
|
|
111
|
-
},
|
|
112
|
-
by: {
|
|
113
|
-
type: "string",
|
|
114
|
-
enum: ["role", "text", "testId", "labelText"],
|
|
115
|
-
description: "Query type",
|
|
116
|
-
},
|
|
117
|
-
value: {
|
|
118
|
-
oneOf: [{ type: "string" }, { type: "number" }],
|
|
119
|
-
description: "Value to search for",
|
|
120
|
-
},
|
|
121
|
-
options: {
|
|
122
|
-
type: "object",
|
|
123
|
-
properties: {
|
|
124
|
-
name: { type: "string" },
|
|
125
|
-
exact: { type: "boolean" },
|
|
126
|
-
timeout: { type: "number" },
|
|
127
|
-
},
|
|
128
|
-
description: "Additional query options",
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
required: ["by", "value"],
|
|
132
|
-
},
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
name: "gtkx_get_widget_props",
|
|
136
|
-
description: "Get all properties of a specific widget by its ID",
|
|
137
|
-
inputSchema: {
|
|
138
|
-
type: "object" as const,
|
|
139
|
-
properties: {
|
|
140
|
-
appId: {
|
|
141
|
-
type: "string",
|
|
142
|
-
description: "App ID to query. If not specified, uses the first connected app.",
|
|
143
|
-
},
|
|
144
|
-
widgetId: {
|
|
145
|
-
type: "string",
|
|
146
|
-
description: "Widget ID to get properties for",
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
required: ["widgetId"],
|
|
150
|
-
},
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
name: "gtkx_click",
|
|
154
|
-
description: "Click a widget. Works with buttons, checkboxes, and other interactive widgets.",
|
|
155
|
-
inputSchema: {
|
|
156
|
-
type: "object" as const,
|
|
157
|
-
properties: {
|
|
158
|
-
appId: {
|
|
159
|
-
type: "string",
|
|
160
|
-
description: "App ID to query. If not specified, uses the first connected app.",
|
|
161
|
-
},
|
|
162
|
-
widgetId: {
|
|
163
|
-
type: "string",
|
|
164
|
-
description: "Widget ID to click",
|
|
165
|
-
},
|
|
166
|
-
},
|
|
167
|
-
required: ["widgetId"],
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
name: "gtkx_type",
|
|
172
|
-
description: "Type text into an editable widget like Entry or TextView",
|
|
173
|
-
inputSchema: {
|
|
174
|
-
type: "object" as const,
|
|
175
|
-
properties: {
|
|
176
|
-
appId: {
|
|
177
|
-
type: "string",
|
|
178
|
-
description: "App ID to query. If not specified, uses the first connected app.",
|
|
179
|
-
},
|
|
180
|
-
widgetId: {
|
|
181
|
-
type: "string",
|
|
182
|
-
description: "Widget ID to type into",
|
|
183
|
-
},
|
|
184
|
-
text: {
|
|
185
|
-
type: "string",
|
|
186
|
-
description: "Text to type",
|
|
187
|
-
},
|
|
188
|
-
clear: {
|
|
189
|
-
type: "boolean",
|
|
190
|
-
description: "Clear existing text before typing",
|
|
191
|
-
},
|
|
192
|
-
},
|
|
193
|
-
required: ["widgetId", "text"],
|
|
194
|
-
},
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
name: "gtkx_fire_event",
|
|
198
|
-
description: "Emit a GTK signal on a widget. Use this for custom interactions.",
|
|
199
|
-
inputSchema: {
|
|
200
|
-
type: "object" as const,
|
|
201
|
-
properties: {
|
|
202
|
-
appId: {
|
|
203
|
-
type: "string",
|
|
204
|
-
description: "App ID to query. If not specified, uses the first connected app.",
|
|
205
|
-
},
|
|
206
|
-
widgetId: {
|
|
207
|
-
type: "string",
|
|
208
|
-
description: "Widget ID to emit event on",
|
|
209
|
-
},
|
|
210
|
-
signal: {
|
|
211
|
-
type: "string",
|
|
212
|
-
description: "GTK signal name to emit",
|
|
213
|
-
},
|
|
214
|
-
args: {
|
|
215
|
-
type: "array",
|
|
216
|
-
items: {},
|
|
217
|
-
description: "Arguments to pass to the signal",
|
|
218
|
-
},
|
|
219
|
-
},
|
|
220
|
-
required: ["widgetId", "signal"],
|
|
221
|
-
},
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
name: "gtkx_take_screenshot",
|
|
225
|
-
description: "Capture a screenshot of a window. Returns base64-encoded PNG image data.",
|
|
226
|
-
inputSchema: {
|
|
227
|
-
type: "object" as const,
|
|
228
|
-
properties: {
|
|
229
|
-
appId: {
|
|
230
|
-
type: "string",
|
|
231
|
-
description: "App ID to query. If not specified, uses the first connected app.",
|
|
232
|
-
},
|
|
233
|
-
windowId: {
|
|
234
|
-
type: "string",
|
|
235
|
-
description: "Window ID to capture. If not specified, captures the first window.",
|
|
236
|
-
},
|
|
237
|
-
},
|
|
238
|
-
required: [],
|
|
239
|
-
},
|
|
240
|
-
},
|
|
241
|
-
];
|
|
242
|
-
|
|
243
|
-
async function main() {
|
|
244
|
-
const socketServer = new SocketServer(DEFAULT_SOCKET_PATH);
|
|
245
|
-
const connectionManager = new ConnectionManager(socketServer);
|
|
246
|
-
|
|
247
|
-
socketServer.on("error", (error) => {
|
|
248
|
-
const code = (error as NodeJS.ErrnoException).code;
|
|
249
|
-
if (code !== "EPIPE" && code !== "ECONNRESET") {
|
|
250
|
-
console.error("[gtkx] Socket error:", error.message);
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
await socketServer.start();
|
|
255
|
-
console.error(`[gtkx] Socket server listening on ${DEFAULT_SOCKET_PATH}`);
|
|
256
|
-
|
|
257
|
-
connectionManager.on("appRegistered", (appInfo) => {
|
|
258
|
-
console.error(`[gtkx] App registered: ${appInfo.appId} (PID: ${appInfo.pid})`);
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
connectionManager.on("appUnregistered", (appId) => {
|
|
262
|
-
console.error(`[gtkx] App unregistered: ${appId}`);
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
const server = new Server(
|
|
266
|
-
{
|
|
267
|
-
name: "gtkx-mcp",
|
|
268
|
-
version,
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
capabilities: {
|
|
272
|
-
tools: {},
|
|
273
|
-
},
|
|
274
|
-
},
|
|
275
|
-
);
|
|
276
|
-
|
|
277
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
278
|
-
return { tools };
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
282
|
-
const { name, arguments: args } = request.params;
|
|
283
|
-
|
|
284
|
-
try {
|
|
285
|
-
switch (name) {
|
|
286
|
-
case "gtkx_list_apps": {
|
|
287
|
-
const input = ListAppsInputSchema.parse(args);
|
|
288
|
-
|
|
289
|
-
if (input.waitForApps && !connectionManager.hasConnectedApps()) {
|
|
290
|
-
try {
|
|
291
|
-
await connectionManager.waitForApp(input.timeout);
|
|
292
|
-
} catch (error) {
|
|
293
|
-
return {
|
|
294
|
-
content: [
|
|
295
|
-
{
|
|
296
|
-
type: "text",
|
|
297
|
-
text: error instanceof Error ? error.message : "Timeout waiting for app",
|
|
298
|
-
},
|
|
299
|
-
],
|
|
300
|
-
isError: true,
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const apps = connectionManager.getApps();
|
|
306
|
-
const appsWithWindows = await Promise.all(
|
|
307
|
-
apps.map(async (app) => {
|
|
308
|
-
try {
|
|
309
|
-
const result = await connectionManager.sendToApp<{
|
|
310
|
-
windows: Array<{ id: string; title: string | null }>;
|
|
311
|
-
}>(app.appId, "app.getWindows", {});
|
|
312
|
-
return { ...app, windows: result.windows };
|
|
313
|
-
} catch {
|
|
314
|
-
return app;
|
|
315
|
-
}
|
|
316
|
-
}),
|
|
317
|
-
);
|
|
318
|
-
return {
|
|
319
|
-
content: [{ type: "text", text: JSON.stringify(appsWithWindows, null, 2) }],
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
case "gtkx_get_widget_tree": {
|
|
324
|
-
const input = GetWidgetTreeInputSchema.parse(args);
|
|
325
|
-
const result = await connectionManager.sendToApp<{ tree: string }>(
|
|
326
|
-
input.appId,
|
|
327
|
-
"widget.getTree",
|
|
328
|
-
{},
|
|
329
|
-
);
|
|
330
|
-
return {
|
|
331
|
-
content: [{ type: "text", text: result.tree }],
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
case "gtkx_query_widgets": {
|
|
336
|
-
const input = QueryWidgetsInputSchema.parse(args);
|
|
337
|
-
const result = await connectionManager.sendToApp(input.appId, "widget.query", {
|
|
338
|
-
queryType: input.by,
|
|
339
|
-
value: input.value,
|
|
340
|
-
options: input.options,
|
|
341
|
-
});
|
|
342
|
-
return {
|
|
343
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
case "gtkx_get_widget_props": {
|
|
348
|
-
const input = GetWidgetPropsInputSchema.parse(args);
|
|
349
|
-
const result = await connectionManager.sendToApp(input.appId, "widget.getProps", {
|
|
350
|
-
widgetId: input.widgetId,
|
|
351
|
-
});
|
|
352
|
-
return {
|
|
353
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
case "gtkx_click": {
|
|
358
|
-
const input = ClickInputSchema.parse(args);
|
|
359
|
-
await connectionManager.sendToApp(input.appId, "widget.click", {
|
|
360
|
-
widgetId: input.widgetId,
|
|
361
|
-
});
|
|
362
|
-
return {
|
|
363
|
-
content: [{ type: "text", text: "Click successful" }],
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
case "gtkx_type": {
|
|
368
|
-
const input = TypeInputSchema.parse(args);
|
|
369
|
-
await connectionManager.sendToApp(input.appId, "widget.type", {
|
|
370
|
-
widgetId: input.widgetId,
|
|
371
|
-
text: input.text,
|
|
372
|
-
clear: input.clear,
|
|
373
|
-
});
|
|
374
|
-
return {
|
|
375
|
-
content: [{ type: "text", text: "Type successful" }],
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
case "gtkx_fire_event": {
|
|
380
|
-
const input = FireEventInputSchema.parse(args);
|
|
381
|
-
await connectionManager.sendToApp(input.appId, "widget.fireEvent", {
|
|
382
|
-
widgetId: input.widgetId,
|
|
383
|
-
signal: input.signal,
|
|
384
|
-
args: input.args,
|
|
385
|
-
});
|
|
386
|
-
return {
|
|
387
|
-
content: [{ type: "text", text: "Event fired successfully" }],
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
case "gtkx_take_screenshot": {
|
|
392
|
-
const input = TakeScreenshotInputSchema.parse(args);
|
|
393
|
-
const result = await connectionManager.sendToApp<{ data: string; mimeType: string }>(
|
|
394
|
-
input.appId,
|
|
395
|
-
"widget.screenshot",
|
|
396
|
-
{
|
|
397
|
-
windowId: input.windowId,
|
|
398
|
-
},
|
|
399
|
-
);
|
|
400
|
-
return {
|
|
401
|
-
content: [
|
|
402
|
-
{
|
|
403
|
-
type: "image",
|
|
404
|
-
data: result.data,
|
|
405
|
-
mimeType: result.mimeType,
|
|
406
|
-
},
|
|
407
|
-
],
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
default:
|
|
412
|
-
return {
|
|
413
|
-
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
414
|
-
isError: true,
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
} catch (error) {
|
|
418
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
419
|
-
return {
|
|
420
|
-
content: [{ type: "text", text: message }],
|
|
421
|
-
isError: true,
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
const transport = new StdioServerTransport();
|
|
427
|
-
await server.connect(transport);
|
|
428
|
-
|
|
429
|
-
let isShuttingDown = false;
|
|
430
|
-
const shutdown = async () => {
|
|
431
|
-
if (isShuttingDown) return;
|
|
432
|
-
isShuttingDown = true;
|
|
433
|
-
try {
|
|
434
|
-
connectionManager.cleanup();
|
|
435
|
-
await socketServer.stop();
|
|
436
|
-
await server.close();
|
|
437
|
-
} finally {
|
|
438
|
-
process.exit(0);
|
|
439
|
-
}
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
process.on("SIGINT", shutdown);
|
|
443
|
-
process.on("SIGTERM", shutdown);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
main().catch((error) => {
|
|
447
|
-
console.error("[gtkx] Fatal error:", error);
|
|
448
|
-
process.exit(1);
|
|
449
|
-
});
|