mcpServer.ts
utils/computerUse/mcpServer.ts
107
Lines
4123
Bytes
2
Exports
12
Imports
10
Keywords
What this is
This page documents one file from the repository and includes its full source so you can read it without leaving the docs site.
Beginner explanation
This file is one piece of the larger system. Its name, directory, imports, and exports show where it fits. Start by reading the exports and related files first.
How it is used
Start from the exports list and related files. Those are the easiest clues for where this file fits into the system.
Expert explanation
Architecturally, this file intersects with mcp. It contains 107 lines, 12 detected imports, and 2 detected exports.
Important relationships
Detected exports
createComputerUseMcpServerForClirunComputerUseMcpServer
Keywords
serverpromiseadaptervoidcreatecomputerusemcpserveranalyticslogfordebugginginstalledservicesgetcomputerusehostadapter
Detected imports
@ant/computer-use-mcp@modelcontextprotocol/sdk/server/stdio.js@modelcontextprotocol/sdk/types.jsos../../services/analytics/datadog.js../../services/analytics/firstPartyEventLogger.js../../services/analytics/sink.js../config.js../debug.js./appNames.js./gates.js./hostAdapter.js
Source notes
This page embeds the full file contents. Small or leaf files are still indexed honestly instead of being over-explained.
Full source
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')
}