Welcome to the Claude in Chrome project! If you are new here, don't worryβwe are going to build this understanding block by block.
Imagine Claude (the AI) is a Pilot flying a plane, and the Chrome Browser is the Airport where the plane needs to land.
The Pilot can't just yell out the window to the ground crew. They need a system to communicate effectively. They need an Air Traffic Control (ATC) tower to manage the radio frequencies, check the weather (status), and ensure instructions are received clearly.
In our project, the MCP Server Context is that Air Traffic Control tower.
We want to allow Claude to send a command like "Click the 'Login' button" to Chrome. The Problem: Claude runs on a server, and Chrome runs on your desktop. They don't speak the same language or live in the same place.
The Solution: We create a "Context" (a configuration object) that initializes a server. This server acts as the bridge, holding the state of the connection and routing messages back and forth.
Before we look at the code, let's understand the three main components of this chapter:
Let's look at how we build this "brain" in code. We will look at mcpServer.ts.
The server needs a voice to report what is happening. We create a simple logger that helps us debug issues.
// A simple logger implementation
class DebugLogger implements Logger {
info(message: string, ...args: unknown[]): void {
// logs information to the debug console
logForDebugging(format(message, ...args), { level: 'info' })
}
// ... other methods like warn() and error()
}
Explanation: This DebugLogger is passed into our context so the server can shout "Hey, I'm connected!" or "Something went wrong!"
This is the most important part. We create a function createChromeContext that bundles our settings.
export function createChromeContext(): ClaudeForChromeContext {
const logger = new DebugLogger()
return {
serverName: 'Claude in Chrome', // Who are we?
logger, // How do we talk?
socketPath: getSecureSocketPath(), // Where is the pipe to Chrome?
clientTypeId: 'claude-code', // Who is using this?
// ... event handlers below
}
}
Explanation: We return an object defining the server's identity. socketPath is crucialβit points to the specific file location used to talk to the Native Messaging Host.
The context also defines what to do when specific things happen, like a disconnection.
// Inside the return object of createChromeContext...
onToolCallDisconnected: () => {
return `Browser extension is not connected.
Please ensure the extension is installed and running.`
},
onExtensionPaired: (deviceId, name) => {
logger.info(`Paired with "${name}"`)
// Saves the pairing config so we remember this browser
},
Explanation: If the "radio signal" is lost, onToolCallDisconnected provides a helpful error message to Claude. If we connect successfully, onExtensionPaired logs it.
Finally, we have the runClaudeInChromeMcpServer function. This turns on the lights in the ATC tower.
export async function runClaudeInChromeMcpServer(): Promise<void> {
// 1. Create the rulebook (Context)
const context = createChromeContext()
// 2. Create the Server using that context
const server = createClaudeForChromeMcpServer(context)
// 3. Define how we listen (Standard Input/Output)
const transport = new StdioServerTransport()
Explanation: We initialize the context, create the server instance, and prepare the transport layer.
// 4. Connect and Start
logForDebugging('[Claude in Chrome] Starting MCP server')
await server.connect(transport)
logForDebugging('[Claude in Chrome] MCP server started')
}
Explanation: server.connect(transport) is the moment the server goes live and starts listening for instructions from Claude.
When you run this code, a sequence of events triggers to establish the communication bridge.
Here is what happens the moment the mcpServer.ts file is executed:
In the file mcpServer.ts, you might notice logic regarding getChromeBridgeUrl().
The Context is smart. It decides how to talk to Chrome based on your environment:
wss://bridge.claudeusercontent.com.The code handles this automatically:
function getChromeBridgeUrl(): string | undefined {
// Check if we should use the web bridge
const bridgeEnabled = process.env.USER_TYPE === 'ant'
if (!bridgeEnabled) {
return undefined // Use Native Messaging instead
}
return 'wss://bridge.claudeusercontent.com'
}
Explanation: If the bridge isn't enabled, it returns undefined. The createChromeContext function sees this and defaults to using socketPath (Native Messaging).
You have successfully set up the MCP Server Context! You now have a running server that acts as the brain of the operation. It knows who it is, how to log errors, and has selected a method (Socket or WebSocket) to talk to the browser.
However, a brain is useless without thoughts. The server needs to know what to say to the AI to help it understand how to browse the web.
Next Chapter: AI System Instructions
Generated by Code IQ