@spooky-sync/cli 0.0.1-canary.211 → 0.0.1-canary.213
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/AGENTS.md +21 -4
- package/devtools-mcp/index.js +24023 -30
- package/package.json +8 -7
- package/devtools-mcp/bridge.d.ts +0 -23
- package/devtools-mcp/bridge.js +0 -155
- package/devtools-mcp/dist/bridge.d.ts +0 -23
- package/devtools-mcp/dist/bridge.js +0 -155
- package/devtools-mcp/dist/index.d.ts +0 -2
- package/devtools-mcp/dist/index.js +0 -37
- package/devtools-mcp/dist/protocol.d.ts +0 -35
- package/devtools-mcp/dist/protocol.js +0 -38
- package/devtools-mcp/dist/server.d.ts +0 -4
- package/devtools-mcp/dist/server.js +0 -330
- package/devtools-mcp/dist/surreal.d.ts +0 -13
- package/devtools-mcp/dist/surreal.js +0 -27
- package/devtools-mcp/index.d.ts +0 -2
- package/devtools-mcp/protocol.d.ts +0 -34
- package/devtools-mcp/protocol.js +0 -37
- package/devtools-mcp/server.d.ts +0 -4
- package/devtools-mcp/server.js +0 -290
- package/devtools-mcp/surreal.d.ts +0 -13
- package/devtools-mcp/surreal.js +0 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spooky-sync/cli",
|
|
3
|
-
"version": "0.0.1-canary.
|
|
3
|
+
"version": "0.0.1-canary.213",
|
|
4
4
|
"description": "Generate TypeScript/Dart types from SurrealDB schema files",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/syncgen.cjs",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"spky": "./dist/cli.js"
|
|
11
11
|
},
|
|
12
12
|
"exports": {
|
|
13
|
+
"./devtools-mcp": "./devtools-mcp/index.js",
|
|
13
14
|
".": {
|
|
14
15
|
"import": "./dist/syncgen.js",
|
|
15
16
|
"require": "./dist/syncgen.cjs",
|
|
@@ -28,7 +29,7 @@
|
|
|
28
29
|
"build:rust": "cargo build --release",
|
|
29
30
|
"build:vite": "vite build",
|
|
30
31
|
"build:types": "tsc --emitDeclarationOnly --declaration --declarationDir dist",
|
|
31
|
-
"build:devtools-mcp": "
|
|
32
|
+
"build:devtools-mcp": "vite build --config vite.config.devtools-mcp.ts",
|
|
32
33
|
"build:js": "npm run build:vite && npm run build:types",
|
|
33
34
|
"build": "npm run build:rust && npm run build:devtools-mcp && npm run build:js",
|
|
34
35
|
"preview": "vite preview",
|
|
@@ -61,10 +62,10 @@
|
|
|
61
62
|
"vitest": "^1.0.0"
|
|
62
63
|
},
|
|
63
64
|
"optionalDependencies": {
|
|
64
|
-
"@spooky-sync/cli-darwin-arm64": "0.0.1-canary.
|
|
65
|
-
"@spooky-sync/cli-darwin-x64": "0.0.1-canary.
|
|
66
|
-
"@spooky-sync/cli-linux-arm64": "0.0.1-canary.
|
|
67
|
-
"@spooky-sync/cli-linux-x64": "0.0.1-canary.
|
|
68
|
-
"@spooky-sync/cli-win32-x64": "0.0.1-canary.
|
|
65
|
+
"@spooky-sync/cli-darwin-arm64": "0.0.1-canary.213",
|
|
66
|
+
"@spooky-sync/cli-darwin-x64": "0.0.1-canary.213",
|
|
67
|
+
"@spooky-sync/cli-linux-arm64": "0.0.1-canary.213",
|
|
68
|
+
"@spooky-sync/cli-linux-x64": "0.0.1-canary.213",
|
|
69
|
+
"@spooky-sync/cli-win32-x64": "0.0.1-canary.213"
|
|
69
70
|
}
|
|
70
71
|
}
|
package/devtools-mcp/bridge.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
interface ConnectedTab {
|
|
2
|
-
tabId: number;
|
|
3
|
-
url?: string;
|
|
4
|
-
title?: string;
|
|
5
|
-
}
|
|
6
|
-
export declare class Bridge {
|
|
7
|
-
private wss;
|
|
8
|
-
private extensionSocket;
|
|
9
|
-
private connectedTabs;
|
|
10
|
-
private pendingRequests;
|
|
11
|
-
private requestCounter;
|
|
12
|
-
private pingInterval;
|
|
13
|
-
get isConnected(): boolean;
|
|
14
|
-
getConnectedTabs(): ConnectedTab[];
|
|
15
|
-
start(): Promise<void>;
|
|
16
|
-
private startPing;
|
|
17
|
-
private stopPing;
|
|
18
|
-
private handleMessage;
|
|
19
|
-
request(method: string, params?: Record<string, unknown>, tabId?: number): Promise<unknown>;
|
|
20
|
-
private getDefaultTabId;
|
|
21
|
-
stop(): Promise<void>;
|
|
22
|
-
}
|
|
23
|
-
export {};
|
package/devtools-mcp/bridge.js
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { WebSocketServer, WebSocket } from 'ws';
|
|
2
|
-
import { isBridgeResponse, isBridgeNotification, BRIDGE_PORT, } from './protocol.js';
|
|
3
|
-
const REQUEST_TIMEOUT_MS = 10_000;
|
|
4
|
-
export class Bridge {
|
|
5
|
-
wss = null;
|
|
6
|
-
extensionSocket = null;
|
|
7
|
-
connectedTabs = new Map();
|
|
8
|
-
pendingRequests = new Map();
|
|
9
|
-
requestCounter = 0;
|
|
10
|
-
pingInterval = null;
|
|
11
|
-
get isConnected() {
|
|
12
|
-
return this.extensionSocket?.readyState === WebSocket.OPEN;
|
|
13
|
-
}
|
|
14
|
-
getConnectedTabs() {
|
|
15
|
-
return Array.from(this.connectedTabs.values());
|
|
16
|
-
}
|
|
17
|
-
start() {
|
|
18
|
-
const port = Number.parseInt(process.env.SP00KY_MCP_PORT || '', 10) || BRIDGE_PORT;
|
|
19
|
-
return new Promise((resolve, reject) => {
|
|
20
|
-
this.wss = new WebSocketServer({ host: '127.0.0.1', port }, () => {
|
|
21
|
-
process.stderr.write(`[sp00ky-mcp] Bridge listening on ws://127.0.0.1:${port}\n`);
|
|
22
|
-
resolve();
|
|
23
|
-
});
|
|
24
|
-
this.wss.on('error', (err) => {
|
|
25
|
-
process.stderr.write(`[sp00ky-mcp] Bridge error: ${err.message}\n`);
|
|
26
|
-
reject(err);
|
|
27
|
-
});
|
|
28
|
-
this.wss.on('connection', (ws) => {
|
|
29
|
-
process.stderr.write('[sp00ky-mcp] Extension connected\n');
|
|
30
|
-
// Only allow one extension connection at a time
|
|
31
|
-
if (this.extensionSocket) {
|
|
32
|
-
this.extensionSocket.close();
|
|
33
|
-
}
|
|
34
|
-
this.extensionSocket = ws;
|
|
35
|
-
// Start keepalive pings
|
|
36
|
-
this.startPing(ws);
|
|
37
|
-
ws.on('message', (data) => {
|
|
38
|
-
try {
|
|
39
|
-
const msg = JSON.parse(data.toString());
|
|
40
|
-
this.handleMessage(msg);
|
|
41
|
-
}
|
|
42
|
-
catch (err) {
|
|
43
|
-
process.stderr.write(`[sp00ky-mcp] Bad message: ${err}\n`);
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
ws.on('close', () => {
|
|
47
|
-
process.stderr.write('[sp00ky-mcp] Extension disconnected\n');
|
|
48
|
-
if (this.extensionSocket === ws) {
|
|
49
|
-
this.extensionSocket = null;
|
|
50
|
-
this.connectedTabs.clear();
|
|
51
|
-
this.stopPing();
|
|
52
|
-
// Reject all pending requests
|
|
53
|
-
for (const [id, pending] of this.pendingRequests) {
|
|
54
|
-
pending.reject(new Error('Extension disconnected'));
|
|
55
|
-
clearTimeout(pending.timer);
|
|
56
|
-
this.pendingRequests.delete(id);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
ws.on('error', (err) => {
|
|
61
|
-
process.stderr.write(`[sp00ky-mcp] Socket error: ${err.message}\n`);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
startPing(ws) {
|
|
67
|
-
this.stopPing();
|
|
68
|
-
this.pingInterval = setInterval(() => {
|
|
69
|
-
if (ws.readyState === WebSocket.OPEN) {
|
|
70
|
-
ws.ping();
|
|
71
|
-
}
|
|
72
|
-
}, 20_000);
|
|
73
|
-
}
|
|
74
|
-
stopPing() {
|
|
75
|
-
if (this.pingInterval) {
|
|
76
|
-
clearInterval(this.pingInterval);
|
|
77
|
-
this.pingInterval = null;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
handleMessage(msg) {
|
|
81
|
-
// Handle response to a pending request
|
|
82
|
-
if (isBridgeResponse(msg)) {
|
|
83
|
-
const pending = this.pendingRequests.get(msg.id);
|
|
84
|
-
if (pending) {
|
|
85
|
-
clearTimeout(pending.timer);
|
|
86
|
-
this.pendingRequests.delete(msg.id);
|
|
87
|
-
if (msg.error) {
|
|
88
|
-
pending.reject(new Error(msg.error.message));
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
pending.resolve(msg.result);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
// Handle notifications from extension
|
|
97
|
-
if (isBridgeNotification(msg)) {
|
|
98
|
-
if (msg.method === 'tabsChanged') {
|
|
99
|
-
this.connectedTabs.clear();
|
|
100
|
-
const tabs = msg.params.tabs;
|
|
101
|
-
for (const tab of tabs) {
|
|
102
|
-
this.connectedTabs.set(tab.tabId, tab);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
async request(method, params = {}, tabId) {
|
|
109
|
-
if (!this.extensionSocket || this.extensionSocket.readyState !== WebSocket.OPEN) {
|
|
110
|
-
throw new Error('No extension connected. Make sure the Sp00ky DevTools extension is running and has a page with Sp00ky open.');
|
|
111
|
-
}
|
|
112
|
-
const id = `mcp-${++this.requestCounter}`;
|
|
113
|
-
const resolvedTabId = tabId ?? this.getDefaultTabId();
|
|
114
|
-
const request = {
|
|
115
|
-
jsonrpc: '2.0',
|
|
116
|
-
id,
|
|
117
|
-
method,
|
|
118
|
-
params,
|
|
119
|
-
...(resolvedTabId !== undefined ? { tabId: resolvedTabId } : {}),
|
|
120
|
-
};
|
|
121
|
-
return new Promise((resolve, reject) => {
|
|
122
|
-
const timer = setTimeout(() => {
|
|
123
|
-
this.pendingRequests.delete(id);
|
|
124
|
-
reject(new Error(`Request timed out after ${REQUEST_TIMEOUT_MS}ms: ${method}`));
|
|
125
|
-
}, REQUEST_TIMEOUT_MS);
|
|
126
|
-
this.pendingRequests.set(id, { resolve, reject, timer });
|
|
127
|
-
// oxlint-disable-next-line no-non-null-assertion
|
|
128
|
-
this.extensionSocket.send(JSON.stringify(request));
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
getDefaultTabId() {
|
|
132
|
-
const tabs = this.getConnectedTabs();
|
|
133
|
-
return tabs.length > 0 ? tabs[0].tabId : undefined;
|
|
134
|
-
}
|
|
135
|
-
async stop() {
|
|
136
|
-
this.stopPing();
|
|
137
|
-
for (const [id, pending] of this.pendingRequests) {
|
|
138
|
-
clearTimeout(pending.timer);
|
|
139
|
-
pending.reject(new Error('Bridge shutting down'));
|
|
140
|
-
this.pendingRequests.delete(id);
|
|
141
|
-
}
|
|
142
|
-
if (this.extensionSocket) {
|
|
143
|
-
this.extensionSocket.close();
|
|
144
|
-
this.extensionSocket = null;
|
|
145
|
-
}
|
|
146
|
-
return new Promise((resolve) => {
|
|
147
|
-
if (this.wss) {
|
|
148
|
-
this.wss.close(() => resolve());
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
resolve();
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
interface ConnectedTab {
|
|
2
|
-
tabId: number;
|
|
3
|
-
url?: string;
|
|
4
|
-
title?: string;
|
|
5
|
-
}
|
|
6
|
-
export declare class Bridge {
|
|
7
|
-
private wss;
|
|
8
|
-
private extensionSocket;
|
|
9
|
-
private connectedTabs;
|
|
10
|
-
private pendingRequests;
|
|
11
|
-
private requestCounter;
|
|
12
|
-
private pingInterval;
|
|
13
|
-
get isConnected(): boolean;
|
|
14
|
-
getConnectedTabs(): ConnectedTab[];
|
|
15
|
-
start(): Promise<void>;
|
|
16
|
-
private startPing;
|
|
17
|
-
private stopPing;
|
|
18
|
-
private handleMessage;
|
|
19
|
-
request(method: string, params?: Record<string, unknown>, tabId?: number): Promise<unknown>;
|
|
20
|
-
private getDefaultTabId;
|
|
21
|
-
stop(): Promise<void>;
|
|
22
|
-
}
|
|
23
|
-
export {};
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { WebSocketServer, WebSocket } from 'ws';
|
|
2
|
-
import { isBridgeResponse, isBridgeNotification, BRIDGE_PORT, } from './protocol.js';
|
|
3
|
-
const REQUEST_TIMEOUT_MS = 10_000;
|
|
4
|
-
export class Bridge {
|
|
5
|
-
wss = null;
|
|
6
|
-
extensionSocket = null;
|
|
7
|
-
connectedTabs = new Map();
|
|
8
|
-
pendingRequests = new Map();
|
|
9
|
-
requestCounter = 0;
|
|
10
|
-
pingInterval = null;
|
|
11
|
-
get isConnected() {
|
|
12
|
-
return this.extensionSocket?.readyState === WebSocket.OPEN;
|
|
13
|
-
}
|
|
14
|
-
getConnectedTabs() {
|
|
15
|
-
return Array.from(this.connectedTabs.values());
|
|
16
|
-
}
|
|
17
|
-
start() {
|
|
18
|
-
const port = Number.parseInt(process.env.SP00KY_MCP_PORT || '', 10) || BRIDGE_PORT;
|
|
19
|
-
return new Promise((resolve, reject) => {
|
|
20
|
-
this.wss = new WebSocketServer({ host: '127.0.0.1', port }, () => {
|
|
21
|
-
process.stderr.write(`[sp00ky-mcp] Bridge listening on ws://127.0.0.1:${port}\n`);
|
|
22
|
-
resolve();
|
|
23
|
-
});
|
|
24
|
-
this.wss.on('error', (err) => {
|
|
25
|
-
process.stderr.write(`[sp00ky-mcp] Bridge error: ${err.message}\n`);
|
|
26
|
-
reject(err);
|
|
27
|
-
});
|
|
28
|
-
this.wss.on('connection', (ws) => {
|
|
29
|
-
process.stderr.write('[sp00ky-mcp] Extension connected\n');
|
|
30
|
-
// Only allow one extension connection at a time
|
|
31
|
-
if (this.extensionSocket) {
|
|
32
|
-
this.extensionSocket.close();
|
|
33
|
-
}
|
|
34
|
-
this.extensionSocket = ws;
|
|
35
|
-
// Start keepalive pings
|
|
36
|
-
this.startPing(ws);
|
|
37
|
-
ws.on('message', (data) => {
|
|
38
|
-
try {
|
|
39
|
-
const msg = JSON.parse(data.toString());
|
|
40
|
-
this.handleMessage(msg);
|
|
41
|
-
}
|
|
42
|
-
catch (err) {
|
|
43
|
-
process.stderr.write(`[sp00ky-mcp] Bad message: ${err}\n`);
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
ws.on('close', () => {
|
|
47
|
-
process.stderr.write('[sp00ky-mcp] Extension disconnected\n');
|
|
48
|
-
if (this.extensionSocket === ws) {
|
|
49
|
-
this.extensionSocket = null;
|
|
50
|
-
this.connectedTabs.clear();
|
|
51
|
-
this.stopPing();
|
|
52
|
-
// Reject all pending requests
|
|
53
|
-
for (const [id, pending] of this.pendingRequests) {
|
|
54
|
-
pending.reject(new Error('Extension disconnected'));
|
|
55
|
-
clearTimeout(pending.timer);
|
|
56
|
-
this.pendingRequests.delete(id);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
ws.on('error', (err) => {
|
|
61
|
-
process.stderr.write(`[sp00ky-mcp] Socket error: ${err.message}\n`);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
startPing(ws) {
|
|
67
|
-
this.stopPing();
|
|
68
|
-
this.pingInterval = setInterval(() => {
|
|
69
|
-
if (ws.readyState === WebSocket.OPEN) {
|
|
70
|
-
ws.ping();
|
|
71
|
-
}
|
|
72
|
-
}, 20_000);
|
|
73
|
-
}
|
|
74
|
-
stopPing() {
|
|
75
|
-
if (this.pingInterval) {
|
|
76
|
-
clearInterval(this.pingInterval);
|
|
77
|
-
this.pingInterval = null;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
handleMessage(msg) {
|
|
81
|
-
// Handle response to a pending request
|
|
82
|
-
if (isBridgeResponse(msg)) {
|
|
83
|
-
const pending = this.pendingRequests.get(msg.id);
|
|
84
|
-
if (pending) {
|
|
85
|
-
clearTimeout(pending.timer);
|
|
86
|
-
this.pendingRequests.delete(msg.id);
|
|
87
|
-
if (msg.error) {
|
|
88
|
-
pending.reject(new Error(msg.error.message));
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
pending.resolve(msg.result);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
// Handle notifications from extension
|
|
97
|
-
if (isBridgeNotification(msg)) {
|
|
98
|
-
if (msg.method === 'tabsChanged') {
|
|
99
|
-
this.connectedTabs.clear();
|
|
100
|
-
const tabs = msg.params.tabs;
|
|
101
|
-
for (const tab of tabs) {
|
|
102
|
-
this.connectedTabs.set(tab.tabId, tab);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
async request(method, params = {}, tabId) {
|
|
109
|
-
if (!this.extensionSocket || this.extensionSocket.readyState !== WebSocket.OPEN) {
|
|
110
|
-
throw new Error('No extension connected. Make sure the Sp00ky DevTools extension is running and has a page with Sp00ky open.');
|
|
111
|
-
}
|
|
112
|
-
const id = `mcp-${++this.requestCounter}`;
|
|
113
|
-
const resolvedTabId = tabId ?? this.getDefaultTabId();
|
|
114
|
-
const request = {
|
|
115
|
-
jsonrpc: '2.0',
|
|
116
|
-
id,
|
|
117
|
-
method,
|
|
118
|
-
params,
|
|
119
|
-
...(resolvedTabId !== undefined ? { tabId: resolvedTabId } : {}),
|
|
120
|
-
};
|
|
121
|
-
return new Promise((resolve, reject) => {
|
|
122
|
-
const timer = setTimeout(() => {
|
|
123
|
-
this.pendingRequests.delete(id);
|
|
124
|
-
reject(new Error(`Request timed out after ${REQUEST_TIMEOUT_MS}ms: ${method}`));
|
|
125
|
-
}, REQUEST_TIMEOUT_MS);
|
|
126
|
-
this.pendingRequests.set(id, { resolve, reject, timer });
|
|
127
|
-
// oxlint-disable-next-line no-non-null-assertion
|
|
128
|
-
this.extensionSocket.send(JSON.stringify(request));
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
getDefaultTabId() {
|
|
132
|
-
const tabs = this.getConnectedTabs();
|
|
133
|
-
return tabs.length > 0 ? tabs[0].tabId : undefined;
|
|
134
|
-
}
|
|
135
|
-
async stop() {
|
|
136
|
-
this.stopPing();
|
|
137
|
-
for (const [id, pending] of this.pendingRequests) {
|
|
138
|
-
clearTimeout(pending.timer);
|
|
139
|
-
pending.reject(new Error('Bridge shutting down'));
|
|
140
|
-
this.pendingRequests.delete(id);
|
|
141
|
-
}
|
|
142
|
-
if (this.extensionSocket) {
|
|
143
|
-
this.extensionSocket.close();
|
|
144
|
-
this.extensionSocket = null;
|
|
145
|
-
}
|
|
146
|
-
return new Promise((resolve) => {
|
|
147
|
-
if (this.wss) {
|
|
148
|
-
this.wss.close(() => resolve());
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
resolve();
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
-
import { Bridge } from './bridge.js';
|
|
4
|
-
import { SurrealClient } from './surreal.js';
|
|
5
|
-
import { createServer } from './server.js';
|
|
6
|
-
async function main() {
|
|
7
|
-
const bridge = new Bridge();
|
|
8
|
-
await bridge.start();
|
|
9
|
-
const surreal = process.env.SURREAL_URL
|
|
10
|
-
? new SurrealClient({
|
|
11
|
-
url: process.env.SURREAL_URL,
|
|
12
|
-
namespace: process.env.SURREAL_NS ?? 'main',
|
|
13
|
-
database: process.env.SURREAL_DB ?? 'main',
|
|
14
|
-
username: process.env.SURREAL_USER ?? 'root',
|
|
15
|
-
password: process.env.SURREAL_PASS ?? 'root',
|
|
16
|
-
})
|
|
17
|
-
: null;
|
|
18
|
-
if (surreal) {
|
|
19
|
-
process.stderr.write(`[sp00ky-mcp] Direct DB mode enabled (${process.env.SURREAL_URL})\n`);
|
|
20
|
-
}
|
|
21
|
-
const server = createServer(bridge, surreal);
|
|
22
|
-
const transport = new StdioServerTransport();
|
|
23
|
-
await server.connect(transport);
|
|
24
|
-
process.stderr.write('[sp00ky-mcp] MCP server running on stdio\n');
|
|
25
|
-
// Graceful shutdown
|
|
26
|
-
const cleanup = async () => {
|
|
27
|
-
process.stderr.write('[sp00ky-mcp] Shutting down...\n');
|
|
28
|
-
await bridge.stop();
|
|
29
|
-
process.exit(0);
|
|
30
|
-
};
|
|
31
|
-
process.on('SIGINT', cleanup);
|
|
32
|
-
process.on('SIGTERM', cleanup);
|
|
33
|
-
}
|
|
34
|
-
main().catch((err) => {
|
|
35
|
-
process.stderr.write(`[sp00ky-mcp] Fatal error: ${err.message}\n`);
|
|
36
|
-
process.exit(1);
|
|
37
|
-
});
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
export interface BridgeRequest {
|
|
2
|
-
jsonrpc: '2.0';
|
|
3
|
-
id: string;
|
|
4
|
-
method: string;
|
|
5
|
-
params: Record<string, unknown>;
|
|
6
|
-
tabId?: number;
|
|
7
|
-
}
|
|
8
|
-
export interface BridgeResponse {
|
|
9
|
-
jsonrpc: '2.0';
|
|
10
|
-
id: string;
|
|
11
|
-
result?: unknown;
|
|
12
|
-
error?: {
|
|
13
|
-
code: number;
|
|
14
|
-
message: string;
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
export interface BridgeNotification {
|
|
18
|
-
jsonrpc: '2.0';
|
|
19
|
-
method: string;
|
|
20
|
-
params: Record<string, unknown>;
|
|
21
|
-
}
|
|
22
|
-
export type BridgeMessage = BridgeRequest | BridgeResponse | BridgeNotification;
|
|
23
|
-
export declare const BRIDGE_METHODS: {
|
|
24
|
-
readonly GET_STATE: "getState";
|
|
25
|
-
readonly RUN_QUERY: "runQuery";
|
|
26
|
-
readonly GET_TABLE_DATA: "getTableData";
|
|
27
|
-
readonly GET_QUERY_ROWS: "getQueryRows";
|
|
28
|
-
readonly UPDATE_TABLE_ROW: "updateTableRow";
|
|
29
|
-
readonly DELETE_TABLE_ROW: "deleteTableRow";
|
|
30
|
-
readonly CLEAR_HISTORY: "clearHistory";
|
|
31
|
-
};
|
|
32
|
-
export declare const BRIDGE_PORT = 9315;
|
|
33
|
-
export declare function isBridgeResponse(msg: unknown): msg is BridgeResponse;
|
|
34
|
-
export declare function isBridgeRequest(msg: unknown): msg is BridgeRequest;
|
|
35
|
-
export declare function isBridgeNotification(msg: unknown): msg is BridgeNotification;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// Shared message types for MCP Server <-> Chrome Extension bridge (JSON-RPC 2.0 style)
|
|
2
|
-
// Methods the MCP server can call on the extension
|
|
3
|
-
export const BRIDGE_METHODS = {
|
|
4
|
-
GET_STATE: 'getState',
|
|
5
|
-
RUN_QUERY: 'runQuery',
|
|
6
|
-
GET_TABLE_DATA: 'getTableData',
|
|
7
|
-
GET_QUERY_ROWS: 'getQueryRows',
|
|
8
|
-
UPDATE_TABLE_ROW: 'updateTableRow',
|
|
9
|
-
DELETE_TABLE_ROW: 'deleteTableRow',
|
|
10
|
-
CLEAR_HISTORY: 'clearHistory',
|
|
11
|
-
};
|
|
12
|
-
export const BRIDGE_PORT = 9315;
|
|
13
|
-
export function isBridgeResponse(msg) {
|
|
14
|
-
return (typeof msg === 'object' &&
|
|
15
|
-
msg !== null &&
|
|
16
|
-
'jsonrpc' in msg &&
|
|
17
|
-
msg.jsonrpc === '2.0' &&
|
|
18
|
-
'id' in msg &&
|
|
19
|
-
('result' in msg || 'error' in msg));
|
|
20
|
-
}
|
|
21
|
-
export function isBridgeRequest(msg) {
|
|
22
|
-
return (typeof msg === 'object' &&
|
|
23
|
-
msg !== null &&
|
|
24
|
-
'jsonrpc' in msg &&
|
|
25
|
-
msg.jsonrpc === '2.0' &&
|
|
26
|
-
'method' in msg &&
|
|
27
|
-
'id' in msg &&
|
|
28
|
-
!('result' in msg) &&
|
|
29
|
-
!('error' in msg));
|
|
30
|
-
}
|
|
31
|
-
export function isBridgeNotification(msg) {
|
|
32
|
-
return (typeof msg === 'object' &&
|
|
33
|
-
msg !== null &&
|
|
34
|
-
'jsonrpc' in msg &&
|
|
35
|
-
msg.jsonrpc === '2.0' &&
|
|
36
|
-
'method' in msg &&
|
|
37
|
-
!('id' in msg));
|
|
38
|
-
}
|