// 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. 认证
所有接口都需要认证,二选一:
HTTP 头:Authorization: Bearer ${token}
URL 参数:?token=${token}(方便浏览器直接打开,例如 API 文档 )
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)}
端点总览
端点详情
${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)}
错误码
`;
}
// 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)}
`;
}