π File detail
utils/computerUse/mcpServer.ts
π― Use case
This file lives under βutils/β, which covers cross-cutting helpers (shell, tempfiles, settings, messages, process input, β¦). On the API surface it exposes createComputerUseMcpServerForCli and runComputerUseMcpServer β mainly functions, hooks, or classes. Dependencies touch @ant, @modelcontextprotocol, and Node OS/process metadata. It composes internal code from services, config, debug, appNames, and gates (relative imports).
Generated from folder role, exports, dependency roots, and inline comments β not hand-reviewed for every path.
π§ Inline summary
import { buildComputerUseTools, createComputerUseMcpServer, } from '@ant/computer-use-mcp' import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
π€ Exports (heuristic)
createComputerUseMcpServerForClirunComputerUseMcpServer
π External import roots
Package roots from from "β¦" (relative paths omitted).
@ant@modelcontextprotocolos
π₯οΈ Source preview
import {
buildComputerUseTools,
createComputerUseMcpServer,
} from '@ant/computer-use-mcp'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'
import { homedir } from 'os'
import { shutdownDatadog } from '../../services/analytics/datadog.js'
import { shutdown1PEventLogging } from '../../services/analytics/firstPartyEventLogger.js'
import { initializeAnalyticsSink } from '../../services/analytics/sink.js'
import { enableConfigs } from '../config.js'
import { logForDebugging } from '../debug.js'
import { filterAppsForDescription } from './appNames.js'
import { getChicagoCoordinateMode } from './gates.js'
import { getComputerUseHostAdapter } from './hostAdapter.js'
const APP_ENUM_TIMEOUT_MS = 1000
/**
* Enumerate installed apps, timed. Fails soft β if Spotlight is slow or
* claude-swift throws, the tool description just omits the list. Resolution
* happens at call time regardless; the model just doesn't get hints.
*/
async function tryGetInstalledAppNames(): Promise<string[] | undefined> {
const adapter = getComputerUseHostAdapter()
const enumP = adapter.executor.listInstalledApps()
let timer: ReturnType<typeof setTimeout> | undefined
const timeoutP = new Promise<undefined>(resolve => {
timer = setTimeout(resolve, APP_ENUM_TIMEOUT_MS, undefined)
})
const installed = await Promise.race([enumP, timeoutP])
.catch(() => undefined)
.finally(() => clearTimeout(timer))
if (!installed) {
// The enumeration continues in the background β swallow late rejections.
void enumP.catch(() => {})
logForDebugging(
`[Computer Use MCP] app enumeration exceeded ${APP_ENUM_TIMEOUT_MS}ms or failed; tool description omits list`,
)
return undefined
}
return filterAppsForDescription(installed, homedir())
}
/**
* Construct the in-process server. Delegates to the package's
* `createComputerUseMcpServer` for the Server object + stub CallTool handler,
* then REPLACES the ListTools handler with one that includes installed-app
* names in the `request_access` description (the package's factory doesn't
* take `installedAppNames`, and Cowork builds its own tool array in
* serverDef.ts for the same reason).
*
* Async so the 1s app-enumeration timeout doesn't block startup β called from
* an `await import()` in `client.ts` on first CU connection, not `main.tsx`.
*
* Real dispatch still goes through `wrapper.tsx`'s `.call()` override; this
* server exists only to answer ListTools.
*/
export async function createComputerUseMcpServerForCli(): Promise<
ReturnType<typeof createComputerUseMcpServer>
> {
const adapter = getComputerUseHostAdapter()
const coordinateMode = getChicagoCoordinateMode()
const server = createComputerUseMcpServer(adapter, coordinateMode)
const installedAppNames = await tryGetInstalledAppNames()
const tools = buildComputerUseTools(
adapter.executor.capabilities,
coordinateMode,
installedAppNames,
)
server.setRequestHandler(ListToolsRequestSchema, async () =>
adapter.isDisabled() ? { tools: [] } : { tools },
)
return server
}
/**
* Subprocess entrypoint for `--computer-use-mcp`. Mirror of
* `runClaudeInChromeMcpServer` β stdio transport, exit on stdin close,
* flush analytics before exit.
*/
export async function runComputerUseMcpServer(): Promise<void> {
enableConfigs()
initializeAnalyticsSink()
const server = await createComputerUseMcpServerForCli()
const transport = new StdioServerTransport()
let exiting = false
const shutdownAndExit = async (): Promise<void> => {
if (exiting) return
exiting = true
await Promise.all([shutdown1PEventLogging(), shutdownDatadog()])
// eslint-disable-next-line custom-rules/no-process-exit
process.exit(0)
}
process.stdin.on('end', () => void shutdownAndExit())
process.stdin.on('error', () => void shutdownAndExit())
logForDebugging('[Computer Use MCP] Starting MCP server')
await server.connect(transport)
logForDebugging('[Computer Use MCP] MCP server started')
}