Native Messaging Protocol
The native messaging host is the bridge between the Firefox extension and external tooling. It uses Firefox's standard native messaging protocol over stdin/stdout. ## Wire Format Every message is framed with a **4-byte little-endian unsigned integer** length prefix, followed by a UTF-8 JSON payload. ``` ┌──────────────────┬─────────────────────────────┐ │ Length (4 bytes) │ JSON payload (UTF-8) │ │ Little-endian │ { "command": "ping", ... } │ │ uint32 │ │ └──────────────────┴─────────────────────────────┘ ``` ### Reading a Message 1. Read exactly 4 bytes from stdin. 2. Interpret as a `uint32` in little-endian byte order — this is the payload length. 3. Read exactly that many bytes. 4. Decode as UTF-8 and parse as JSON. ### Writing a Message 1. Serialize the response object to a JSON string. 2. Encode as UTF-8 into a byte buffer. 3. Write a 4-byte little-endian `uint32` of the buffer length to stdout. 4. Write the buffer to stdout. ## Message Size Limits | Direction | Limit | Enforced by | |-----------|-------|-------------| | Host to Extension | **1 MB** | Native host (`protocol.js`) throws if exceeded | | Extension to Host | **4 GB** | Protocol spec (validated against `uint32` max) | | Socket buffer | **10 MB** | Native host memory guard | The 1 MB host-to-extension limit is the practical constraint. Screenshot data is kept under this limit through JPEG compression (60% quality) and downscaling (50% by default). ## Request Format Commands sent from the MCP server to the host (via Unix socket), then forwarded to the extension: ```json { "command": "navigate", "tabId": 42, "url": "https://example.com", "agentId": "agent_a1b2c3d4e5f6..._12345", "timeout": 30000 } ``` | Field | Required | Description | |-------|----------|-------------| | `command` | Yes | One of the whitelisted command names | | `tabId` | Varies | Target tab (required for most page interaction commands) | | `agentId` | Auto | Injected by MCP server; used for ownership checks | | `timeout` | No | Per-operation timeout in ms (5000-300000, default: 150000) | ## Response Format ```json { "success": true, "tabId": 42, "title": "Example Domain", "url": "https://example.com" } ``` Error responses: ```json { "success": false, "error": "OWNERSHIP: Cannot navigate tab 42 (owned by agent_e7f8...)" } ``` ## Per-Operation Timeouts All MCP tools accept an optional `timeout` parameter that controls how long the system waits for a response from Firefox. - **Minimum:** 5,000 ms (5 seconds) - **Maximum:** 300,000 ms (5 minutes) - **Default:** 150,000 ms (2.5 minutes) The timeout covers the full round-trip: MCP server to host, host to extension, extension processing, and the return path. If the timeout expires, the MCP server returns an error without waiting further. ## Host Manifest The native messaging host is registered with Firefox through a JSON manifest file. **Location:** - macOS: `~/.mozilla/native-messaging-hosts/claudezilla.json` - Linux: `~/.mozilla/native-messaging-hosts/claudezilla.json` - Windows: Registry key pointing to the manifest file **Manifest contents:** ```json { "name": "claudezilla", "description": "Claudezilla Native Messaging Host", "path": "/absolute/path/to/claudezilla/host/index.js", "type": "stdio", "allowed_extensions": ["claudezilla@boot.industries"] } ``` | Field | Description | |-------|-------------| | `name` | Must match the name used in `browser.runtime.connectNative()` | | `path` | Absolute path to the host executable (the Node.js entry point) | | `type` | Always `stdio` — communication over stdin/stdout | | `allowed_extensions` | Only the Claudezilla extension ID is permitted to connect | ## Unix Socket (Host to MCP Server) The native host also runs a Unix domain socket server (or named pipe on Windows) for the MCP server to connect to. - **Path:** Platform-dependent, resolved by `ipc.js` (typically in `XDG_RUNTIME_DIR` or system temp) - **Auth:** 32-byte random hex token written to a file on host startup; MCP server reads and presents it on connection - **Permissions:** Socket and token file set to `0600` (owner-only access) The socket carries the same JSON message format but without the 4-byte length prefix — messages are newline-delimited JSON over the socket connection.The native messaging host is the bridge between the Firefox extension and external tooling. It uses Firefox’s standard native messaging protocol over stdin/stdout.
Wire Format
Section titled “Wire Format”Every message is framed with a 4-byte little-endian unsigned integer length prefix, followed by a UTF-8 JSON payload.
┌──────────────────┬─────────────────────────────┐│ Length (4 bytes) │ JSON payload (UTF-8) ││ Little-endian │ { "command": "ping", ... } ││ uint32 │ │└──────────────────┴─────────────────────────────┘Reading a Message
Section titled “Reading a Message”- Read exactly 4 bytes from stdin.
- Interpret as a
uint32in little-endian byte order — this is the payload length. - Read exactly that many bytes.
- Decode as UTF-8 and parse as JSON.
Writing a Message
Section titled “Writing a Message”- Serialize the response object to a JSON string.
- Encode as UTF-8 into a byte buffer.
- Write a 4-byte little-endian
uint32of the buffer length to stdout. - Write the buffer to stdout.
Message Size Limits
Section titled “Message Size Limits”| Direction | Limit | Enforced by |
|---|---|---|
| Host to Extension | 1 MB | Native host (protocol.js) throws if exceeded |
| Extension to Host | 4 GB | Protocol spec (validated against uint32 max) |
| Socket buffer | 10 MB | Native host memory guard |
The 1 MB host-to-extension limit is the practical constraint. Screenshot data is kept under this limit through JPEG compression (60% quality) and downscaling (50% by default).
Request Format
Section titled “Request Format”Commands sent from the MCP server to the host (via Unix socket), then forwarded to the extension:
{ "command": "navigate", "tabId": 42, "url": "https://example.com", "agentId": "agent_a1b2c3d4e5f6..._12345", "timeout": 30000}| Field | Required | Description |
|---|---|---|
command | Yes | One of the whitelisted command names |
tabId | Varies | Target tab (required for most page interaction commands) |
agentId | Auto | Injected by MCP server; used for ownership checks |
timeout | No | Per-operation timeout in ms (5000-300000, default: 150000) |
Response Format
Section titled “Response Format”{ "success": true, "tabId": 42, "title": "Example Domain", "url": "https://example.com"}Error responses:
{ "success": false, "error": "OWNERSHIP: Cannot navigate tab 42 (owned by agent_e7f8...)"}Per-Operation Timeouts
Section titled “Per-Operation Timeouts”All MCP tools accept an optional timeout parameter that controls how long the system waits for a response from Firefox.
- Minimum: 5,000 ms (5 seconds)
- Maximum: 300,000 ms (5 minutes)
- Default: 150,000 ms (2.5 minutes)
The timeout covers the full round-trip: MCP server to host, host to extension, extension processing, and the return path. If the timeout expires, the MCP server returns an error without waiting further.
Host Manifest
Section titled “Host Manifest”The native messaging host is registered with Firefox through a JSON manifest file.
Location:
- macOS:
~/.mozilla/native-messaging-hosts/claudezilla.json - Linux:
~/.mozilla/native-messaging-hosts/claudezilla.json - Windows: Registry key pointing to the manifest file
Manifest contents:
{ "name": "claudezilla", "description": "Claudezilla Native Messaging Host", "path": "/absolute/path/to/claudezilla/host/index.js", "type": "stdio", "allowed_extensions": ["claudezilla@boot.industries"]}| Field | Description |
|---|---|
name | Must match the name used in browser.runtime.connectNative() |
path | Absolute path to the host executable (the Node.js entry point) |
type | Always stdio — communication over stdin/stdout |
allowed_extensions | Only the Claudezilla extension ID is permitted to connect |
Unix Socket (Host to MCP Server)
Section titled “Unix Socket (Host to MCP Server)”The native host also runs a Unix domain socket server (or named pipe on Windows) for the MCP server to connect to.
- Path: Platform-dependent, resolved by
ipc.js(typically inXDG_RUNTIME_DIRor system temp) - Auth: 32-byte random hex token written to a file on host startup; MCP server reads and presents it on connection
- Permissions: Socket and token file set to
0600(owner-only access)
The socket carries the same JSON message format but without the 4-byte length prefix — messages are newline-delimited JSON over the socket connection.