@chatpanel/bridge 0.10.1 → 0.10.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatpanel/bridge",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
4
4
  "type": "module",
5
5
  "description": "Local bridge that exposes the AI coding agents installed on your machine — Claude Code (CLI), Codex (CLI), and Gemini CLI — to the ChatPanel Chrome extension over a localhost SSE endpoint. Bring your own agent.",
6
6
  "keywords": [
@@ -17,7 +17,7 @@ import { spawn } from 'node:child_process';
17
17
  import { writeFile, unlink } from 'node:fs/promises';
18
18
  import os from 'node:os';
19
19
  import path from 'node:path';
20
- import { resolveClaude, buildSpawnSpec, isCompiledBinary } from '../env.js';
20
+ import { resolveClaude, buildSpawnSpec, isCompiledBinary, selfMcpStdio } from '../env.js';
21
21
 
22
22
  // Write base64 data-URL images to temp files. Claude Code reads them with its
23
23
  // Read tool (which feeds images to the model as vision), so we just reference the
@@ -93,6 +93,18 @@ function buildPrompt(messages) {
93
93
  return prompt;
94
94
  }
95
95
 
96
+ export function claudeMcpConfig(mcp) {
97
+ if (!mcp?.url || !Array.isArray(mcp.specs) || !mcp.specs.length) return null;
98
+ const serverName = mcp.serverName || 'chatpanel_browser';
99
+ const { command, args } = selfMcpStdio(mcp.url);
100
+ const toolNames = [...new Set(mcp.specs.map((s) => s?.name).filter(Boolean))];
101
+ return {
102
+ serverName,
103
+ config: { mcpServers: { [serverName]: { command, args } } },
104
+ allowedTools: toolNames.map((name) => `mcp__${serverName}__${name}`),
105
+ };
106
+ }
107
+
96
108
  // Spawn claude (however it resolves) and stream its stream-json output via
97
109
  // `emit`. Resolves with { streamedAny, resultText } once it closes 0. Returns
98
110
  // null (no spawn) when claude can't be resolved, so the caller can fall back.
@@ -198,19 +210,20 @@ export async function chat({ messages, system, options, images }, emit) {
198
210
  const tag = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
199
211
  const args = ['--print', '--output-format', 'stream-json', '--include-partial-messages', '--verbose'];
200
212
 
201
- // Browser-tools relay: ChatPanel hands this CLI the page-action tools over an
202
- // HTTP MCP server the bridge hosts (which relays each call to the extension).
213
+ // Browser-tools relay: ChatPanel hands this CLI the page-action tools through
214
+ // the bridge's stdio MCP proxy, which forwards each call to the per-chat HTTP
215
+ // MCP session and then to the extension.
203
216
  // options.mcp = { url, serverName, specs }. We pre-allow the tools so a headless
204
217
  // run doesn't block on approval, and merge alongside the user's own MCP servers.
205
218
  const mcpFiles = [];
206
219
  const mcpAllow = [];
207
- if (options.mcp?.url && Array.isArray(options.mcp.specs) && options.mcp.specs.length) {
208
- const serverName = options.mcp.serverName || 'chatpanel_browser';
220
+ const mcpConfig = claudeMcpConfig(options.mcp);
221
+ if (mcpConfig) {
209
222
  const cfgFile = path.join(os.tmpdir(), `chatpanel-mcp-${tag}.json`);
210
- await writeFile(cfgFile, JSON.stringify({ mcpServers: { [serverName]: { type: 'http', url: options.mcp.url } } }));
223
+ await writeFile(cfgFile, JSON.stringify(mcpConfig.config));
211
224
  mcpFiles.push(cfgFile);
212
225
  args.push('--mcp-config', cfgFile);
213
- for (const s of options.mcp.specs) mcpAllow.push(`mcp__${serverName}__${s.name}`);
226
+ mcpAllow.push(...mcpConfig.allowedTools);
214
227
  }
215
228
 
216
229
  // Gate writes/shell behind the chosen mode; otherwise restrict to read-only
package/src/server.js CHANGED
@@ -30,7 +30,7 @@ import { callLocalMcp } from './mcp-local.js';
30
30
  // Hardcoded (not read from package.json) so it survives Bun's single-file
31
31
  // --compile, where package.json isn't on a readable FS. CI fails the publish if
32
32
  // this drifts from package.json, so the two can't silently diverge.
33
- const VERSION = '0.10.1';
33
+ const VERSION = '0.10.2';
34
34
  const HOST = process.env.CHATPANEL_BRIDGE_HOST || '127.0.0.1';
35
35
  const PORT = Number(process.env.CHATPANEL_BRIDGE_PORT) || 4319;
36
36