browxai 0.7.0 → 0.8.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 (2) hide show
  1. package/dist/cli/serve.js +38 -21
  2. package/package.json +1 -1
package/dist/cli/serve.js CHANGED
@@ -14,8 +14,9 @@
14
14
  // server, identical to stdio.
15
15
  import { chmodSync, existsSync, unlinkSync } from "node:fs";
16
16
  import { createServer as createNetServer } from "node:net";
17
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
18
- import { createServer } from "../server.js";
17
+ import { Server as McpServer } from "@modelcontextprotocol/sdk/server/index.js";
18
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
19
+ import { createServer, NAME, VERSION } from "../server.js";
19
20
  import { SocketTransport } from "../sdk/socket-transport.js";
20
21
  import { log } from "../util/logging.js";
21
22
  function parseFlagString(args, flag) {
@@ -54,29 +55,45 @@ export async function startServeForTests(opts) {
54
55
  }
55
56
  }
56
57
  const browxai = await createServer({ attachCdp: opts.attachCdp, headless: opts.headless });
57
- // We share ONE McpServer per attached client connection by creating a
58
- // fresh adapter per connection. The simplest correct approach: each
59
- // connection gets its OWN McpServer instance that re-registers against
60
- // the SAME `browxai.handlers` map. Since `handlers` is shared,
61
- // session-state isolation is the SessionRegistry's job (already true),
62
- // and the per-connection McpServer just routes the JSON-RPC.
63
- //
64
- // Implementation detail: re-creating tools from scratch on every connect
65
- // would require duplicating server.ts's input schemas. Instead we expose
66
- // a thin tool-call proxy: the connection's McpServer registers a single
67
- // catch-all? No — the MCP SDK requires tools to be registered by name.
68
- // The cleanest path is: register the same tool names that the in-process
69
- // server already has, with `inputSchema: { additionalProperties: true }`
70
- // (open schema — the underlying handler still validates). Each tool's
71
- // handler delegates to `browxai.handlers[name]`.
58
+ // Each attached client connection gets its OWN low-level MCP Server that
59
+ // routes JSON-RPC straight to the SHARED `browxai.handlers` map (session-state
60
+ // isolation is the SessionRegistry's job, already true). We deliberately do
61
+ // NOT use the high-level `McpServer.registerTool` with per-tool schemas: that
62
+ // path validates/strips arguments against the declared schema, and an empty
63
+ // schema dropped every argument (the `navigate`-hangs-forever bug). The
64
+ // low-level CallTool handler forwards raw arguments, exactly like the
65
+ // in-process transport.
72
66
  const liveConnections = new Set();
73
67
  const netServer = createNetServer((socket) => {
74
68
  void (async () => {
75
69
  try {
76
- const mcp = new McpServer({ name: "browxai", version: "0.2.3" });
77
- for (const [name, handler] of Object.entries(browxai.handlers)) {
78
- mcp.registerTool(name, { description: `browxai/${name}`, inputSchema: {} }, async (args) => handler(args));
79
- }
70
+ // Route JSON-RPC straight to the in-process handler map with the RAW
71
+ // arguments. The previous `McpServer.registerTool(name, { inputSchema:
72
+ // {} }, …)` path validated each call against an EMPTY object schema,
73
+ // which silently STRIPPED every argument — so e.g. `navigate` reached
74
+ // its handler with no `url` and hung the whole call (load wait that
75
+ // never resolves). The per-tool handler does its own validation, so the
76
+ // socket layer must pass args through untouched, exactly like the
77
+ // in-process transport (`src/sdk/transport-in-process.ts`).
78
+ const mcp = new McpServer({ name: NAME, version: VERSION }, { capabilities: { tools: {} } });
79
+ mcp.setRequestHandler(ListToolsRequestSchema, () => ({
80
+ tools: Object.keys(browxai.handlers).map((name) => ({
81
+ name,
82
+ description: `browxai/${name}`,
83
+ // Open schema — NOT `{}` (which strips args). The handler validates.
84
+ inputSchema: { type: "object", additionalProperties: true },
85
+ })),
86
+ }));
87
+ mcp.setRequestHandler(CallToolRequestSchema, async (request) => {
88
+ const handler = browxai.handlers[request.params.name];
89
+ if (!handler) {
90
+ return {
91
+ isError: true,
92
+ content: [{ type: "text", text: `browxai: unknown tool "${request.params.name}"` }],
93
+ };
94
+ }
95
+ return await handler(request.params.arguments ?? {});
96
+ });
80
97
  const transport = new SocketTransport(socket);
81
98
  await mcp.connect(transport);
82
99
  const conn = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browxai",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "MCP-native, model-agnostic, agentic-first, multi-engine browser-control server.",
5
5
  "author": "Kalebtec <security@kalebtec.com>",
6
6
  "license": "MIT",