Maho MCP Server
maho mcp is the stdio entry point for using Maho Browser as an MCP
(Model Context Protocol) tool server from another AI application.
From Claude Desktop, Cursor, or another MCP host, the configuration is simply:
run the maho executable with the mcp argument. Maho then exposes browser
tabs, navigation, page extraction, history/bookmark operations, and session
coordination as MCP tools.
Architecture
Section titled “Architecture”Maho keeps the privileged server logic inside the browser process. The CLI is the stdio-facing adapter used by MCP clients:
Claude Desktop / Cursor / MCP host | | stdio v maho mcp | | local browser IPC v Maho Browser MCP server | +--> tabs / navigation / page tools +--> history / bookmarks +--> policy / approvals / redactionThere is no TCP listener and no public HTTP endpoint. Quitting Maho removes the
browser-side service; maho mcp is not a daemon that keeps a browser API alive
after the Browser exits.
Run the stdio server
Section titled “Run the stdio server”The command is:
maho mcpNormally you do not run it in an interactive terminal. The MCP host launches it as a child process and owns stdin/stdout. Starting it manually is useful only for process/path troubleshooting; a healthy stdio server may simply wait for MCP input.
Claude Desktop
Section titled “Claude Desktop”Claude Desktop reads MCP server entries from claude_desktop_config.json.
On macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonOn Windows:
%APPDATA%\Claude\claude_desktop_config.jsonAdd Maho under mcpServers:
{ "mcpServers": { "maho": { "command": "maho", "args": ["mcp"] } }}If the CLI is not on the GUI application’s PATH, use an absolute path:
{ "mcpServers": { "maho": { "command": "/absolute/path/to/maho", "args": ["mcp"] } }}Restart Claude Desktop after changing the config. The client should enumerate Maho’s tools during MCP initialization.
A low-risk first test is to ask Claude to list your open Maho tabs. That maps to
browser_tab_list and does not require navigating to a new domain.
Cursor
Section titled “Cursor”Cursor can use the same stdio definition. Add a Maho MCP server through Cursor’s
MCP settings, or use the JSON MCP configuration for the scope you want (for
example a project .cursor/mcp.json):
{ "mcpServers": { "maho": { "command": "maho", "args": ["mcp"] } }}Restart/reload Cursor after changing MCP configuration, then confirm the Maho server is enabled and its tools are visible.
A useful smoke-test prompt is:
Use the Maho browser tools to list my open tabs. Do not navigate or close anything.Once tool discovery works, try a read-only page request before a mutating action:
Read the visible text from the active Maho tab and summarize it. Do not navigate.Exposed browser tools
Section titled “Exposed browser tools”Maho’s browser MCP registry is organized by capability. Tools are standard MCP
tools/list / tools/call entries and return JSON-bearing tool content.
| Tool | Purpose |
|---|---|
browser_tab_list | List open tabs. |
browser_tab_get | Get details for one tab. |
browser_tab_new | Open a new tab. |
browser_tab_close | Close a tab. |
Navigation and domain policy
Section titled “Navigation and domain policy”| Tool | Purpose |
|---|---|
browser_navigate | Navigate a tab to a URL, subject to the session’s allowed-domain policy. |
browser_set_allowed_domains | Set/update the session-scoped domain allowlist used for navigation. |
Page content
Section titled “Page content”| Tool | Purpose |
|---|---|
browser_page_content | Return full page content in the requested supported representation. |
browser_page_text | Return visible/readable page text. |
browser_search_in_page | Search within page text. |
browser_page_context | Return high-level page context such as title/URL and extracted document metadata. |
page_query_selector | Resolve a CSS selector to a node reference. |
page_get_text | Read text from a resolved node. |
page_get_attribute | Read an attribute from a resolved node. |
page_wait_for_selector | Wait until a selector resolves. |
History and bookmarks
Section titled “History and bookmarks”| Tool | Purpose |
|---|---|
browser_history_search | Search local browsing history. |
browser_bookmarks_search | Search bookmarks. |
browser_bookmark_create | Create a bookmark. |
Session coordination
Section titled “Session coordination”| Tool | Purpose |
|---|---|
browser_acquire_lease | Acquire exclusive control of a tab for the MCP session. |
browser_heartbeat_lease | Keep an existing lease alive. |
browser_release_lease | Release the session’s tab lease. |
For argument schemas and raw JSON-RPC examples, see the Agent Protocol tools reference.
Feature-gated Mail tools
Section titled “Feature-gated Mail tools”When Browser-integrated Mail is enabled and the relevant consent gates pass, Mail read tools can also be surfaced through the Browser tool layer, including:
mail_list_accountsmail_list_foldersmail_list_emailsmail_get_emailmail_search_emailsmail_list_threadmail_extract_otp
Mail tools are not an independent mail server. They are dispatched by Maho Browser to the profile-scoped Mail helper. See MCP and Agent access for the feature, helper, consent, and typed-approval gates.
No generic JavaScript eval tool
Section titled “No generic JavaScript eval tool”The MCP registry intentionally does not expose a generic JavaScript execution primitive. Page access is provided through typed content/query tools, which gives Maho a place to apply redaction and policy before content leaves the browser process.
This is different from maho tab eval, an
explicit local CLI operation. Do not wrap tab eval and hand it to an agent as a
way to bypass the MCP policy surface.
Security and approval model
Section titled “Security and approval model”MCP tool access is local, but “local” is not the same as “unrestricted”. Maho keeps policy enforcement in the browser where the page/profile data lives.
Same-user local transport
Section titled “Same-user local transport”The Agent Protocol is not a network service. On macOS/Linux the browser uses a local Unix-domain transport with same-user checks; Windows uses a local Named Pipe/session-token model. This prevents a normal MCP configuration from becoming a LAN-accessible browser-control endpoint.
Domain approval
Section titled “Domain approval”Navigation is scoped by an allowed-domain policy. A session that has not been approved for a target domain cannot simply navigate there because the model asked. MCP clients should expect a browser-side approval flow or a policy error when a domain is outside the current allowlist.
Credential firewall
Section titled “Credential firewall”Content leaving the browser goes through Maho’s credential-redaction boundary. Sensitive values such as credentials/auth material are not meant to become ordinary MCP tool output just because a page contains them.
See Agent Protocol security for the current redaction vectors and policy details.
Per-tab leases
Section titled “Per-tab leases”Agents coordinate control through per-tab leases. If two sessions race for the same tab, the lease registry can reject/conflict rather than letting both mutate the tab concurrently. Long-running clients heartbeat their lease and release it when finished.
Mail consent is separate
Section titled “Mail consent is separate”A permissive global tool policy does not imply permission to read Mail. Mail reads additionally require Allow AI to read Mail. Sensitive Mail write or account-changing actions go through their typed approval path.
Tool availability can be policy-dependent
Section titled “Tool availability can be policy-dependent”A tool can exist in the product while being unavailable to a specific session because of feature flags, user settings, consent state, domain policy, or the current implementation status. MCP clients should handle tool errors instead of assuming discovery implies every invocation will succeed.
MCP response model
Section titled “MCP response model”Maho follows the MCP tool-call shape. Tool results are returned as MCP content; Maho’s Browser tools use text content containing JSON for structured payloads. At the protocol level, a representative response is:
{ "jsonrpc": "2.0", "id": 42, "result": { "content": [ { "type": "text", "text": "{\"tabs\":[{\"id\":\"tab_1a2b\",\"title\":\"Example\",\"url\":\"https://example.com/\",\"active\":true}]}" } ], "isError": false }}MCP SDKs normally parse the outer protocol structure for you. If you are writing
a raw client, parse the JSON string inside result.content[0].text before using
the Browser payload.
Troubleshooting
Section titled “Troubleshooting”Client says maho is not found
Section titled “Client says maho is not found”Desktop GUI apps often inherit a smaller PATH than your terminal. Replace
"command": "maho" with the absolute path to the executable.
Server starts but tools do not appear
Section titled “Server starts but tools do not appear”Confirm Maho Browser is running, reload the MCP client, and inspect the client’s MCP logs. Tool enumeration happens during initialization, so a stale client session may need to reconnect.
Navigation is denied
Section titled “Navigation is denied”That is not necessarily a connection failure. The requested domain may not be in the MCP session’s allowed-domain policy. Approve/set the domain through the normal Maho flow rather than trying to bypass the policy.
Mail tools are missing or denied
Section titled “Mail tools are missing or denied”Check, in order: Mail enabled for the profile, Mail helper ready, global tool policy not deny-all, and Allow AI to read Mail enabled for read tools. See MCP and Agent access for stable denial reasons.
A tab operation reports a lease conflict
Section titled “A tab operation reports a lease conflict”Another agent session may own the tab lease. Let that session release/expire its lease, or use the product’s explicit lease-control semantics rather than retrying mutating calls in a tight loop.
CLI vs MCP
Section titled “CLI vs MCP”Use plain CLI commands when the shell is the orchestrator:
maho page markdown | llm 'Summarize this page.'Use MCP when another AI host should decide which Browser tool to call:
{ "mcpServers": { "maho": { "command": "maho", "args": ["mcp"] } }}The underlying Browser remains the policy boundary in both cases.