claude-ide-bridge 1.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 (273) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +263 -0
  3. package/dist/activityLog.d.ts +26 -0
  4. package/dist/activityLog.js +76 -0
  5. package/dist/activityLog.js.map +1 -0
  6. package/dist/bridge.d.ts +19 -0
  7. package/dist/bridge.js +277 -0
  8. package/dist/bridge.js.map +1 -0
  9. package/dist/config.d.ts +22 -0
  10. package/dist/config.js +221 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/errors.d.ts +16 -0
  13. package/dist/errors.js +20 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/extensionClient.d.ts +193 -0
  16. package/dist/extensionClient.js +698 -0
  17. package/dist/extensionClient.js.map +1 -0
  18. package/dist/fileLock.d.ts +12 -0
  19. package/dist/fileLock.js +30 -0
  20. package/dist/fileLock.js.map +1 -0
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.js +38 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/lockfile.d.ts +12 -0
  25. package/dist/lockfile.js +127 -0
  26. package/dist/lockfile.js.map +1 -0
  27. package/dist/logger.d.ts +16 -0
  28. package/dist/logger.js +68 -0
  29. package/dist/logger.js.map +1 -0
  30. package/dist/probe.d.ts +22 -0
  31. package/dist/probe.js +45 -0
  32. package/dist/probe.js.map +1 -0
  33. package/dist/server.d.ts +25 -0
  34. package/dist/server.js +265 -0
  35. package/dist/server.js.map +1 -0
  36. package/dist/tools/activityLog.d.ts +39 -0
  37. package/dist/tools/activityLog.js +49 -0
  38. package/dist/tools/activityLog.js.map +1 -0
  39. package/dist/tools/aiComments.d.ts +26 -0
  40. package/dist/tools/aiComments.js +196 -0
  41. package/dist/tools/aiComments.js.map +1 -0
  42. package/dist/tools/bridgeStatus.d.ts +21 -0
  43. package/dist/tools/bridgeStatus.js +41 -0
  44. package/dist/tools/bridgeStatus.js.map +1 -0
  45. package/dist/tools/checkDocumentDirty.d.ts +28 -0
  46. package/dist/tools/checkDocumentDirty.js +61 -0
  47. package/dist/tools/checkDocumentDirty.js.map +1 -0
  48. package/dist/tools/clipboard.d.ts +50 -0
  49. package/dist/tools/clipboard.js +82 -0
  50. package/dist/tools/clipboard.js.map +1 -0
  51. package/dist/tools/closeTabs.d.ts +49 -0
  52. package/dist/tools/closeTabs.js +77 -0
  53. package/dist/tools/closeTabs.js.map +1 -0
  54. package/dist/tools/debug.d.ts +154 -0
  55. package/dist/tools/debug.js +248 -0
  56. package/dist/tools/debug.js.map +1 -0
  57. package/dist/tools/decorations.d.ts +92 -0
  58. package/dist/tools/decorations.js +150 -0
  59. package/dist/tools/decorations.js.map +1 -0
  60. package/dist/tools/diffDebugger.d.ts +62 -0
  61. package/dist/tools/diffDebugger.js +245 -0
  62. package/dist/tools/diffDebugger.js.map +1 -0
  63. package/dist/tools/editText.d.ts +80 -0
  64. package/dist/tools/editText.js +274 -0
  65. package/dist/tools/editText.js.map +1 -0
  66. package/dist/tools/fileOperations.d.ts +111 -0
  67. package/dist/tools/fileOperations.js +280 -0
  68. package/dist/tools/fileOperations.js.map +1 -0
  69. package/dist/tools/fileWatcher.d.ts +54 -0
  70. package/dist/tools/fileWatcher.js +100 -0
  71. package/dist/tools/fileWatcher.js.map +1 -0
  72. package/dist/tools/findFiles.d.ts +31 -0
  73. package/dist/tools/findFiles.js +119 -0
  74. package/dist/tools/findFiles.js.map +1 -0
  75. package/dist/tools/fixAllLintErrors.d.ts +29 -0
  76. package/dist/tools/fixAllLintErrors.js +114 -0
  77. package/dist/tools/fixAllLintErrors.js.map +1 -0
  78. package/dist/tools/flowGuardian.d.ts +61 -0
  79. package/dist/tools/flowGuardian.js +311 -0
  80. package/dist/tools/flowGuardian.js.map +1 -0
  81. package/dist/tools/formatDocument.d.ts +30 -0
  82. package/dist/tools/formatDocument.js +132 -0
  83. package/dist/tools/formatDocument.js.map +1 -0
  84. package/dist/tools/formatFile.d.ts +28 -0
  85. package/dist/tools/formatFile.js +110 -0
  86. package/dist/tools/formatFile.js.map +1 -0
  87. package/dist/tools/getBufferContent.d.ts +38 -0
  88. package/dist/tools/getBufferContent.js +100 -0
  89. package/dist/tools/getBufferContent.js.map +1 -0
  90. package/dist/tools/getCurrentSelection.d.ts +43 -0
  91. package/dist/tools/getCurrentSelection.js +75 -0
  92. package/dist/tools/getCurrentSelection.js.map +1 -0
  93. package/dist/tools/getDiagnostics.d.ts +38 -0
  94. package/dist/tools/getDiagnostics.js +204 -0
  95. package/dist/tools/getDiagnostics.js.map +1 -0
  96. package/dist/tools/getDocumentSymbols.d.ts +27 -0
  97. package/dist/tools/getDocumentSymbols.js +133 -0
  98. package/dist/tools/getDocumentSymbols.js.map +1 -0
  99. package/dist/tools/getFileTree.d.ts +36 -0
  100. package/dist/tools/getFileTree.js +111 -0
  101. package/dist/tools/getFileTree.js.map +1 -0
  102. package/dist/tools/getGitDiff.d.ts +34 -0
  103. package/dist/tools/getGitDiff.js +57 -0
  104. package/dist/tools/getGitDiff.js.map +1 -0
  105. package/dist/tools/getGitLog.d.ts +30 -0
  106. package/dist/tools/getGitLog.js +65 -0
  107. package/dist/tools/getGitLog.js.map +1 -0
  108. package/dist/tools/getGitStatus.d.ts +26 -0
  109. package/dist/tools/getGitStatus.js +95 -0
  110. package/dist/tools/getGitStatus.js.map +1 -0
  111. package/dist/tools/getOpenEditors.d.ts +21 -0
  112. package/dist/tools/getOpenEditors.js +84 -0
  113. package/dist/tools/getOpenEditors.js.map +1 -0
  114. package/dist/tools/getProjectInfo.d.ts +20 -0
  115. package/dist/tools/getProjectInfo.js +315 -0
  116. package/dist/tools/getProjectInfo.js.map +1 -0
  117. package/dist/tools/getToolCapabilities.d.ts +23 -0
  118. package/dist/tools/getToolCapabilities.js +249 -0
  119. package/dist/tools/getToolCapabilities.js.map +1 -0
  120. package/dist/tools/getWorkspaceFolders.d.ts +21 -0
  121. package/dist/tools/getWorkspaceFolders.js +47 -0
  122. package/dist/tools/getWorkspaceFolders.js.map +1 -0
  123. package/dist/tools/gitHistory.d.ts +78 -0
  124. package/dist/tools/gitHistory.js +151 -0
  125. package/dist/tools/gitHistory.js.map +1 -0
  126. package/dist/tools/gitWrite.d.ts +335 -0
  127. package/dist/tools/gitWrite.js +859 -0
  128. package/dist/tools/gitWrite.js.map +1 -0
  129. package/dist/tools/github/actions.d.ts +67 -0
  130. package/dist/tools/github/actions.js +155 -0
  131. package/dist/tools/github/actions.js.map +1 -0
  132. package/dist/tools/github/index.d.ts +4 -0
  133. package/dist/tools/github/index.js +5 -0
  134. package/dist/tools/github/index.js.map +1 -0
  135. package/dist/tools/github/issues.d.ts +140 -0
  136. package/dist/tools/github/issues.js +279 -0
  137. package/dist/tools/github/issues.js.map +1 -0
  138. package/dist/tools/github/pr.d.ts +101 -0
  139. package/dist/tools/github/pr.js +215 -0
  140. package/dist/tools/github/pr.js.map +1 -0
  141. package/dist/tools/github/review.d.ts +101 -0
  142. package/dist/tools/github/review.js +292 -0
  143. package/dist/tools/github/review.js.map +1 -0
  144. package/dist/tools/github/shared.d.ts +4 -0
  145. package/dist/tools/github/shared.js +12 -0
  146. package/dist/tools/github/shared.js.map +1 -0
  147. package/dist/tools/github.d.ts +308 -0
  148. package/dist/tools/github.js +656 -0
  149. package/dist/tools/github.js.map +1 -0
  150. package/dist/tools/hoverAtCursor.d.ts +22 -0
  151. package/dist/tools/hoverAtCursor.js +51 -0
  152. package/dist/tools/hoverAtCursor.js.map +1 -0
  153. package/dist/tools/httpClient.d.ts +83 -0
  154. package/dist/tools/httpClient.js +335 -0
  155. package/dist/tools/httpClient.js.map +1 -0
  156. package/dist/tools/index.d.ts +7 -0
  157. package/dist/tools/index.js +246 -0
  158. package/dist/tools/index.js.map +1 -0
  159. package/dist/tools/inlayHints.d.ts +38 -0
  160. package/dist/tools/inlayHints.js +56 -0
  161. package/dist/tools/inlayHints.js.map +1 -0
  162. package/dist/tools/linters/biome.d.ts +2 -0
  163. package/dist/tools/linters/biome.js +44 -0
  164. package/dist/tools/linters/biome.js.map +1 -0
  165. package/dist/tools/linters/cargo.d.ts +2 -0
  166. package/dist/tools/linters/cargo.js +45 -0
  167. package/dist/tools/linters/cargo.js.map +1 -0
  168. package/dist/tools/linters/eslint.d.ts +2 -0
  169. package/dist/tools/linters/eslint.js +59 -0
  170. package/dist/tools/linters/eslint.js.map +1 -0
  171. package/dist/tools/linters/govet.d.ts +2 -0
  172. package/dist/tools/linters/govet.js +37 -0
  173. package/dist/tools/linters/govet.js.map +1 -0
  174. package/dist/tools/linters/pyright.d.ts +2 -0
  175. package/dist/tools/linters/pyright.js +34 -0
  176. package/dist/tools/linters/pyright.js.map +1 -0
  177. package/dist/tools/linters/ruff.d.ts +2 -0
  178. package/dist/tools/linters/ruff.js +30 -0
  179. package/dist/tools/linters/ruff.js.map +1 -0
  180. package/dist/tools/linters/types.d.ts +16 -0
  181. package/dist/tools/linters/types.js +2 -0
  182. package/dist/tools/linters/types.js.map +1 -0
  183. package/dist/tools/linters/typescript.d.ts +2 -0
  184. package/dist/tools/linters/typescript.js +38 -0
  185. package/dist/tools/linters/typescript.js.map +1 -0
  186. package/dist/tools/lsp.d.ts +310 -0
  187. package/dist/tools/lsp.js +684 -0
  188. package/dist/tools/lsp.js.map +1 -0
  189. package/dist/tools/notebook.d.ts +95 -0
  190. package/dist/tools/notebook.js +144 -0
  191. package/dist/tools/notebook.js.map +1 -0
  192. package/dist/tools/openDiff.d.ts +41 -0
  193. package/dist/tools/openDiff.js +116 -0
  194. package/dist/tools/openDiff.js.map +1 -0
  195. package/dist/tools/openFile.d.ts +34 -0
  196. package/dist/tools/openFile.js +102 -0
  197. package/dist/tools/openFile.js.map +1 -0
  198. package/dist/tools/organizeImports.d.ts +29 -0
  199. package/dist/tools/organizeImports.js +64 -0
  200. package/dist/tools/organizeImports.js.map +1 -0
  201. package/dist/tools/planPersistence.d.ts +196 -0
  202. package/dist/tools/planPersistence.js +437 -0
  203. package/dist/tools/planPersistence.js.map +1 -0
  204. package/dist/tools/replaceBlock.d.ts +40 -0
  205. package/dist/tools/replaceBlock.js +105 -0
  206. package/dist/tools/replaceBlock.js.map +1 -0
  207. package/dist/tools/runCommand.d.ts +43 -0
  208. package/dist/tools/runCommand.js +141 -0
  209. package/dist/tools/runCommand.js.map +1 -0
  210. package/dist/tools/runTests.d.ts +32 -0
  211. package/dist/tools/runTests.js +160 -0
  212. package/dist/tools/runTests.js.map +1 -0
  213. package/dist/tools/saveDocument.d.ts +28 -0
  214. package/dist/tools/saveDocument.js +58 -0
  215. package/dist/tools/saveDocument.js.map +1 -0
  216. package/dist/tools/searchAndReplace.d.ts +50 -0
  217. package/dist/tools/searchAndReplace.js +203 -0
  218. package/dist/tools/searchAndReplace.js.map +1 -0
  219. package/dist/tools/searchWorkspace.d.ts +52 -0
  220. package/dist/tools/searchWorkspace.js +159 -0
  221. package/dist/tools/searchWorkspace.js.map +1 -0
  222. package/dist/tools/setActiveWorkspaceFolder.d.ts +28 -0
  223. package/dist/tools/setActiveWorkspaceFolder.js +32 -0
  224. package/dist/tools/setActiveWorkspaceFolder.js.map +1 -0
  225. package/dist/tools/tasks.d.ts +56 -0
  226. package/dist/tools/tasks.js +89 -0
  227. package/dist/tools/tasks.js.map +1 -0
  228. package/dist/tools/terminal.d.ts +241 -0
  229. package/dist/tools/terminal.js +539 -0
  230. package/dist/tools/terminal.js.map +1 -0
  231. package/dist/tools/testRunners/cargoTest.d.ts +2 -0
  232. package/dist/tools/testRunners/cargoTest.js +123 -0
  233. package/dist/tools/testRunners/cargoTest.js.map +1 -0
  234. package/dist/tools/testRunners/goTest.d.ts +2 -0
  235. package/dist/tools/testRunners/goTest.js +106 -0
  236. package/dist/tools/testRunners/goTest.js.map +1 -0
  237. package/dist/tools/testRunners/pytest.d.ts +2 -0
  238. package/dist/tools/testRunners/pytest.js +133 -0
  239. package/dist/tools/testRunners/pytest.js.map +1 -0
  240. package/dist/tools/testRunners/types.d.ts +18 -0
  241. package/dist/tools/testRunners/types.js +2 -0
  242. package/dist/tools/testRunners/types.js.map +1 -0
  243. package/dist/tools/testRunners/vitestJest.d.ts +3 -0
  244. package/dist/tools/testRunners/vitestJest.js +178 -0
  245. package/dist/tools/testRunners/vitestJest.js.map +1 -0
  246. package/dist/tools/typeHierarchy.d.ts +45 -0
  247. package/dist/tools/typeHierarchy.js +65 -0
  248. package/dist/tools/typeHierarchy.js.map +1 -0
  249. package/dist/tools/utils.d.ts +54 -0
  250. package/dist/tools/utils.js +267 -0
  251. package/dist/tools/utils.js.map +1 -0
  252. package/dist/tools/vscodeCommands.d.ts +59 -0
  253. package/dist/tools/vscodeCommands.js +108 -0
  254. package/dist/tools/vscodeCommands.js.map +1 -0
  255. package/dist/tools/watchDiagnostics.d.ts +32 -0
  256. package/dist/tools/watchDiagnostics.js +87 -0
  257. package/dist/tools/watchDiagnostics.js.map +1 -0
  258. package/dist/tools/workspaceSettings.d.ts +67 -0
  259. package/dist/tools/workspaceSettings.js +102 -0
  260. package/dist/tools/workspaceSettings.js.map +1 -0
  261. package/dist/tools/workspaceSnapshots.d.ts +174 -0
  262. package/dist/tools/workspaceSnapshots.js +474 -0
  263. package/dist/tools/workspaceSnapshots.js.map +1 -0
  264. package/dist/transport.d.ts +57 -0
  265. package/dist/transport.js +417 -0
  266. package/dist/transport.js.map +1 -0
  267. package/dist/version.d.ts +2 -0
  268. package/dist/version.js +3 -0
  269. package/dist/version.js.map +1 -0
  270. package/dist/wsUtils.d.ts +9 -0
  271. package/dist/wsUtils.js +54 -0
  272. package/dist/wsUtils.js.map +1 -0
  273. package/package.json +69 -0
@@ -0,0 +1,417 @@
1
+ import { WebSocket } from "ws";
2
+ import { ErrorCodes } from "./errors.js";
3
+ import { BRIDGE_PROTOCOL_VERSION } from "./version.js";
4
+ import { BACKPRESSURE_THRESHOLD, safeSend } from "./wsUtils.js";
5
+ const TOOL_TIMEOUT_MS = 60_000; // 60s — prevents tools from blocking indefinitely
6
+ const MAX_CONCURRENT_TOOLS = 10;
7
+ const RATE_LIMIT_WINDOW_MS = 60_000; // 1 minute window
8
+ const RATE_LIMIT_MAX = 200; // max requests per window
9
+ // Supported MCP protocol versions, newest first.
10
+ // Extend this array when new protocol versions are ratified; keep oldest supported version last.
11
+ const SUPPORTED_VERSIONS = ["2025-11-25"];
12
+ const LOG_LEVELS = [
13
+ "debug",
14
+ "info",
15
+ "notice",
16
+ "warning",
17
+ "error",
18
+ "critical",
19
+ "alert",
20
+ "emergency",
21
+ ];
22
+ export class McpTransport {
23
+ logger;
24
+ tools = new Map();
25
+ serverInfo = {
26
+ name: "claude-ide-bridge",
27
+ version: BRIDGE_PROTOCOL_VERSION,
28
+ };
29
+ activeWs = null;
30
+ activeListener = null;
31
+ inFlightControllers = new Map();
32
+ initialized = false;
33
+ activeToolCalls = 0;
34
+ generation = 0; // incremented on each attach; stale handlers check this
35
+ // Ring buffer for O(1) sliding-window rate limiting — avoids array scan + splice
36
+ rateLimitBuf = new Float64Array(RATE_LIMIT_MAX); // initialised to 0 (epoch 1970, always outside window)
37
+ rateLimitHead = 0; // index of oldest entry / next write position
38
+ clientLogLevel = "warning";
39
+ activityLog = null;
40
+ isExtensionConnectedFn = null;
41
+ constructor(logger) {
42
+ this.logger = logger;
43
+ }
44
+ setExtensionConnectedFn(fn) {
45
+ this.isExtensionConnectedFn = fn;
46
+ }
47
+ setActivityLog(log) {
48
+ this.activityLog = log;
49
+ }
50
+ registerTool(schema, handler, timeoutMs) {
51
+ if (!/^[a-zA-Z0-9_]+$/.test(schema.name)) {
52
+ throw new Error(`Invalid tool name "${schema.name}": must contain only letters, digits, and underscores`);
53
+ }
54
+ this.tools.set(schema.name, { schema, handler, timeoutMs });
55
+ }
56
+ detach() {
57
+ // Remove listener from old WebSocket to prevent accumulation
58
+ if (this.activeWs && this.activeListener) {
59
+ this.activeWs.removeListener("message", this.activeListener);
60
+ this.activeListener = null;
61
+ }
62
+ // Abort all in-flight tool calls to prevent resource leaks
63
+ for (const [, controller] of this.inFlightControllers) {
64
+ controller.abort();
65
+ }
66
+ this.inFlightControllers.clear();
67
+ this.activeWs = null;
68
+ this.initialized = false;
69
+ this.activeToolCalls = 0;
70
+ this.rateLimitBuf.fill(0);
71
+ this.rateLimitHead = 0;
72
+ this.clientLogLevel = "warning";
73
+ }
74
+ attach(ws) {
75
+ this.activeWs = ws;
76
+ this.initialized = false; // Force re-initialization on every new connection
77
+ const gen = ++this.generation;
78
+ const listener = async (data) => {
79
+ // Ignore messages from superseded connections
80
+ if (gen !== this.generation)
81
+ return;
82
+ try {
83
+ const raw = JSON.parse(data.toString("utf-8"));
84
+ if (typeof raw !== "object" || raw === null) {
85
+ this.logger.debug("Ignoring non-object JSON-RPC message");
86
+ return;
87
+ }
88
+ if (Array.isArray(raw)) {
89
+ await safeSend(ws, JSON.stringify({
90
+ jsonrpc: "2.0",
91
+ id: null,
92
+ error: {
93
+ code: ErrorCodes.INVALID_REQUEST,
94
+ message: "Batch requests are not supported",
95
+ },
96
+ }), this.logger);
97
+ return;
98
+ }
99
+ const msg = raw;
100
+ this.logger.debug(`<-- ${msg.method} (id=${msg.id})`);
101
+ if (!msg.method)
102
+ return;
103
+ // Notifications (no id)
104
+ if (msg.id === undefined || msg.id === null) {
105
+ if (msg.method === "notifications/cancelled") {
106
+ const requestId = msg.params
107
+ ?.requestId;
108
+ if (requestId !== undefined) {
109
+ const controller = this.inFlightControllers.get(requestId);
110
+ if (controller)
111
+ controller.abort();
112
+ }
113
+ }
114
+ else if (msg.method === "notifications/initialized") {
115
+ this.initialized = true;
116
+ this.logger.debug("Client initialized");
117
+ }
118
+ return;
119
+ }
120
+ // Rate limiting — O(1) ring buffer sliding window.
121
+ // rateLimitBuf holds the last RATE_LIMIT_MAX timestamps in insertion order.
122
+ // rateLimitHead points to the oldest entry (next write position).
123
+ // If the oldest timestamp is still within the window, all 200 slots are
124
+ // occupied by recent requests → limit exceeded.
125
+ const now = Date.now();
126
+ const oldest = this.rateLimitBuf[this.rateLimitHead];
127
+ if (oldest > now - RATE_LIMIT_WINDOW_MS) {
128
+ this.logger.warn(`Rate limit exceeded: ${RATE_LIMIT_MAX} requests in ${RATE_LIMIT_WINDOW_MS}ms`);
129
+ await safeSend(ws, JSON.stringify({
130
+ jsonrpc: "2.0",
131
+ id: msg.id,
132
+ error: {
133
+ code: ErrorCodes.INTERNAL_ERROR,
134
+ message: "Rate limit exceeded — too many requests",
135
+ },
136
+ }), this.logger);
137
+ return;
138
+ }
139
+ // Record this timestamp and advance the head pointer
140
+ this.rateLimitBuf[this.rateLimitHead] = now;
141
+ this.rateLimitHead = (this.rateLimitHead + 1) % RATE_LIMIT_MAX;
142
+ let response;
143
+ switch (msg.method) {
144
+ case "initialize": {
145
+ const clientParams = msg.params;
146
+ const clientVersion = clientParams?.protocolVersion;
147
+ const negotiatedVersion = clientVersion && SUPPORTED_VERSIONS.includes(clientVersion)
148
+ ? clientVersion
149
+ : SUPPORTED_VERSIONS[0];
150
+ if (clientVersion && !SUPPORTED_VERSIONS.includes(clientVersion)) {
151
+ this.logger.warn(`Client requested unsupported protocol version ${clientVersion}, responding with ${negotiatedVersion}`);
152
+ }
153
+ this.initialized = false; // Reset — waiting for notifications/initialized
154
+ response = {
155
+ jsonrpc: "2.0",
156
+ id: msg.id,
157
+ result: {
158
+ protocolVersion: negotiatedVersion,
159
+ capabilities: {
160
+ tools: { listChanged: true },
161
+ logging: {},
162
+ },
163
+ serverInfo: this.serverInfo,
164
+ },
165
+ };
166
+ break;
167
+ }
168
+ case "tools/list": {
169
+ if (!this.initialized) {
170
+ response = {
171
+ jsonrpc: "2.0",
172
+ id: msg.id,
173
+ error: {
174
+ code: ErrorCodes.INVALID_REQUEST,
175
+ message: "Not initialized — send initialize first",
176
+ },
177
+ };
178
+ break;
179
+ }
180
+ const extConnected = this.isExtensionConnectedFn?.() ?? true;
181
+ response = {
182
+ jsonrpc: "2.0",
183
+ id: msg.id,
184
+ result: {
185
+ tools: Array.from(this.tools.values())
186
+ .filter((t) => !t.schema.extensionRequired || extConnected)
187
+ .map((t) => t.schema),
188
+ },
189
+ };
190
+ break;
191
+ }
192
+ case "logging/setLevel": {
193
+ const levelParam = msg.params?.level;
194
+ if (levelParam && LOG_LEVELS.includes(levelParam)) {
195
+ this.clientLogLevel = levelParam;
196
+ this.logger.debug(`Client log level set to: ${levelParam}`);
197
+ }
198
+ response = { jsonrpc: "2.0", id: msg.id, result: {} };
199
+ break;
200
+ }
201
+ case "tools/call": {
202
+ if (!this.initialized) {
203
+ response = {
204
+ jsonrpc: "2.0",
205
+ id: msg.id,
206
+ error: {
207
+ code: ErrorCodes.INVALID_REQUEST,
208
+ message: "Not initialized — send initialize first",
209
+ },
210
+ };
211
+ break;
212
+ }
213
+ // Concurrent tool-call limit
214
+ if (this.activeToolCalls >= MAX_CONCURRENT_TOOLS) {
215
+ response = {
216
+ jsonrpc: "2.0",
217
+ id: msg.id,
218
+ result: {
219
+ content: [
220
+ {
221
+ type: "text",
222
+ text: `Too many concurrent tool calls (max ${MAX_CONCURRENT_TOOLS}). Retry after current calls complete.`,
223
+ },
224
+ ],
225
+ isError: true,
226
+ },
227
+ };
228
+ break;
229
+ }
230
+ const params = msg.params;
231
+ const tool = this.tools.get(params.name);
232
+ if (!tool) {
233
+ response = {
234
+ jsonrpc: "2.0",
235
+ id: msg.id,
236
+ error: {
237
+ code: ErrorCodes.TOOL_NOT_FOUND,
238
+ message: "Tool not found",
239
+ data: params.name,
240
+ },
241
+ };
242
+ }
243
+ else {
244
+ const startTime = Date.now();
245
+ const callId = Math.random().toString(36).slice(2, 10);
246
+ const callLog = this.logger.child({ tool: params.name, callId });
247
+ let timedOut = false;
248
+ let handlerPromise = null;
249
+ try {
250
+ const toolArgs = params.arguments ?? {};
251
+ if (typeof toolArgs !== "object" ||
252
+ toolArgs === null ||
253
+ Array.isArray(toolArgs)) {
254
+ response = {
255
+ jsonrpc: "2.0",
256
+ id: msg.id,
257
+ error: {
258
+ code: ErrorCodes.INVALID_PARAMS,
259
+ message: "Tool arguments must be a JSON object",
260
+ },
261
+ };
262
+ break;
263
+ }
264
+ callLog.debug(`Calling tool: ${params.name}`);
265
+ this.logger.event("tool_call", { tool: params.name, callId });
266
+ const controller = new AbortController();
267
+ this.inFlightControllers.set(msg.id, controller);
268
+ // Build progress callback if client provided a progressToken
269
+ const progressToken = params._meta?.progressToken;
270
+ const progressFn = progressToken !== undefined
271
+ ? (progress, total, message) => this.sendProgress(ws, progressToken, progress, total, message)
272
+ : undefined;
273
+ this.activeToolCalls++;
274
+ let timeoutHandle;
275
+ try {
276
+ handlerPromise = tool.handler(toolArgs, controller.signal, progressFn);
277
+ const effectiveTimeout = tool.timeoutMs ?? TOOL_TIMEOUT_MS;
278
+ const timeoutPromise = new Promise((_, reject) => {
279
+ timeoutHandle = setTimeout(() => {
280
+ timedOut = true;
281
+ controller.abort();
282
+ reject(new Error(`Tool "${params.name}" timed out after ${effectiveTimeout}ms`));
283
+ }, effectiveTimeout);
284
+ });
285
+ const result = await Promise.race([
286
+ handlerPromise,
287
+ timeoutPromise,
288
+ ]);
289
+ const durationMs = Date.now() - startTime;
290
+ this.activityLog?.record(params.name, durationMs, "success");
291
+ callLog.debug(`Tool completed in ${durationMs}ms`);
292
+ response = { jsonrpc: "2.0", id: msg.id, result };
293
+ }
294
+ finally {
295
+ if (timeoutHandle !== undefined)
296
+ clearTimeout(timeoutHandle);
297
+ this.inFlightControllers.delete(msg.id);
298
+ // Only decrement if we're still on the same generation;
299
+ // detach() already reset activeToolCalls for new connections.
300
+ if (gen === this.generation) {
301
+ this.activeToolCalls = Math.max(0, this.activeToolCalls - 1);
302
+ }
303
+ }
304
+ }
305
+ catch (err) {
306
+ // MCP spec: tool execution errors are returned as successful
307
+ // JSON-RPC responses with isError: true in the content, NOT as
308
+ // JSON-RPC error responses. This lets the LLM understand and
309
+ // potentially recover from tool failures.
310
+ const message = err instanceof Error ? err.message : String(err);
311
+ callLog.error(`Tool ${params.name} failed: ${message}`);
312
+ this.activityLog?.record(params.name, Date.now() - startTime, "error", message);
313
+ response = {
314
+ jsonrpc: "2.0",
315
+ id: msg.id,
316
+ result: {
317
+ content: [{ type: "text", text: message }],
318
+ isError: true,
319
+ },
320
+ };
321
+ // Track zombie tool completion after timeout
322
+ if (timedOut && handlerPromise) {
323
+ handlerPromise
324
+ .then(() => {
325
+ this.logger.warn(`Zombie tool "${params.name}" completed ${Date.now() - startTime}ms after start (timed out at ${tool.timeoutMs ?? TOOL_TIMEOUT_MS}ms)`);
326
+ })
327
+ .catch(() => {
328
+ // Already logged the timeout error above; suppress the zombie's error
329
+ });
330
+ }
331
+ }
332
+ }
333
+ break;
334
+ }
335
+ case "ping":
336
+ response = { jsonrpc: "2.0", id: msg.id, result: {} };
337
+ break;
338
+ default:
339
+ response = {
340
+ jsonrpc: "2.0",
341
+ id: msg.id,
342
+ error: {
343
+ code: ErrorCodes.METHOD_NOT_FOUND,
344
+ message: `Method not found: ${msg.method}`,
345
+ },
346
+ };
347
+ }
348
+ this.logger.debug(`--> response for ${msg.method}`);
349
+ const sent = await safeSend(ws, JSON.stringify(response), this.logger);
350
+ if (!sent) {
351
+ this.logger.warn(`Response for ${msg.method} (id=${msg.id}) dropped — socket closed`);
352
+ }
353
+ }
354
+ catch (err) {
355
+ this.logger.error(`Failed to handle message: ${err}`);
356
+ }
357
+ };
358
+ this.activeListener = listener;
359
+ ws.on("message", listener);
360
+ }
361
+ /** Send progress notification for a long-running tool */
362
+ sendProgress(ws, progressToken, progress, total, message) {
363
+ const msg = {
364
+ jsonrpc: "2.0",
365
+ method: "notifications/progress",
366
+ params: {
367
+ progressToken,
368
+ progress,
369
+ ...(total !== undefined && { total }),
370
+ ...(message !== undefined && { message }),
371
+ },
372
+ };
373
+ if (ws.readyState === WebSocket.OPEN &&
374
+ ws.bufferedAmount < BACKPRESSURE_THRESHOLD) {
375
+ try {
376
+ ws.send(JSON.stringify(msg));
377
+ }
378
+ catch {
379
+ /* best-effort */
380
+ }
381
+ }
382
+ }
383
+ /** Send a log message to the MCP client (respects clientLogLevel) */
384
+ sendLogMessage(level, loggerName, data) {
385
+ if (!this.activeWs || this.activeWs.readyState !== WebSocket.OPEN)
386
+ return;
387
+ // Only send if the message level is at or above the client's requested level
388
+ const msgIdx = LOG_LEVELS.indexOf(level);
389
+ const clientIdx = LOG_LEVELS.indexOf(this.clientLogLevel);
390
+ if (msgIdx < clientIdx)
391
+ return;
392
+ const msg = {
393
+ jsonrpc: "2.0",
394
+ method: "notifications/message",
395
+ params: { level, logger: loggerName, data },
396
+ };
397
+ try {
398
+ this.activeWs.send(JSON.stringify(msg));
399
+ }
400
+ catch {
401
+ /* best-effort */
402
+ }
403
+ }
404
+ /** Send a server-initiated notification */
405
+ static sendNotification(ws, method, params, logger) {
406
+ const msg = { jsonrpc: "2.0", method, params };
407
+ if (ws.readyState === WebSocket.OPEN) {
408
+ try {
409
+ ws.send(JSON.stringify(msg));
410
+ }
411
+ catch (err) {
412
+ logger?.warn(`Failed to send notification ${method}: ${err}`);
413
+ }
414
+ }
415
+ }
416
+ }
417
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ /** Shared protocol version between the bridge server and the VS Code extension. */
2
+ export declare const BRIDGE_PROTOCOL_VERSION = "1.1.0";
@@ -0,0 +1,3 @@
1
+ /** Shared protocol version between the bridge server and the VS Code extension. */
2
+ export const BRIDGE_PROTOCOL_VERSION = "1.1.0";
3
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAO,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { WebSocket } from "ws";
2
+ import type { Logger } from "./logger.js";
3
+ export declare const BACKPRESSURE_THRESHOLD = 1048576;
4
+ export declare const DRAIN_TIMEOUT_MS = 5000;
5
+ /** Wait for the WebSocket send buffer to drain below threshold */
6
+ export declare function waitForDrain(ws: WebSocket, logger: Logger, label?: string): Promise<void>;
7
+ /** Send a JSON-RPC message with backpressure awareness.
8
+ * Returns false if the message was not sent (socket not open). */
9
+ export declare function safeSend(ws: WebSocket, data: string, logger: Logger): Promise<boolean>;
@@ -0,0 +1,54 @@
1
+ import { WebSocket } from "ws";
2
+ export const BACKPRESSURE_THRESHOLD = 1_048_576; // 1MB — pause sending until drained
3
+ export const DRAIN_TIMEOUT_MS = 5_000; // Don't wait forever for drain
4
+ /** Wait for the WebSocket send buffer to drain below threshold */
5
+ export function waitForDrain(ws, logger, label = "Backpressure") {
6
+ if (ws.bufferedAmount < BACKPRESSURE_THRESHOLD) {
7
+ return Promise.resolve();
8
+ }
9
+ logger.warn(`${label}: waiting for drain (buffered: ${ws.bufferedAmount} bytes)`);
10
+ return new Promise((resolve) => {
11
+ const raw = ws._socket;
12
+ if (!raw) {
13
+ resolve();
14
+ return;
15
+ }
16
+ raw.setMaxListeners(Math.max(raw.getMaxListeners(), 20));
17
+ let settled = false;
18
+ const settle = () => {
19
+ if (settled)
20
+ return;
21
+ settled = true;
22
+ clearTimeout(drainTimeout);
23
+ raw.removeListener("drain", onDrain);
24
+ raw.removeListener("close", onClose);
25
+ resolve();
26
+ };
27
+ const onDrain = () => settle();
28
+ const onClose = () => settle();
29
+ const drainTimeout = setTimeout(() => {
30
+ logger.warn(`${label}: waitForDrain timed out`);
31
+ settle();
32
+ }, DRAIN_TIMEOUT_MS);
33
+ raw.once("drain", onDrain);
34
+ raw.once("close", onClose);
35
+ });
36
+ }
37
+ /** Send a JSON-RPC message with backpressure awareness.
38
+ * Returns false if the message was not sent (socket not open). */
39
+ export async function safeSend(ws, data, logger) {
40
+ if (ws.readyState !== WebSocket.OPEN)
41
+ return false;
42
+ await waitForDrain(ws, logger);
43
+ if (ws.readyState !== WebSocket.OPEN)
44
+ return false;
45
+ try {
46
+ ws.send(data);
47
+ return true;
48
+ }
49
+ catch (err) {
50
+ logger.error(`Failed to send: ${err}`);
51
+ return false;
52
+ }
53
+ }
54
+ //# sourceMappingURL=wsUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wsUtils.js","sourceRoot":"","sources":["../src/wsUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAG/B,MAAM,CAAC,MAAM,sBAAsB,GAAG,SAAS,CAAC,CAAC,oCAAoC;AACrF,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC,CAAC,+BAA+B;AAEtE,kEAAkE;AAClE,MAAM,UAAU,YAAY,CAC1B,EAAa,EACb,MAAc,EACd,KAAK,GAAG,cAAc;IAEtB,IAAI,EAAE,CAAC,cAAc,GAAG,sBAAsB,EAAE,CAAC;QAC/C,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IACD,MAAM,CAAC,IAAI,CACT,GAAG,KAAK,kCAAkC,EAAE,CAAC,cAAc,SAAS,CACrE,CAAC;IACF,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QACnC,MAAM,GAAG,GAAI,EAAsC,CAAC,OAAO,CAAC;QAC5D,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QACD,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QACzD,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,YAAY,CAAC,YAAY,CAAC,CAAC;YAC3B,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACrC,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACrC,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC;QAC/B,MAAM,YAAY,GAAG,UAAU,CAAC,GAAG,EAAE;YACnC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,0BAA0B,CAAC,CAAC;YAChD,MAAM,EAAE,CAAC;QACX,CAAC,EAAE,gBAAgB,CAAC,CAAC;QACrB,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC3B,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;mEACmE;AACnE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,EAAa,EACb,IAAY,EACZ,MAAc;IAEd,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACnD,MAAM,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC/B,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACnD,IAAI,CAAC;QACH,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,mBAAmB,GAAG,EAAE,CAAC,CAAC;QACvC,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "claude-ide-bridge",
3
+ "version": "1.1.0",
4
+ "description": "Standalone MCP bridge for Claude Code IDE integration with any editor — 115+ tools for LSP, debugging, terminals, Git, GitHub, and more",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "claude-ide-bridge": "dist/index.js"
9
+ },
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "claude",
13
+ "claude-code",
14
+ "mcp",
15
+ "ide",
16
+ "vscode",
17
+ "lsp",
18
+ "debugging",
19
+ "terminal",
20
+ "git",
21
+ "github",
22
+ "ai",
23
+ "coding-assistant"
24
+ ],
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/Oolab-labs/claude-ide-bridge"
28
+ },
29
+ "homepage": "https://github.com/Oolab-labs/claude-ide-bridge#readme",
30
+ "bugs": {
31
+ "url": "https://github.com/Oolab-labs/claude-ide-bridge/issues"
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "!dist/__tests__",
36
+ "!dist/**/__tests__",
37
+ "LICENSE",
38
+ "README.md"
39
+ ],
40
+ "engines": {
41
+ "node": ">=20.0.0"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc",
45
+ "dev": "tsx src/index.ts",
46
+ "start": "node dist/index.js",
47
+ "test": "vitest run",
48
+ "test:coverage": "vitest run --coverage",
49
+ "test:watch": "vitest",
50
+ "lint": "biome check .",
51
+ "lint:fix": "biome check --write .",
52
+ "typecheck": "tsc --noEmit",
53
+ "prepublishOnly": "npm run build",
54
+ "remote": "bash scripts/start-remote.sh",
55
+ "start-all": "bash scripts/start-all.sh"
56
+ },
57
+ "dependencies": {
58
+ "ws": "^8.18.0"
59
+ },
60
+ "devDependencies": {
61
+ "@biomejs/biome": "^1.9.0",
62
+ "@types/ws": "^8.5.0",
63
+ "@types/node": "^22.0.0",
64
+ "typescript": "^5.7.0",
65
+ "tsx": "^4.0.0",
66
+ "vitest": "^3.0.0",
67
+ "@vitest/coverage-v8": "^3.0.0"
68
+ }
69
+ }