// HTML home page and JSON API docs for the browser-mcp gateway. // All examples are built from the visitor's Host header so IP/port always match. export function renderHome(baseUrl, token) { // B is a placeholder element filled by client-side JS with the effective base // URL (visitor's host by default, overridable in the settings bar). const B = ''; return ` browser-mcp gateway

browser-mcp gateway

本网关把本机 Chrome 浏览器(通过 browser-mcp 扩展)暴露到局域网。页面所有示例基于 ${B} 生成(默认为你当前的访问地址,可在上方设置栏修改)。

1. 认证

所有接口都需要认证,二选一:

2. 查看 API 文档

HTML 文档:${B}/docs | JSON 版本:${B}/docs.json

3. REST API 使用(/api)

方法路径说明
GET/api/health存活与上游状态
GET/api/tools列出全部浏览器工具(40 个)
POST/api/call调用工具,body 为 {"name": "工具名", "arguments": {...}}

示例:打开网页并读取内容

curl -s -X POST ${B}/api/call \\
  -H "Authorization: Bearer ${token}" \\
  -H "Content-Type: application/json" \\
  -d '{"name":"browser_navigate","arguments":{"url":"https://example.com"}}'

curl -s -X POST ${B}/api/call \\
  -H "Authorization: Bearer ${token}" \\
  -H "Content-Type: application/json" \\
  -d '{"name":"browser_get_page_content","arguments":{"format":"text"}}'

返回格式:MCP 标准结果 {"content":[{"type":"text","text":"..."}]},错误时 HTTP 状态码非 200 且 body 为 {"error":"..."}。

4. 添加 MCP(/mcp 端点)

MCP 端点地址:${B}/mcp(Streamable HTTP 传输,无状态模式)。

Kimi Code

编辑 ~/.kimi-code/mcp.json,在 mcpServers 中加入:

"browser-remote": {
  "url": "${B}/mcp",
  "headers": { "Authorization": "Bearer ${token}" }
}

保存后新建会话生效(已打开的会话不会加载新增的 server)。也可以在 TUI 里用 /mcp-config 交互式添加。

Claude Code

claude mcp add --transport http browser-remote ${B}/mcp \\
  --header "Authorization: Bearer ${token}"

5. 一句话部署

Linux / macOS(写入 Kimi Code 用户级配置):

node -e "const f=process.env.HOME+'/.kimi-code/mcp.json',j=require(f);j.mcpServers['browser-remote']={url:'${B}/mcp',headers:{Authorization:'Bearer ${token}'}};require('fs').writeFileSync(f,JSON.stringify(j,null,2))"

Windows PowerShell:

$f="$env:USERPROFILE\\.kimi-code\\mcp.json"; $j=Get-Content $f -Raw | ConvertFrom-Json; $j.mcpServers | Add-Member -NotePropertyName browser-remote -NotePropertyValue @{url='${B}/mcp';headers=@{Authorization='Bearer ${token}'}} -Force; $j | ConvertTo-Json -Depth 10 | Set-Content $f -Encoding UTF8
注意:远程调用驱动的是网关所在机器的 Chrome,请保持该机器的 browser-mcp 扩展处于连接状态。Token 即全部权限,请勿泄露到不可信网络。
`; } export function renderDocs(baseUrl, token) { const auth = { type: 'bearer', header: 'Authorization: Bearer ', alt: 'query param ?token=' }; return { name: 'browser-mcp-gateway', version: '1.0.0', description: 'LAN gateway exposing the local browser-mcp (Agent360) browser over MCP Streamable HTTP and a simple REST API.', baseUrl, auth, endpoints: [ { method: 'GET', path: '/', description: 'HTML 使用说明页(认证、REST API 用法、MCP 接入、一句话部署)。', response: 'text/html', }, { method: 'GET', path: '/docs', description: 'HTML 格式的 API 文档(本页)。', response: 'text/html', }, { method: 'GET', path: '/docs.json', description: 'JSON 格式的 API 文档(机器可读)。', response: 'application/json', }, { method: 'GET', path: '/api/health', description: 'Liveness probe; reports whether the upstream browser-mcp stdio server is connected.', response: { ok: true, upstream: true }, example: `curl -s ${baseUrl}/api/health -H "Authorization: Bearer ${token}"`, }, { method: 'GET', path: '/api/tools', description: 'List all available browser tools (MCP tools/list).', response: { tools: [{ name: 'browser_navigate', description: '...', inputSchema: {} }] }, example: `curl -s ${baseUrl}/api/tools -H "Authorization: Bearer ${token}"`, }, { method: 'POST', path: '/api/call', description: 'Call a browser tool (MCP tools/call). Body: {"name": string, "arguments"?: object}.', request: { name: 'browser_navigate', arguments: { url: 'https://example.com' } }, response: { content: [{ type: 'text', text: '...' }] }, example: `curl -s -X POST ${baseUrl}/api/call -H "Authorization: Bearer ${token}" -H "Content-Type: application/json" -d '{"name":"browser_list_tabs","arguments":{}}'`, }, { method: 'POST', path: '/mcp', description: 'MCP Streamable HTTP endpoint (stateless; POST only). Point any MCP client here.', notes: 'Accept header must include application/json and text/event-stream per the MCP spec.', }, ], mcpClients: { 'kimi-code': { file: '~/.kimi-code/mcp.json', config: { 'browser-remote': { url: `${baseUrl}/mcp`, headers: { Authorization: `Bearer ${token}` } } }, note: 'Takes effect in new sessions; or use /mcp-config in the TUI.', }, 'claude-code': { oneLiner: `claude mcp add --transport http browser-remote ${baseUrl}/mcp --header "Authorization: Bearer ${token}"`, }, }, oneLinerDeploy: { posix: `node -e "const f=process.env.HOME+'/.kimi-code/mcp.json',j=require(f);j.mcpServers['browser-remote']={url:'${baseUrl}/mcp',headers:{Authorization:'Bearer ${token}'}};require('fs').writeFileSync(f,JSON.stringify(j,null,2))"`, powershell: `$f="$env:USERPROFILE\\.kimi-code\\mcp.json"; $j=Get-Content $f -Raw | ConvertFrom-Json; $j.mcpServers | Add-Member -NotePropertyName browser-remote -NotePropertyValue @{url='${baseUrl}/mcp';headers=@{Authorization='Bearer ${token}'}} -Force; $j | ConvertTo-Json -Depth 10 | Set-Content $f -Encoding UTF8`, }, errors: { 401: 'missing or wrong token', 400: 'bad request body', 404: 'unknown route', 503: 'upstream browser-mcp not connected (is the Chrome extension connected?)', }, }; } function esc(s) { return String(s).replace(/&/g, '&').replace(//g, '>'); } export function renderDocsHtml(baseUrl, token) { const d = renderDocs(baseUrl, token); const pre = (o) => `
${esc(typeof o === 'string' ? o : JSON.stringify(o, null, 2))}
`; const endpointRows = d.endpoints.map((e) => `${e.method}${e.path}${esc(e.description)}`, ).join('\n'); const endpointDetails = d.endpoints.map((e) => `

${e.method} ${e.path}

${esc(e.description)}

${e.notes ? `

${esc(e.notes)}

` : ''} ${e.request ? `

请求 body

${pre(e.request)}` : ''} ${e.response ? `

响应${typeof e.response === 'string' ? '(' + esc(e.response) + ')' : ' 示例'}

${pre(e.response)}` : ''} ${e.example ? `

示例

${pre(e.example)}` : ''}
`).join('\n'); const errorRows = Object.entries(d.errors).map(([code, msg]) => `${code}${esc(msg)}`, ).join('\n'); return ` API 文档 - browser-mcp gateway

${esc(d.name)} v${esc(d.version)}

${esc(d.description)}

Base URL:${esc(d.baseUrl)} | 返回使用说明 | JSON 版本

认证

HTTP 头:${esc(d.auth.header)},或 URL 参数:${esc(d.auth.alt)}

端点总览

${endpointRows}
方法路径说明

端点详情

${endpointDetails}

MCP 客户端接入

Kimi Code(${esc(d.mcpClients['kimi-code'].file)})

${pre(JSON.stringify({ mcpServers: d.mcpClients['kimi-code'].config }, null, 2))}

${esc(d.mcpClients['kimi-code'].note)}

Claude Code(一句话)

${pre(d.mcpClients['claude-code'].oneLiner)}

一句话部署(写入 Kimi Code 配置)

Linux / macOS

${pre(d.oneLinerDeploy.posix)}

Windows PowerShell

${pre(d.oneLinerDeploy.powershell)}

错误码

${errorRows}
状态码含义
`; } // Server-side JSON syntax highlighting for the /docs.json browser view. function highlightJson(obj) { const json = JSON.stringify(obj, null, 2); const re = /("(?:\\.|[^"\\])*")(\s*:)?|(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)\b|(true|false|null)\b/g; let out = ''; let last = 0; let m; while ((m = re.exec(json))) { out += esc(json.slice(last, m.index)); if (m[1] !== undefined) { if (m[2]) out += `${esc(m[1])}${esc(m[2])}`; else out += `${esc(m[1])}`; } else if (m[3] !== undefined) { out += `${esc(m[3])}`; } else { out += `${esc(m[4])}`; } last = m.index + m[0].length; } return out + esc(json.slice(last)); } export function renderJsonViewer(baseUrl, token, doc) { return ` docs.json - browser-mcp gateway

docs.json browser-mcp gateway API 文档(JSON)

浏览器访问自动格式化高亮显示;用 curl 或 Accept: application/json 请求可获取原始 JSON。 | 返回 HTML 文档 | 使用说明

${highlightJson(doc)}
`; }