Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,33 +61,6 @@ const clients: ClientConfig[] = [
action: 'Run in your terminal:',
getSnippet: (url) => `codex mcp add browseros ${url}`,
},
{
id: 'claude-desktop',
name: 'Claude Desktop',
kind: 'config',
action: (
<>
Add to{' '}
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px]">
~/Library/Application Support/Claude/claude_desktop_config.json
</code>{' '}
and restart Claude Desktop:
</>
),
getSnippet: (url) =>
JSON.stringify(
{
mcpServers: {
browserOS: {
command: 'npx',
args: ['mcp-remote', url],
},
},
},
null,
2,
),
},
]

const CopyButton: FC<{ text: string; label?: string }> = ({ text, label }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

import type { FC, SVGProps } from 'react'
import { AnthropicBlack } from '@/components/ui/svgs/anthropicBlack'
import { ClaudeAiIcon } from '@/components/ui/svgs/claudeAiIcon'
import { CodexLight } from '@/components/ui/svgs/codexLight'
import { CursorLight } from '@/components/ui/svgs/cursorLight'
import { Vscode } from '@/components/ui/svgs/vscode'
Expand All @@ -24,10 +23,6 @@ export const ClaudeMark: FC<AgentMarkProps> = (props) => (
<AnthropicBlack aria-hidden {...props} />
)

export const ClaudeDesktopMark: FC<AgentMarkProps> = (props) => (
<ClaudeAiIcon aria-hidden {...props} />
)

export const CursorMark: FC<AgentMarkProps> = (props) => (
<CursorLight aria-hidden {...props} />
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { FC, SVGProps } from 'react'
import {
ClaudeDesktopMark,
ClaudeMark,
CodexMark,
CursorMark,
Expand Down Expand Up @@ -30,11 +29,6 @@ const AGENT_PRESENTATION: Record<string, AgentPresentation> = {
installUrl: 'https://claude.ai/code',
mark: ClaudeMark,
},
'claude-desktop': {
label: 'Claude Desktop',
installUrl: 'https://claude.ai/download',
mark: ClaudeDesktopMark,
},
cursor: {
label: 'Cursor',
installUrl: 'https://cursor.com',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const features: Feature[] = [
highlights: [
'One-line setup — run `claude mcp add` with your server URL to connect',
'31 browser tools — tabs, clicks, typing, screenshots, bookmarks, history',
'Works everywhere — Claude Code, Gemini CLI, Codex, Claude Desktop',
'Works everywhere — Claude Code, Gemini CLI, Codex, Cursor, Zed',
'Authenticated access — extract data from logged-in pages like LinkedIn',
],
videoDuration: '1:40',
Expand Down
2 changes: 1 addition & 1 deletion packages/browseros-agent/apps/claw-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"@browseros/shared": "workspace:*",
"@hono/zod-validator": "^0.8.0",
"@modelcontextprotocol/sdk": "^1.27.1",
"agent-mcp-manager": "^0.0.1",
"agent-mcp-manager": "^0.0.3",
Comment thread
DaniAkash marked this conversation as resolved.
"commander": "^14.0.3",
"drizzle-orm": "^0.45.2",
"hono": "^4.12.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/browseros-agent/apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"acp-probe": "^0.0.2",
"acpx": "^0.10.0",
"acpx-ai-provider": "^0.0.6",
"agent-mcp-manager": "^0.0.2",
"agent-mcp-manager": "^0.0.3",
"ai": "^6.0.208",
"commander": "^14.0.3",
"core-js": "3.45.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,20 @@ import { getBrowserosDir } from '../browseros-dir'

/**
* Server-name BrowserOS registers itself under for agents that speak
* MCP over HTTP natively (Claude Code, Claude Desktop, Cursor, VS Code,
* Zed). The stdio-only agents get a separate entry — see
* MCP over HTTP natively (Claude Code, Cursor, VS Code, Codex, Zed).
* Stdio-only agents — when supported — get a separate entry under
* `BROWSEROS_MCP_STDIO_SERVER_NAME` below.
*/
export const BROWSEROS_MCP_SERVER_NAME = 'browseros'

/**
* Server-name BrowserOS registers itself under for stdio-only agents
* (today: Codex). The spec wraps `npx mcp-remote <url>` so a stdio
* client can speak to the BrowserOS HTTP MCP endpoint. Kept as a
* separate manifest entry from the HTTP one so each carries its own
* spec and can be reconciled independently.
* Server-name BrowserOS registers itself under for stdio-only agents.
* The spec wraps `npx mcp-remote <url>` so a stdio client can speak
* to the BrowserOS HTTP MCP endpoint. Kept as a separate manifest
* entry from the HTTP one so each carries its own spec and can be
* reconciled independently. No surfaced agent currently uses this
* branch — Claude Desktop is hidden from the Integrations panel
* because its stdio bridge requires Node on the user's machine.
*/
export const BROWSEROS_MCP_STDIO_SERVER_NAME = 'browseros-stdio'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,20 @@ export type DetectInstalledAgentsFn = () => Promise<AgentInfo[]>

/**
* Agents the upstream library supports but BrowserOS deliberately
* does not surface in the Integrations panel. Today: Gemini CLI's
* MCP HTTP support is not stable enough to one-click-install
* against. Users who actually want it can still copy-paste the
* manual setup snippet from the disclosure on the same page.
* does not surface in the Integrations panel.
*
* - `gemini`: HTTP MCP support is not stable enough to one-click
* install against.
* - `claude-desktop`: Anthropic's `claude_desktop_config.json` parser
* only validates stdio entries, and the stdio bridge they recommend
* (`npx mcp-remote`) requires Node on the user's machine. Without a
* bundled-runtime path we cannot make this reliable, so we hide it
* rather than ship a broken-by-default flow.
*
* Users who actually want either can still copy-paste the manual
* setup snippet from the disclosure on the same page.
Comment thread
DaniAkash marked this conversation as resolved.
Outdated
*/
const HIDDEN_AGENTS: ReadonlySet<string> = new Set(['gemini'])
const HIDDEN_AGENTS: ReadonlySet<string> = new Set(['gemini', 'claude-desktop'])

/**
* The two server-names BrowserOS manages in the manifest. Iterating
Expand All @@ -63,9 +71,10 @@ interface AgentServerPlan {
* Transport routing is sourced from the library's catalog via
* `resolveAgentSurface` so we stay in lock-step with whatever
* upstream agent-mcp-manager classifies as http-capable. Agents
* that only accept stdio (claude-desktop, codex, …) get wrapped
* via `npx mcp-remote <url>` so a stdio client still ends up
* talking to the local HTTP MCP endpoint.
* that only accept stdio (e.g. claude-desktop) get wrapped via
* `npx mcp-remote <url>` so a stdio client still ends up talking
* to the local HTTP MCP endpoint. Codex moved to native HTTP in
* agent-mcp-manager 0.0.3, so it lands on the http branch.
*/
function planFor(agentId: AgentId, currentUrl: string): AgentServerPlan {
const surface = resolveAgentSurface(agentId, 'system')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,11 @@ describe('listAgents', () => {
})

it('hides agents BrowserOS does not surface in the panel', async () => {
// Today only Gemini CLI is hidden: its HTTP MCP support is not
// stable enough for a one-click install. The agent stays
// available via the manual setup snippet.
// Hidden: Gemini CLI (HTTP MCP support not stable enough for a
// one-click install) and Claude Desktop (only stdio config is
// valid and the recommended `npx mcp-remote` bridge needs Node
// on the user's machine). Both stay available via the manual
// setup snippet.
stubAgents = [
{
id: 'claude-code',
Expand All @@ -146,6 +148,12 @@ describe('listAgents', () => {
installed: true,
configPath: '/tmp/fake/gemini.json',
},
{
id: 'claude-desktop',
displayName: 'Claude Desktop',
installed: true,
configPath: '/tmp/fake/claude-desktop.json',
},
]
const { manager: hiddenManager } = makeManagerStub()
setMcpManagerForTesting(hiddenManager)
Expand Down Expand Up @@ -220,25 +228,25 @@ describe('installInto', () => {
expect(calls.link[0].serverName).toBe('browseros')
})

it('uses a stdio mcp-remote spec under a separate server name for codex', async () => {
// Codex rejects HTTP MCP specs; the manager surfaces this as an
// InvalidServerSpecError. Wrapping the HTTP url in `npx mcp-remote`
// lets a stdio-only client still reach the local HTTP endpoint.
it('uses an http spec under the http server name for codex', async () => {
// Codex gained streamable-HTTP MCP support in agent-mcp-manager
// 0.0.3 (its surface flipped to ['stdio', 'http']). planFor now
// hits the http branch, mirroring claude-code, so no stdio bridge
// is needed and the integration works without npx on the host.
const { manager, calls } = makeManagerStub()
setMcpManagerForTesting(manager)

const result = await installInto('codex', 'http://127.0.0.1:9100/mcp')
expect(result.success).toBe(true)
expect(calls.add).toHaveLength(1)
expect(calls.add[0].name).toBe('browseros-stdio')
expect(calls.add[0].name).toBe('browseros')
expect(calls.add[0].spec).toEqual({
transport: 'stdio',
command: 'npx',
args: ['mcp-remote', 'http://127.0.0.1:9100/mcp'],
transport: 'http',
url: 'http://127.0.0.1:9100/mcp',
})
expect(calls.link).toHaveLength(1)
expect(calls.link[0].agent).toBe('codex')
expect(calls.link[0].serverName).toBe('browseros-stdio')
expect(calls.link[0].serverName).toBe('browseros')
})

it('uses a stdio mcp-remote spec under the stdio server name for claude-desktop', async () => {
Expand Down
8 changes: 3 additions & 5 deletions packages/browseros-agent/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading