@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
@@ -1,59 +1,50 @@
1
- import EventEmitter from "node:events";
2
1
  import * as fs from "node:fs";
3
2
  import * as net from "node:net";
4
- import { invalidRequestError } from "./protocol/errors.js";
5
- import { DEFAULT_SOCKET_PATH, IpcRequestSchema, IpcResponseSchema, } from "./protocol/types.js";
6
- /**
7
- * Unix domain socket server for MCP communication.
8
- *
9
- * Manages connections from GTKX applications and handles IPC messaging.
10
- */
11
- export class SocketServer extends EventEmitter {
3
+ import { DEFAULT_SOCKET_PATH } from "./protocol/schemas.js";
4
+ const isSocketLive = (socketPath) => new Promise((resolve) => {
5
+ const probe = net.connect(socketPath);
6
+ probe.once("connect", () => {
7
+ probe.destroy();
8
+ resolve(true);
9
+ });
10
+ probe.once("error", () => resolve(false));
11
+ });
12
+ export class SocketServer {
12
13
  server = null;
13
- connections = new Map();
14
14
  socketPath;
15
- constructor(socketPath = DEFAULT_SOCKET_PATH) {
16
- super();
15
+ registry;
16
+ constructor(registry, socketPath = DEFAULT_SOCKET_PATH) {
17
+ this.registry = registry;
17
18
  this.socketPath = socketPath;
18
19
  }
19
- get path() {
20
- return this.socketPath;
21
- }
22
- get isListening() {
23
- return this.server?.listening ?? false;
24
- }
25
- getConnections() {
26
- return Array.from(this.connections.values());
27
- }
28
- getConnection(id) {
29
- return this.connections.get(id);
30
- }
31
20
  async start() {
32
- if (this.server) {
21
+ if (this.server)
33
22
  return;
34
- }
35
23
  if (fs.existsSync(this.socketPath)) {
24
+ if (await isSocketLive(this.socketPath)) {
25
+ throw new Error(`Another GTKX MCP server already owns ${this.socketPath}. ` +
26
+ "Stop the other server (for example, the gtkx MCP server of another active session) and reconnect.");
27
+ }
36
28
  fs.unlinkSync(this.socketPath);
37
29
  }
38
30
  return new Promise((resolve, reject) => {
39
- this.server = net.createServer((socket) => this.handleConnection(socket));
31
+ this.server = net.createServer((socket) => this.registry.register(socket));
32
+ let listening = false;
40
33
  this.server.on("error", (error) => {
41
- this.emit("error", error);
42
- reject(error);
34
+ this.registry.emit("error", error);
35
+ if (!listening)
36
+ reject(error);
43
37
  });
44
38
  this.server.listen(this.socketPath, () => {
39
+ listening = true;
45
40
  resolve();
46
41
  });
47
42
  });
48
43
  }
49
44
  async stop() {
50
- if (!this.server) {
45
+ if (!this.server)
51
46
  return;
52
- }
53
- for (const connection of this.connections.values()) {
54
- connection.socket.destroy();
55
- }
56
- this.connections.clear();
47
+ this.registry.dispose("Server stopping");
57
48
  return new Promise((resolve) => {
58
49
  this.server?.close(() => {
59
50
  this.server = null;
@@ -64,79 +55,5 @@ export class SocketServer extends EventEmitter {
64
55
  });
65
56
  });
66
57
  }
67
- send(connectionId, message) {
68
- const connection = this.connections.get(connectionId);
69
- if (!connection || !connection.socket.writable) {
70
- return false;
71
- }
72
- const data = `${JSON.stringify(message)}\n`;
73
- connection.socket.write(data);
74
- return true;
75
- }
76
- handleConnection(socket) {
77
- const connectionId = crypto.randomUUID();
78
- const connection = {
79
- id: connectionId,
80
- socket,
81
- buffer: "",
82
- };
83
- this.connections.set(connectionId, connection);
84
- this.emit("connection", connection);
85
- socket.on("data", (data) => this.handleData(connection, data));
86
- socket.on("close", () => {
87
- this.connections.delete(connectionId);
88
- this.emit("disconnection", connection);
89
- });
90
- socket.on("error", (error) => {
91
- this.emit("error", error);
92
- });
93
- }
94
- handleData(connection, data) {
95
- connection.buffer += data.toString();
96
- let newlineIndex = connection.buffer.indexOf("\n");
97
- while (newlineIndex !== -1) {
98
- const line = connection.buffer.slice(0, newlineIndex);
99
- connection.buffer = connection.buffer.slice(newlineIndex + 1);
100
- if (line.trim()) {
101
- this.processMessage(connection, line);
102
- }
103
- newlineIndex = connection.buffer.indexOf("\n");
104
- }
105
- }
106
- processMessage(connection, line) {
107
- let parsed;
108
- try {
109
- parsed = JSON.parse(line);
110
- }
111
- catch {
112
- const response = {
113
- id: "unknown",
114
- error: invalidRequestError("Invalid JSON").toIpcError(),
115
- };
116
- this.send(connection.id, response);
117
- return;
118
- }
119
- const message = parsed;
120
- const hasMethod = typeof message.method === "string";
121
- if (hasMethod) {
122
- const requestResult = IpcRequestSchema.safeParse(parsed);
123
- if (requestResult.success) {
124
- this.emit("request", connection, requestResult.data);
125
- return;
126
- }
127
- }
128
- else {
129
- const responseResult = IpcResponseSchema.safeParse(parsed);
130
- if (responseResult.success) {
131
- this.emit("response", connection, responseResult.data);
132
- return;
133
- }
134
- }
135
- const response = {
136
- id: message.id ?? "unknown",
137
- error: invalidRequestError("Invalid message format").toIpcError(),
138
- };
139
- this.send(connection.id, response);
140
- }
141
58
  }
142
59
  //# sourceMappingURL=socket-server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"socket-server.js","sourceRoot":"","sources":["../src/socket-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"socket-server.js","sourceRoot":"","sources":["../src/socket-server.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as net from \"node:net\";\nimport type { ConnectionRegistry } from \"./connection-registry.js\";\nimport { DEFAULT_SOCKET_PATH } from \"./protocol/schemas.js\";\n\nconst isSocketLive = (socketPath: string): Promise<boolean> =>\n new Promise((resolve) => {\n const probe = net.connect(socketPath);\n probe.once(\"connect\", () => {\n probe.destroy();\n resolve(true);\n });\n probe.once(\"error\", () => resolve(false));\n });\n\nexport class SocketServer {\n private server: net.Server | null = null;\n private socketPath: string;\n private registry: ConnectionRegistry;\n\n constructor(registry: ConnectionRegistry, socketPath: string = DEFAULT_SOCKET_PATH) {\n this.registry = registry;\n this.socketPath = socketPath;\n }\n\n async start(): Promise<void> {\n if (this.server) return;\n\n if (fs.existsSync(this.socketPath)) {\n if (await isSocketLive(this.socketPath)) {\n throw new Error(\n `Another GTKX MCP server already owns ${this.socketPath}. ` +\n \"Stop the other server (for example, the gtkx MCP server of another active session) and reconnect.\",\n );\n }\n fs.unlinkSync(this.socketPath);\n }\n\n return new Promise((resolve, reject) => {\n this.server = net.createServer((socket) => this.registry.register(socket));\n\n let listening = false;\n this.server.on(\"error\", (error) => {\n this.registry.emit(\"error\", error);\n if (!listening) reject(error);\n });\n\n this.server.listen(this.socketPath, () => {\n listening = true;\n resolve();\n });\n });\n }\n\n async stop(): Promise<void> {\n if (!this.server) return;\n\n this.registry.dispose(\"Server stopping\");\n\n return new Promise((resolve) => {\n this.server?.close(() => {\n this.server = null;\n if (fs.existsSync(this.socketPath)) {\n fs.unlinkSync(this.socketPath);\n }\n resolve();\n });\n });\n }\n}\n"]}
package/dist/tool.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
+ import type { z } from "zod";
4
+ export declare const textContent: (text: string) => CallToolResult;
5
+ export declare const textError: (text: string) => CallToolResult;
6
+ export declare const imageContent: (data: string, mimeType: string) => CallToolResult;
7
+ export type ToolArgs<Shape extends Record<string, z.ZodType>> = {
8
+ [K in keyof Shape]: z.output<Shape[K]>;
9
+ };
10
+ type ToolKind = "readOnly" | "action";
11
+ export type Tool<Shape extends Record<string, z.ZodType> = Record<string, z.ZodType>> = {
12
+ name: string;
13
+ title: string;
14
+ kind: ToolKind;
15
+ description: string;
16
+ inputSchema: Shape;
17
+ handler: (args: ToolArgs<Shape>) => Promise<CallToolResult>;
18
+ };
19
+ export declare const defineTool: <Shape extends Record<string, z.ZodType>>(tool: Tool<Shape>) => Tool;
20
+ export declare const registerTool: (server: McpServer, tool: Tool) => void;
21
+ export {};
22
+ //# sourceMappingURL=tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAgB,MAAM,yCAAyC,CAAC;AACvF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAG7B,eAAO,MAAM,WAAW,SAAU,MAAM,KAAG,cAAyD,CAAC;AAErG,eAAO,MAAM,SAAS,SAAU,MAAM,KAAG,cAGvC,CAAC;AAEH,eAAO,MAAM,YAAY,SAAU,MAAM,YAAY,MAAM,KAAG,cAE5D,CAAC;AAEH,MAAM,MAAM,QAAQ,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC;AAE3G,KAAK,QAAQ,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEtC,MAAM,MAAM,IAAI,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI;IACpF,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,KAAK,CAAC;IACnB,OAAO,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;CAC/D,CAAC;AAmBF,eAAO,MAAM,UAAU,GAAI,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAG,IAAoB,CAAC;AAE7G,eAAO,MAAM,YAAY,WAAY,SAAS,QAAQ,IAAI,KAAG,IAiB5D,CAAC"}
package/dist/tool.js ADDED
@@ -0,0 +1,36 @@
1
+ import { ProtocolError } from "./protocol/errors.js";
2
+ export const textContent = (text) => ({ content: [{ type: "text", text }] });
3
+ export const textError = (text) => ({
4
+ content: [{ type: "text", text }],
5
+ isError: true,
6
+ });
7
+ export const imageContent = (data, mimeType) => ({
8
+ content: [{ type: "image", data, mimeType }],
9
+ });
10
+ const hasStringHint = (data) => typeof data === "object" && data !== null && "hint" in data && typeof data.hint === "string";
11
+ const runTool = async (handler, args) => {
12
+ try {
13
+ return await handler(args);
14
+ }
15
+ catch (error) {
16
+ if (error instanceof ProtocolError) {
17
+ return textError(hasStringHint(error.data) ? `${error.message}\n${error.data.hint}` : error.message);
18
+ }
19
+ return textError(error instanceof Error ? error.message : String(error));
20
+ }
21
+ };
22
+ export const defineTool = (tool) => tool;
23
+ export const registerTool = (server, tool) => {
24
+ const callback = ((args, _extra) => runTool(tool.handler, args));
25
+ server.registerTool(tool.name, {
26
+ description: tool.description,
27
+ inputSchema: tool.inputSchema,
28
+ annotations: {
29
+ title: tool.title,
30
+ readOnlyHint: tool.kind === "readOnly",
31
+ destructiveHint: tool.kind === "action",
32
+ openWorldHint: true,
33
+ },
34
+ }, callback);
35
+ };
36
+ //# sourceMappingURL=tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAkB,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;AAErG,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAkB,EAAE,CAAC,CAAC;IACxD,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACjC,OAAO,EAAE,IAAI;CAChB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,QAAgB,EAAkB,EAAE,CAAC,CAAC;IAC7E,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;CAC/C,CAAC,CAAC;AAeH,MAAM,aAAa,GAAG,CAAC,IAAa,EAA4B,EAAE,CAC9D,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC;AAEjG,MAAM,OAAO,GAAG,KAAK,EACjB,OAA+E,EAC/E,IAAyC,EAClB,EAAE;IACzB,IAAI,CAAC;QACD,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;YACjC,OAAO,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACzG,CAAC;QACD,OAAO,SAAS,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7E,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAA0C,IAAiB,EAAQ,EAAE,CAAC,IAAY,CAAC;AAE7G,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAiB,EAAE,IAAU,EAAQ,EAAE;IAChE,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAyC,EAAE,MAAe,EAAE,EAAE,CAC7E,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAA4C,CAAC;IAC5E,MAAM,CAAC,YAAY,CACf,IAAI,CAAC,IAAI,EACT;QACI,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE;YACT,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,YAAY,EAAE,IAAI,CAAC,IAAI,KAAK,UAAU;YACtC,eAAe,EAAE,IAAI,CAAC,IAAI,KAAK,QAAQ;YACvC,aAAa,EAAE,IAAI;SACtB;KACJ,EACD,QAAQ,CACX,CAAC;AACN,CAAC,CAAC","sourcesContent":["import type { McpServer, ToolCallback } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { z } from \"zod\";\nimport { ProtocolError } from \"./protocol/errors.js\";\n\nexport const textContent = (text: string): CallToolResult => ({ content: [{ type: \"text\", text }] });\n\nexport const textError = (text: string): CallToolResult => ({\n content: [{ type: \"text\", text }],\n isError: true,\n});\n\nexport const imageContent = (data: string, mimeType: string): CallToolResult => ({\n content: [{ type: \"image\", data, mimeType }],\n});\n\nexport type ToolArgs<Shape extends Record<string, z.ZodType>> = { [K in keyof Shape]: z.output<Shape[K]> };\n\ntype ToolKind = \"readOnly\" | \"action\";\n\nexport type Tool<Shape extends Record<string, z.ZodType> = Record<string, z.ZodType>> = {\n name: string;\n title: string;\n kind: ToolKind;\n description: string;\n inputSchema: Shape;\n handler: (args: ToolArgs<Shape>) => Promise<CallToolResult>;\n};\n\nconst hasStringHint = (data: unknown): data is { hint: string } =>\n typeof data === \"object\" && data !== null && \"hint\" in data && typeof data.hint === \"string\";\n\nconst runTool = async (\n handler: (args: ToolArgs<Record<string, z.ZodType>>) => Promise<CallToolResult>,\n args: ToolArgs<Record<string, z.ZodType>>,\n): Promise<CallToolResult> => {\n try {\n return await handler(args);\n } catch (error) {\n if (error instanceof ProtocolError) {\n return textError(hasStringHint(error.data) ? `${error.message}\\n${error.data.hint}` : error.message);\n }\n return textError(error instanceof Error ? error.message : String(error));\n }\n};\n\nexport const defineTool = <Shape extends Record<string, z.ZodType>>(tool: Tool<Shape>): Tool => tool as Tool;\n\nexport const registerTool = (server: McpServer, tool: Tool): void => {\n const callback = ((args: ToolArgs<Record<string, z.ZodType>>, _extra: unknown) =>\n runTool(tool.handler, args)) as ToolCallback<Record<string, z.ZodType>>;\n server.registerTool(\n tool.name,\n {\n description: tool.description,\n inputSchema: tool.inputSchema,\n annotations: {\n title: tool.title,\n readOnlyHint: tool.kind === \"readOnly\",\n destructiveHint: tool.kind === \"action\",\n openWorldHint: true,\n },\n },\n callback,\n );\n};\n"]}
@@ -0,0 +1,41 @@
1
+ import EventEmitter from "node:events";
2
+ import type { Socket } from "node:net";
3
+ import type { Duplex } from "node:stream";
4
+ import { ProtocolError } from "./protocol/errors.js";
5
+ import { type Message, type Request } from "./protocol/schemas.js";
6
+ export type ProtocolConnectionEvents = {
7
+ request: [Request];
8
+ invalid: [{
9
+ id: string;
10
+ error: ProtocolError;
11
+ }];
12
+ };
13
+ export declare class ConnectionClosedError extends Error {
14
+ constructor();
15
+ }
16
+ export declare class ProtocolConnection extends EventEmitter<ProtocolConnectionEvents> {
17
+ id: string;
18
+ private buffer;
19
+ private pending;
20
+ private writer;
21
+ constructor(writer: Duplex);
22
+ feed(data: Buffer | string): void;
23
+ write(message: Message): void;
24
+ static fromSocket(socket: Socket, options?: {
25
+ onClose?: () => void;
26
+ onError?: (error: Error) => void;
27
+ }): ProtocolConnection;
28
+ send<T = unknown>(method: string, params: unknown, timeout: number): Promise<T>;
29
+ rejectPending(error: Error): void;
30
+ private processLine;
31
+ private handleResponse;
32
+ }
33
+ export type AppConnectionEvents = {
34
+ disconnection: [ProtocolConnection];
35
+ request: [ProtocolConnection, Request];
36
+ error: [Error];
37
+ };
38
+ export interface AppConnections extends EventEmitter<AppConnectionEvents> {
39
+ send(connectionId: string, message: Message): void;
40
+ }
41
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAA+C,aAAa,EAAuB,MAAM,sBAAsB,CAAC;AACvH,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAgD,MAAM,uBAAuB,CAAC;AAEjH,MAAM,MAAM,wBAAwB,GAAG;IACnC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC;IACnB,OAAO,EAAE,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAE,CAAC,CAAC;CACnD,CAAC;AAQF,qBAAa,qBAAsB,SAAQ,KAAK;IAC5C,cAGC;CACJ;AAED,qBAAa,kBAAmB,SAAQ,YAAY,CAAC,wBAAwB,CAAC;IAC1E,EAAE,EAAE,MAAM,CAAuB;IACjC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,OAAO,CAA0C;IACzD,OAAO,CAAC,MAAM,CAAS;IAEvB,YAAY,MAAM,EAAE,MAAM,EAGzB;IAED,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAahC;IAED,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAG5B;IAED,MAAM,CAAC,UAAU,CACb,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;QACL,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;QACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;KAC/B,GACP,kBAAkB,CAWpB;IAED,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CA0B9E;IAED,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAMhC;IAED,OAAO,CAAC,WAAW;IA4BnB,OAAO,CAAC,cAAc;CAgBzB;AAED,MAAM,MAAM,mBAAmB,GAAG;IAC9B,aAAa,EAAE,CAAC,kBAAkB,CAAC,CAAC;IACpC,OAAO,EAAE,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;IACvC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;CAClB,CAAC;AAEF,MAAM,WAAW,cAAe,SAAQ,YAAY,CAAC,mBAAmB,CAAC;IACrE,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CACtD"}
@@ -0,0 +1,121 @@
1
+ import EventEmitter from "node:events";
2
+ import { ErrorCode, invalidRequestError, isErrorCode, ProtocolError, requestTimeoutError } from "./protocol/errors.js";
3
+ import { RequestSchema, ResponseSchema } from "./protocol/schemas.js";
4
+ export class ConnectionClosedError extends Error {
5
+ constructor() {
6
+ super("Connection stream is not writable");
7
+ this.name = "ConnectionClosedError";
8
+ }
9
+ }
10
+ export class ProtocolConnection extends EventEmitter {
11
+ id = crypto.randomUUID();
12
+ buffer = "";
13
+ pending = new Map();
14
+ writer;
15
+ constructor(writer) {
16
+ super();
17
+ this.writer = writer;
18
+ }
19
+ feed(data) {
20
+ this.buffer += typeof data === "string" ? data : data.toString();
21
+ let newlineIndex = this.buffer.indexOf("\n");
22
+ while (newlineIndex !== -1) {
23
+ const line = this.buffer.slice(0, newlineIndex);
24
+ this.buffer = this.buffer.slice(newlineIndex + 1);
25
+ if (line.trim()) {
26
+ this.processLine(line);
27
+ }
28
+ newlineIndex = this.buffer.indexOf("\n");
29
+ }
30
+ }
31
+ write(message) {
32
+ if (!this.writer.writable)
33
+ return;
34
+ this.writer.write(`${JSON.stringify(message)}\n`);
35
+ }
36
+ static fromSocket(socket, options = {}) {
37
+ const connection = new ProtocolConnection(socket);
38
+ socket.on("data", (data) => connection.feed(data));
39
+ socket.on("close", () => {
40
+ connection.rejectPending(new Error("Connection closed"));
41
+ options.onClose?.();
42
+ });
43
+ if (options.onError) {
44
+ socket.on("error", options.onError);
45
+ }
46
+ return connection;
47
+ }
48
+ send(method, params, timeout) {
49
+ return new Promise((resolve, reject) => {
50
+ if (!this.writer.writable) {
51
+ reject(new ConnectionClosedError());
52
+ return;
53
+ }
54
+ const id = crypto.randomUUID();
55
+ const timeoutHandle = setTimeout(() => {
56
+ this.pending.delete(id);
57
+ reject(requestTimeoutError(timeout));
58
+ }, timeout);
59
+ this.pending.set(id, {
60
+ resolve: resolve,
61
+ reject,
62
+ timeout: timeoutHandle,
63
+ });
64
+ this.write({ id, method, params });
65
+ if (!this.writer.writable) {
66
+ clearTimeout(timeoutHandle);
67
+ this.pending.delete(id);
68
+ reject(new ConnectionClosedError());
69
+ }
70
+ });
71
+ }
72
+ rejectPending(error) {
73
+ for (const entry of this.pending.values()) {
74
+ clearTimeout(entry.timeout);
75
+ entry.reject(error);
76
+ }
77
+ this.pending.clear();
78
+ }
79
+ processLine(line) {
80
+ let parsed;
81
+ try {
82
+ parsed = JSON.parse(line);
83
+ }
84
+ catch {
85
+ this.emit("invalid", { id: "unknown", error: invalidRequestError("Invalid JSON") });
86
+ return;
87
+ }
88
+ const message = parsed;
89
+ if (typeof message.method === "string") {
90
+ const requestResult = RequestSchema.safeParse(parsed);
91
+ if (requestResult.success) {
92
+ this.emit("request", requestResult.data);
93
+ return;
94
+ }
95
+ }
96
+ else {
97
+ const responseResult = ResponseSchema.safeParse(parsed);
98
+ if (responseResult.success) {
99
+ this.handleResponse(responseResult.data);
100
+ return;
101
+ }
102
+ }
103
+ const id = typeof message.id === "string" ? message.id : "unknown";
104
+ this.emit("invalid", { id, error: invalidRequestError("Invalid message format") });
105
+ }
106
+ handleResponse(response) {
107
+ const entry = this.pending.get(response.id);
108
+ if (!entry)
109
+ return;
110
+ clearTimeout(entry.timeout);
111
+ this.pending.delete(response.id);
112
+ if (response.error) {
113
+ const err = response.error;
114
+ entry.reject(new ProtocolError(isErrorCode(err.code) ? err.code : ErrorCode.INTERNAL_ERROR, err.message, err.data));
115
+ }
116
+ else {
117
+ entry.resolve(response.result);
118
+ }
119
+ }
120
+ }
121
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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","sourcesContent":["import EventEmitter from \"node:events\";\nimport type { Socket } from \"node:net\";\nimport type { Duplex } from \"node:stream\";\nimport { ErrorCode, invalidRequestError, isErrorCode, ProtocolError, requestTimeoutError } from \"./protocol/errors.js\";\nimport { type Message, type Request, RequestSchema, type Response, ResponseSchema } from \"./protocol/schemas.js\";\n\nexport type ProtocolConnectionEvents = {\n request: [Request];\n invalid: [{ id: string; error: ProtocolError }];\n};\n\ntype PendingRequest = {\n resolve: (result: unknown) => void;\n reject: (error: Error) => void;\n timeout: NodeJS.Timeout;\n};\n\nexport class ConnectionClosedError extends Error {\n constructor() {\n super(\"Connection stream is not writable\");\n this.name = \"ConnectionClosedError\";\n }\n}\n\nexport class ProtocolConnection extends EventEmitter<ProtocolConnectionEvents> {\n id: string = crypto.randomUUID();\n private buffer = \"\";\n private pending: Map<string, PendingRequest> = new Map();\n private writer: Duplex;\n\n constructor(writer: Duplex) {\n super();\n this.writer = writer;\n }\n\n feed(data: Buffer | string): void {\n this.buffer += typeof data === \"string\" ? data : data.toString();\n\n let newlineIndex = this.buffer.indexOf(\"\\n\");\n while (newlineIndex !== -1) {\n const line = this.buffer.slice(0, newlineIndex);\n this.buffer = this.buffer.slice(newlineIndex + 1);\n\n if (line.trim()) {\n this.processLine(line);\n }\n newlineIndex = this.buffer.indexOf(\"\\n\");\n }\n }\n\n write(message: Message): void {\n if (!this.writer.writable) return;\n this.writer.write(`${JSON.stringify(message)}\\n`);\n }\n\n static fromSocket(\n socket: Socket,\n options: {\n onClose?: () => void;\n onError?: (error: Error) => void;\n } = {},\n ): ProtocolConnection {\n const connection = new ProtocolConnection(socket);\n socket.on(\"data\", (data: Buffer) => connection.feed(data));\n socket.on(\"close\", () => {\n connection.rejectPending(new Error(\"Connection closed\"));\n options.onClose?.();\n });\n if (options.onError) {\n socket.on(\"error\", options.onError);\n }\n return connection;\n }\n\n send<T = unknown>(method: string, params: unknown, timeout: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n if (!this.writer.writable) {\n reject(new ConnectionClosedError());\n return;\n }\n\n const id = crypto.randomUUID();\n const timeoutHandle = setTimeout(() => {\n this.pending.delete(id);\n reject(requestTimeoutError(timeout));\n }, timeout);\n\n this.pending.set(id, {\n resolve: resolve as (result: unknown) => void,\n reject,\n timeout: timeoutHandle,\n });\n\n this.write({ id, method, params });\n if (!this.writer.writable) {\n clearTimeout(timeoutHandle);\n this.pending.delete(id);\n reject(new ConnectionClosedError());\n }\n });\n }\n\n rejectPending(error: Error): void {\n for (const entry of this.pending.values()) {\n clearTimeout(entry.timeout);\n entry.reject(error);\n }\n this.pending.clear();\n }\n\n private processLine(line: string): void {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n this.emit(\"invalid\", { id: \"unknown\", error: invalidRequestError(\"Invalid JSON\") });\n return;\n }\n\n const message = parsed as Record<string, unknown>;\n if (typeof message.method === \"string\") {\n const requestResult = RequestSchema.safeParse(parsed);\n if (requestResult.success) {\n this.emit(\"request\", requestResult.data);\n return;\n }\n } else {\n const responseResult = ResponseSchema.safeParse(parsed);\n if (responseResult.success) {\n this.handleResponse(responseResult.data);\n return;\n }\n }\n\n const id = typeof message.id === \"string\" ? message.id : \"unknown\";\n this.emit(\"invalid\", { id, error: invalidRequestError(\"Invalid message format\") });\n }\n\n private handleResponse(response: Response): void {\n const entry = this.pending.get(response.id);\n if (!entry) return;\n\n clearTimeout(entry.timeout);\n this.pending.delete(response.id);\n\n if (response.error) {\n const err = response.error;\n entry.reject(\n new ProtocolError(isErrorCode(err.code) ? err.code : ErrorCode.INTERNAL_ERROR, err.message, err.data),\n );\n } else {\n entry.resolve(response.result);\n }\n }\n}\n\nexport type AppConnectionEvents = {\n disconnection: [ProtocolConnection];\n request: [ProtocolConnection, Request];\n error: [Error];\n};\n\nexport interface AppConnections extends EventEmitter<AppConnectionEvents> {\n send(connectionId: string, message: Message): void;\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gtkx/mcp",
3
- "version": "0.20.0",
4
- "description": "MCP server for AI-powered interaction with GTKX applications",
3
+ "version": "1.0.0-rc.1",
4
+ "description": "Model Context Protocol server that gives an agent the GTKX API reference and control of a running application",
5
5
  "keywords": [
6
6
  "gtkx",
7
7
  "gtk",
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "repository": {
21
21
  "type": "git",
22
- "url": "https://github.com/gtkx-org/gtkx.git",
22
+ "url": "git+https://github.com/gtkx-org/gtkx.git",
23
23
  "directory": "packages/mcp"
24
24
  },
25
25
  "license": "MPL-2.0",
@@ -27,9 +27,9 @@
27
27
  "type": "module",
28
28
  "exports": {
29
29
  "./package.json": "./package.json",
30
- ".": {
31
- "types": "./dist/index.d.ts",
32
- "default": "./dist/index.js"
30
+ "./internal": {
31
+ "types": "./dist/internal.d.ts",
32
+ "default": "./dist/internal.js"
33
33
  }
34
34
  },
35
35
  "bin": {
@@ -41,13 +41,19 @@
41
41
  "dist",
42
42
  "src"
43
43
  ],
44
+ "engines": {
45
+ "node": ">=24"
46
+ },
44
47
  "dependencies": {
45
- "@modelcontextprotocol/sdk": "^1.26.0",
46
- "zod": "^4.3.6"
48
+ "@modelcontextprotocol/sdk": "^1.29.0",
49
+ "zod": "^4.4.3",
50
+ "@gtkx/codegen": "1.0.0-rc.1",
51
+ "@gtkx/config": "1.0.0-rc.1",
52
+ "@gtkx/utils": "1.0.0-rc.1"
47
53
  },
48
54
  "scripts": {
49
- "build": "tsc -b && cp ../../README.md .",
50
- "test": "vitest run",
51
- "typecheck": "tsc -b --emitDeclarationOnly"
55
+ "build": "tsc -b tsconfig.lib.json",
56
+ "typecheck": "tsc -b --emitDeclarationOnly",
57
+ "release": "tsx ../../scripts/release-package.ts"
52
58
  }
53
59
  }