webclaw-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/dist/__tests__/cli-startup.test.d.ts +2 -0
  3. package/dist/__tests__/cli-startup.test.d.ts.map +1 -0
  4. package/dist/__tests__/cli-startup.test.js +60 -0
  5. package/dist/__tests__/cli-startup.test.js.map +1 -0
  6. package/dist/__tests__/mcp-protocol-integration.test.d.ts +2 -0
  7. package/dist/__tests__/mcp-protocol-integration.test.d.ts.map +1 -0
  8. package/dist/__tests__/mcp-protocol-integration.test.js +223 -0
  9. package/dist/__tests__/mcp-protocol-integration.test.js.map +1 -0
  10. package/dist/__tests__/mcp-stdio-integration.test.d.ts +2 -0
  11. package/dist/__tests__/mcp-stdio-integration.test.d.ts.map +1 -0
  12. package/dist/__tests__/mcp-stdio-integration.test.js +168 -0
  13. package/dist/__tests__/mcp-stdio-integration.test.js.map +1 -0
  14. package/dist/__tests__/native-messaging-client.test.d.ts +2 -0
  15. package/dist/__tests__/native-messaging-client.test.d.ts.map +1 -0
  16. package/dist/__tests__/native-messaging-client.test.js +196 -0
  17. package/dist/__tests__/native-messaging-client.test.js.map +1 -0
  18. package/dist/__tests__/native-messaging-e2e.test.d.ts +2 -0
  19. package/dist/__tests__/native-messaging-e2e.test.d.ts.map +1 -0
  20. package/dist/__tests__/native-messaging-e2e.test.js +280 -0
  21. package/dist/__tests__/native-messaging-e2e.test.js.map +1 -0
  22. package/dist/__tests__/server.test.d.ts +2 -0
  23. package/dist/__tests__/server.test.d.ts.map +1 -0
  24. package/dist/__tests__/server.test.js +85 -0
  25. package/dist/__tests__/server.test.js.map +1 -0
  26. package/dist/cli.d.ts +3 -0
  27. package/dist/cli.d.ts.map +1 -0
  28. package/dist/cli.js +47 -0
  29. package/dist/cli.js.map +1 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +2 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/installer.d.ts +2 -0
  35. package/dist/installer.d.ts.map +1 -0
  36. package/dist/installer.js +109 -0
  37. package/dist/installer.js.map +1 -0
  38. package/dist/native-messaging-client.d.ts +29 -0
  39. package/dist/native-messaging-client.d.ts.map +1 -0
  40. package/dist/native-messaging-client.js +95 -0
  41. package/dist/native-messaging-client.js.map +1 -0
  42. package/dist/server.d.ts +12 -0
  43. package/dist/server.d.ts.map +1 -0
  44. package/dist/server.js +194 -0
  45. package/dist/server.js.map +1 -0
  46. package/package.json +54 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 kuroko1t
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli-startup.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-startup.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cli-startup.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,60 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { spawn } from 'node:child_process';
3
+ import { resolve, dirname } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const cliPath = resolve(__dirname, '../../dist/cli.js');
7
+ describe('MCP Server stdio startup', () => {
8
+ it('starts and can be terminated cleanly', async () => {
9
+ const child = spawn('node', [cliPath], {
10
+ stdio: ['pipe', 'pipe', 'pipe'],
11
+ timeout: 10000,
12
+ });
13
+ let stderr = '';
14
+ // Wait for the startup message or timeout
15
+ await new Promise((resolve) => {
16
+ const timeout = setTimeout(() => resolve(), 5000);
17
+ child.stderr?.on('data', (chunk) => {
18
+ stderr += chunk.toString();
19
+ if (stderr.includes('MCP Server started')) {
20
+ clearTimeout(timeout);
21
+ resolve();
22
+ }
23
+ });
24
+ });
25
+ // Process should still be running
26
+ expect(child.exitCode).toBeNull();
27
+ // Kill it
28
+ child.kill('SIGTERM');
29
+ const exitCode = await new Promise((resolve) => {
30
+ child.on('exit', (code) => resolve(code));
31
+ setTimeout(() => resolve(null), 3000);
32
+ });
33
+ // Should have started (stderr contains startup message)
34
+ expect(stderr).toContain('MCP Server started');
35
+ });
36
+ it('shows help with --help flag', async () => {
37
+ const child = spawn('node', [cliPath, '--help'], {
38
+ stdio: ['pipe', 'pipe', 'pipe'],
39
+ timeout: 5000,
40
+ });
41
+ let stdout = '';
42
+ let stderr = '';
43
+ child.stdout?.on('data', (chunk) => {
44
+ stdout += chunk.toString();
45
+ });
46
+ child.stderr?.on('data', (chunk) => {
47
+ stderr += chunk.toString();
48
+ });
49
+ const exitCode = await new Promise((resolve) => {
50
+ child.on('exit', (code) => resolve(code));
51
+ setTimeout(() => {
52
+ child.kill();
53
+ resolve(null);
54
+ }, 3000);
55
+ });
56
+ const output = stdout + stderr;
57
+ expect(output).toContain('webclaw');
58
+ });
59
+ });
60
+ //# sourceMappingURL=cli-startup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-startup.test.js","sourceRoot":"","sources":["../../src/__tests__/cli-startup.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mcp-protocol-integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-protocol-integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/mcp-protocol-integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * MCP Protocol in-process integration tests.
3
+ *
4
+ * Uses MCP SDK Client + InMemoryTransport to perform a real protocol
5
+ * handshake and tool invocations against the actual server, with a
6
+ * mocked NativeMessagingClient.
7
+ */
8
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
9
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
10
+ import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
11
+ import { PassThrough } from 'node:stream';
12
+ import { createWebClawServer } from '../server.js';
13
+ import { NativeMessagingClient } from '../native-messaging-client.js';
14
+ /** Helper: encode a native-messaging–format response and push it to the stdin PassThrough. */
15
+ function sendNativeResponse(stdin, id, method, payload) {
16
+ const msg = JSON.stringify({ id, type: 'response', method, payload, timestamp: Date.now() });
17
+ const body = Buffer.from(msg, 'utf-8');
18
+ const header = Buffer.alloc(4);
19
+ header.writeUInt32LE(body.length, 0);
20
+ stdin.write(Buffer.concat([header, body]));
21
+ }
22
+ function createMockNativeClient() {
23
+ const stdin = new PassThrough();
24
+ const stdout = new PassThrough();
25
+ const client = new NativeMessagingClient({ stdin, stdout });
26
+ return { client, stdin, stdout };
27
+ }
28
+ /** Decode outgoing native-messaging messages captured from stdout. */
29
+ function decodeNativeMessages(buf) {
30
+ const messages = [];
31
+ let offset = 0;
32
+ while (offset + 4 <= buf.length) {
33
+ const len = buf.readUInt32LE(offset);
34
+ if (offset + 4 + len > buf.length)
35
+ break;
36
+ const data = buf.subarray(offset + 4, offset + 4 + len);
37
+ messages.push(JSON.parse(data.toString('utf-8')));
38
+ offset += 4 + len;
39
+ }
40
+ return messages;
41
+ }
42
+ const EXPECTED_TOOLS = [
43
+ 'navigate_to',
44
+ 'page_snapshot',
45
+ 'click',
46
+ 'type_text',
47
+ 'select_option',
48
+ 'list_webmcp_tools',
49
+ 'invoke_webmcp_tool',
50
+ 'screenshot',
51
+ ];
52
+ describe('MCP Protocol integration (in-process)', () => {
53
+ let mcpClient;
54
+ let nativeStdin;
55
+ let nativeStdout;
56
+ let nativeClient;
57
+ beforeAll(async () => {
58
+ const mock = createMockNativeClient();
59
+ nativeStdin = mock.stdin;
60
+ nativeStdout = mock.stdout;
61
+ nativeClient = mock.client;
62
+ const server = createWebClawServer({ nativeClient });
63
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
64
+ mcpClient = new Client({ name: 'test-client', version: '0.0.1' });
65
+ await server.connect(serverTransport);
66
+ await mcpClient.connect(clientTransport);
67
+ });
68
+ afterAll(async () => {
69
+ await mcpClient.close();
70
+ nativeClient.disconnect();
71
+ });
72
+ // --- Handshake ---
73
+ it('completes initialize handshake and returns server info', () => {
74
+ const serverVersion = mcpClient.getServerVersion();
75
+ expect(serverVersion).toBeDefined();
76
+ expect(serverVersion.name).toBe('webclaw');
77
+ expect(serverVersion.version).toBe('0.1.0');
78
+ });
79
+ // --- tools/list ---
80
+ it('lists all 8 tools', async () => {
81
+ const result = await mcpClient.listTools();
82
+ expect(result.tools).toHaveLength(8);
83
+ const names = result.tools.map((t) => t.name).sort();
84
+ expect(names).toEqual([...EXPECTED_TOOLS].sort());
85
+ });
86
+ it('each tool has a non-empty description', async () => {
87
+ const result = await mcpClient.listTools();
88
+ for (const tool of result.tools) {
89
+ expect(tool.description).toBeTruthy();
90
+ }
91
+ });
92
+ // --- Input schema validation ---
93
+ it('navigate_to schema requires url string', async () => {
94
+ const { tools } = await mcpClient.listTools();
95
+ const nav = tools.find((t) => t.name === 'navigate_to');
96
+ expect(nav.inputSchema.properties).toHaveProperty('url');
97
+ expect(nav.inputSchema.required).toContain('url');
98
+ });
99
+ it('click schema requires ref with pattern and snapshotId', async () => {
100
+ const { tools } = await mcpClient.listTools();
101
+ const click = tools.find((t) => t.name === 'click');
102
+ expect(click.inputSchema.properties).toHaveProperty('ref');
103
+ expect(click.inputSchema.properties).toHaveProperty('snapshotId');
104
+ expect(click.inputSchema.required).toContain('ref');
105
+ expect(click.inputSchema.required).toContain('snapshotId');
106
+ });
107
+ it('type_text schema requires ref, text, snapshotId', async () => {
108
+ const { tools } = await mcpClient.listTools();
109
+ const tt = tools.find((t) => t.name === 'type_text');
110
+ expect(tt.inputSchema.required).toContain('ref');
111
+ expect(tt.inputSchema.required).toContain('text');
112
+ expect(tt.inputSchema.required).toContain('snapshotId');
113
+ });
114
+ it('select_option schema requires ref, value, snapshotId', async () => {
115
+ const { tools } = await mcpClient.listTools();
116
+ const so = tools.find((t) => t.name === 'select_option');
117
+ expect(so.inputSchema.required).toContain('ref');
118
+ expect(so.inputSchema.required).toContain('value');
119
+ expect(so.inputSchema.required).toContain('snapshotId');
120
+ });
121
+ it('screenshot schema has optional tabId only', async () => {
122
+ const { tools } = await mcpClient.listTools();
123
+ const ss = tools.find((t) => t.name === 'screenshot');
124
+ expect(ss.inputSchema.properties).toHaveProperty('tabId');
125
+ // tabId is optional, so required should be empty or not contain tabId
126
+ expect(ss.inputSchema.required ?? []).not.toContain('tabId');
127
+ });
128
+ // --- Validation errors ---
129
+ it('navigate_to rejects invalid URL', async () => {
130
+ const result = await mcpClient.callTool({
131
+ name: 'navigate_to',
132
+ arguments: { url: 'not-a-url' },
133
+ });
134
+ expect(result.isError).toBe(true);
135
+ });
136
+ it('click rejects invalid ref pattern', async () => {
137
+ const result = await mcpClient.callTool({
138
+ name: 'click',
139
+ arguments: { ref: 'bad-ref', snapshotId: 'snap-1' },
140
+ });
141
+ expect(result.isError).toBe(true);
142
+ });
143
+ // --- Tool invocation with mock NativeMessagingClient ---
144
+ it('navigate_to returns formatted response from native client', async () => {
145
+ // Capture outgoing request to respond to it
146
+ const chunks = [];
147
+ nativeStdout.on('data', (chunk) => chunks.push(chunk));
148
+ const toolPromise = mcpClient.callTool({
149
+ name: 'navigate_to',
150
+ arguments: { url: 'https://example.com' },
151
+ });
152
+ // Wait for the request to be sent through native messaging
153
+ await new Promise((r) => setTimeout(r, 50));
154
+ const combined = Buffer.concat(chunks);
155
+ const sent = decodeNativeMessages(combined);
156
+ const req = sent.find((m) => m.method === 'navigate');
157
+ expect(req).toBeDefined();
158
+ sendNativeResponse(nativeStdin, req.id, 'navigate', {
159
+ url: 'https://example.com',
160
+ title: 'Example Domain',
161
+ tabId: 1,
162
+ });
163
+ const result = await toolPromise;
164
+ expect(result.isError).toBeFalsy();
165
+ const text = result.content[0].text;
166
+ expect(text).toContain('Example Domain');
167
+ expect(text).toContain('https://example.com');
168
+ nativeStdout.removeAllListeners('data');
169
+ });
170
+ it('page_snapshot returns formatted snapshot from native client', async () => {
171
+ const chunks = [];
172
+ nativeStdout.on('data', (chunk) => chunks.push(chunk));
173
+ const toolPromise = mcpClient.callTool({
174
+ name: 'page_snapshot',
175
+ arguments: {},
176
+ });
177
+ await new Promise((r) => setTimeout(r, 50));
178
+ const combined = Buffer.concat(chunks);
179
+ const sent = decodeNativeMessages(combined);
180
+ const req = sent.find((m) => m.method === 'snapshot');
181
+ expect(req).toBeDefined();
182
+ sendNativeResponse(nativeStdin, req.id, 'snapshot', {
183
+ text: '[page "Test"]\n [button "Click"]',
184
+ snapshotId: 'snap-123',
185
+ url: 'https://example.com',
186
+ title: 'Test Page',
187
+ });
188
+ const result = await toolPromise;
189
+ expect(result.isError).toBeFalsy();
190
+ const text = result.content[0].text;
191
+ expect(text).toContain('Test Page');
192
+ expect(text).toContain('snap-123');
193
+ nativeStdout.removeAllListeners('data');
194
+ });
195
+ it('tool returning error response sets isError', async () => {
196
+ const chunks = [];
197
+ nativeStdout.on('data', (chunk) => chunks.push(chunk));
198
+ const toolPromise = mcpClient.callTool({
199
+ name: 'page_snapshot',
200
+ arguments: {},
201
+ });
202
+ await new Promise((r) => setTimeout(r, 50));
203
+ const combined = Buffer.concat(chunks);
204
+ const sent = decodeNativeMessages(combined);
205
+ const req = sent.find((m) => m.method === 'snapshot');
206
+ // Send an error response
207
+ const msg = JSON.stringify({
208
+ id: req.id,
209
+ type: 'error',
210
+ method: 'snapshot',
211
+ payload: { code: 'NO_TAB', message: 'No active tab' },
212
+ timestamp: Date.now(),
213
+ });
214
+ const body = Buffer.from(msg, 'utf-8');
215
+ const header = Buffer.alloc(4);
216
+ header.writeUInt32LE(body.length, 0);
217
+ nativeStdin.write(Buffer.concat([header, body]));
218
+ const result = await toolPromise;
219
+ expect(result.isError).toBe(true);
220
+ nativeStdout.removeAllListeners('data');
221
+ });
222
+ });
223
+ //# sourceMappingURL=mcp-protocol-integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-protocol-integration.test.js","sourceRoot":"","sources":["../../src/__tests__/mcp-protocol-integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mcp-stdio-integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-stdio-integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/mcp-stdio-integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * MCP Server stdio integration tests.
3
+ *
4
+ * Spawns `node dist/cli.js` as a child process and communicates
5
+ * via JSON-RPC over stdin/stdout using newline-delimited JSON (NDJSON),
6
+ * which is the framing format used by MCP SDK's StdioServerTransport.
7
+ */
8
+ import { describe, it, expect, afterEach } from 'vitest';
9
+ import { spawn } from 'node:child_process';
10
+ import { resolve, dirname } from 'node:path';
11
+ import { fileURLToPath } from 'node:url';
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ const cliPath = resolve(__dirname, '../../dist/cli.js');
14
+ let child = null;
15
+ /** Send a JSON-RPC message as NDJSON (newline-delimited JSON). */
16
+ function sendJsonRpc(proc, message) {
17
+ proc.stdin.write(JSON.stringify(message) + '\n');
18
+ }
19
+ /**
20
+ * Collect NDJSON responses from stdout.
21
+ * Each response is a single line of JSON terminated by \n.
22
+ */
23
+ function createResponseCollector(proc) {
24
+ const state = { responses: [] };
25
+ let buffer = '';
26
+ proc.stdout.on('data', (chunk) => {
27
+ buffer += chunk.toString();
28
+ const lines = buffer.split('\n');
29
+ // Keep the last (potentially incomplete) line in the buffer
30
+ buffer = lines.pop();
31
+ for (const line of lines) {
32
+ const trimmed = line.trim();
33
+ if (!trimmed)
34
+ continue;
35
+ try {
36
+ state.responses.push(JSON.parse(trimmed));
37
+ }
38
+ catch {
39
+ // skip malformed lines
40
+ }
41
+ }
42
+ });
43
+ return state;
44
+ }
45
+ afterEach(() => {
46
+ if (child && child.exitCode === null) {
47
+ child.kill('SIGTERM');
48
+ }
49
+ child = null;
50
+ });
51
+ describe('MCP Server stdio integration', () => {
52
+ it('responds to initialize request via JSON-RPC', async () => {
53
+ child = spawn('node', [cliPath], {
54
+ stdio: ['pipe', 'pipe', 'pipe'],
55
+ timeout: 15000,
56
+ });
57
+ const collector = createResponseCollector(child);
58
+ // Give the server time to start
59
+ await new Promise((r) => setTimeout(r, 1000));
60
+ sendJsonRpc(child, {
61
+ jsonrpc: '2.0',
62
+ id: 1,
63
+ method: 'initialize',
64
+ params: {
65
+ protocolVersion: '2024-11-05',
66
+ capabilities: {},
67
+ clientInfo: { name: 'test-stdio', version: '0.0.1' },
68
+ },
69
+ });
70
+ // Wait for response
71
+ await new Promise((r) => setTimeout(r, 2000));
72
+ expect(collector.responses.length).toBeGreaterThanOrEqual(1);
73
+ const initResponse = collector.responses.find((r) => r.id === 1 && r.result);
74
+ expect(initResponse).toBeDefined();
75
+ expect(initResponse.result.serverInfo.name).toBe('webclaw');
76
+ expect(initResponse.result.serverInfo.version).toBe('0.1.0');
77
+ }, 20000);
78
+ it('lists 8 tools via JSON-RPC after initialization', async () => {
79
+ child = spawn('node', [cliPath], {
80
+ stdio: ['pipe', 'pipe', 'pipe'],
81
+ timeout: 15000,
82
+ });
83
+ const collector = createResponseCollector(child);
84
+ await new Promise((r) => setTimeout(r, 1000));
85
+ // Send initialize
86
+ sendJsonRpc(child, {
87
+ jsonrpc: '2.0',
88
+ id: 1,
89
+ method: 'initialize',
90
+ params: {
91
+ protocolVersion: '2024-11-05',
92
+ capabilities: {},
93
+ clientInfo: { name: 'test-stdio', version: '0.0.1' },
94
+ },
95
+ });
96
+ await new Promise((r) => setTimeout(r, 1500));
97
+ // Send initialized notification
98
+ sendJsonRpc(child, {
99
+ jsonrpc: '2.0',
100
+ method: 'notifications/initialized',
101
+ });
102
+ await new Promise((r) => setTimeout(r, 200));
103
+ // Send tools/list
104
+ sendJsonRpc(child, {
105
+ jsonrpc: '2.0',
106
+ id: 2,
107
+ method: 'tools/list',
108
+ params: {},
109
+ });
110
+ await new Promise((r) => setTimeout(r, 1500));
111
+ const toolsResponse = collector.responses.find((r) => r.id === 2 && r.result);
112
+ expect(toolsResponse).toBeDefined();
113
+ expect(toolsResponse.result.tools).toHaveLength(8);
114
+ const toolNames = toolsResponse.result.tools
115
+ .map((t) => t.name)
116
+ .sort();
117
+ expect(toolNames).toEqual([
118
+ 'click',
119
+ 'invoke_webmcp_tool',
120
+ 'list_webmcp_tools',
121
+ 'navigate_to',
122
+ 'page_snapshot',
123
+ 'screenshot',
124
+ 'select_option',
125
+ 'type_text',
126
+ ]);
127
+ }, 20000);
128
+ it('each tool schema from stdio has correct structure', async () => {
129
+ child = spawn('node', [cliPath], {
130
+ stdio: ['pipe', 'pipe', 'pipe'],
131
+ timeout: 15000,
132
+ });
133
+ const collector = createResponseCollector(child);
134
+ await new Promise((r) => setTimeout(r, 1000));
135
+ sendJsonRpc(child, {
136
+ jsonrpc: '2.0',
137
+ id: 1,
138
+ method: 'initialize',
139
+ params: {
140
+ protocolVersion: '2024-11-05',
141
+ capabilities: {},
142
+ clientInfo: { name: 'test', version: '0.0.1' },
143
+ },
144
+ });
145
+ await new Promise((r) => setTimeout(r, 1500));
146
+ sendJsonRpc(child, {
147
+ jsonrpc: '2.0',
148
+ method: 'notifications/initialized',
149
+ });
150
+ await new Promise((r) => setTimeout(r, 200));
151
+ sendJsonRpc(child, {
152
+ jsonrpc: '2.0',
153
+ id: 2,
154
+ method: 'tools/list',
155
+ params: {},
156
+ });
157
+ await new Promise((r) => setTimeout(r, 1500));
158
+ const toolsResponse = collector.responses.find((r) => r.id === 2 && r.result);
159
+ expect(toolsResponse).toBeDefined();
160
+ for (const tool of toolsResponse.result.tools) {
161
+ expect(tool.name).toBeTruthy();
162
+ expect(tool.description).toBeTruthy();
163
+ expect(tool.inputSchema).toBeDefined();
164
+ expect(tool.inputSchema.type).toBe('object');
165
+ }
166
+ }, 20000);
167
+ });
168
+ //# sourceMappingURL=mcp-stdio-integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-stdio-integration.test.js","sourceRoot":"","sources":["../../src/__tests__/mcp-stdio-integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=native-messaging-client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-messaging-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/native-messaging-client.test.ts"],"names":[],"mappings":""}