← Back to blog

How Guida's MCP Server Works

· 7 min read ·
technical

Guida ships with a built-in Model Context Protocol (MCP) server. This is what lets an external AI — Claude Code, Cursor, or any MCP-compatible client — control the browser. It’s the bridge between “I want to scrape this page” spoken to an AI and the actual DOM queries, clicks, and data storage that make it happen.

This post is a technical deep dive into how it works. We’ll cover the protocol, the transport layer, how tools get registered, and the three-layer security model that ensures the AI can’t do anything without your knowledge and consent.

What MCP is (briefly)

MCP is a JSON-RPC protocol for connecting AI models to external tools. The AI sends a request like “call the Navigate tool with url: https://example.com”, the server executes it, and returns the result. The model never touches the browser directly — it only sees the tool’s input/output contract.

The protocol defines three primitives:

Guida implements the tools and resources primitives. It exposes 100+ tools covering browser automation, data storage, search, and more.

Transport: local HTTP

MCP supports multiple transports. Guida uses a local HTTP transport — the server runs an embedded Kestrel instance on http://127.0.0.1:9315.

The choice of HTTP over stdio has practical reasons: Guida is a WPF desktop app, not a CLI tool. There’s no stdin/stdout to pipe. HTTP also allows external MCP clients to connect while the browser UI, approval state, task history, and workspace panes remain visible.

For current streamable HTTP clients, the useful endpoint is the server root:

http://127.0.0.1:9315/

The handshake is MCP-standard: the client initializes, the server returns available capabilities, then the client discovers tools and starts making calls.

Client → initialize
{"jsonrpc": "2.0", "method": "initialize", ...}
Server → capabilities
{"jsonrpc": "2.0", "id": 1, "result": {...}}
Client → tools/list
Client → tools/call

Tool registration

Tools are registered in McpServerService.cs using the .NET MCP SDK. Each tool has a name, description, JSON Schema for parameters, and an async handler.

Here are a few representative tools from the 100+ available:

ToolDescription
NavigateNavigate the active tab to a URL
ClickClick an element by CSS selector
GetElementsQuery DOM elements and extract attributes
ScreenshotCapture the visible viewport as PNG
ExecuteScriptRun a g.* script in the app’s scripting engine
StoreGet / StorePutRead/write workspace storage
QueueEnqueue / QueueDequeueManage work queues
SearchQueryFull-text search over indexed documents

Under the hood, most tools delegate to the same services that power the g.* scripting API. Navigate calls the same BrowserAutomationService.NavigateAsync() that g.nav.navigateToUrl() uses. The MCP layer is a thin adapter that maps JSON-RPC requests to service calls and formats the results.

This means scripts and AI tools have the same capabilities — with one critical exception that we’ll get to in the security section.

Three-layer security

Here’s where Guida diverges from most MCP servers. The AI is powerful, but it’s not trusted. Every action goes through three layers of security before it reaches the browser.

Layer 1: Domain whitelisting

Before the AI can navigate to any URL, the domain must be on the whitelist. Guida supports three tiers:

If the AI tries to navigate to a domain that’s not whitelisted, the tool call fails with a clear error message. The AI sees the rejection and can explain what happened.

Wildcards work: *.example.com allows all subdomains. The whitelist applies to scripted navigation only — you can browse anywhere manually.

Layer 2: Tool approval

Even on an allowed domain, monitored tool calls require your explicit approval. When the AI wants to click a button or run a script, Guida shows you:

This is the same permission model you’d expect from a mobile app asking for camera access — except it’s per-action, not per-install. You can trust a tool for the session if you’re tired of clicking approve, or review every call individually.

The Approval Center shows the real parameters, not a summary. If the AI wants to Click with selector button.delete-account, you’ll see that exact selector before it runs.

Layer 3: Audit trail

Every tool call is recorded in mcp-audit.db — a separate LiteDB database that the AI cannot access. The audit log captures:

The MCP History pane in the app shows the audit log in real time. You can search, filter by errors, and drill into individual calls to see the full JSON parameters and results.

The key security property: the AI cannot read or clear its own audit trail. There are no MCP tools that expose the audit database. This means even a prompt-injected AI can’t cover its tracks.

Secrets isolation

One more security boundary worth calling out. Guida has a Secrets pane where you store API keys, passwords, and tokens, encrypted with Windows DPAPI. Scripts can read secrets via g.secrets.getSecret(name) — but MCP-origin scripts cannot.

When a script is launched via an MCP tool (like ExecuteScript), Guida tags it with origin Mcp. Any call to g.secrets.getSecret() from an MCP-origin script returns an error. This breaks the exfiltration chain:

AI calls ExecuteScript → script calls g.secrets.getSecret("api-key")
→ BLOCKED (MCP origin detected)

Without this, a prompt-injected AI could: run a script that reads your API key, write it to g.store, then read the store via MCP. The origin check prevents step one.

Other secret operations (listing names, setting values) are allowed — only reading decrypted values is blocked. This lets the AI help you manage secrets without ever seeing the actual values.

Custom tools

Beyond the 100+ built-in tools, you can define custom HTTP tools in a workspace’s tools.json:

{
"tools": [
{
"name": "GetWeather",
"description": "Get current weather for a city",
"endpoint": "https://api.weather.example/v1/current",
"method": "GET",
"parameters": {
"city": { "type": "string", "description": "City name", "required": true }
},
"headers": {
"Authorization": "Bearer {{secrets.WEATHER_API_KEY}}"
}
}
]
}

Notice the {{secrets.WEATHER_API_KEY}} template. The actual secret value is injected at call time by the server — the AI never sees it. This lets you give the AI access to authenticated APIs without exposing credentials.

Custom tools go through the same approval flow as built-in tools. The AI sees the tool’s schema, proposes a call, and you approve or deny.

Architecture summary

Here’s how the pieces fit together:

┌──────────────────────┐
│ AI Client │ Claude Code, Cursor, etc.
│ (MCP Client) │
└──────────┬───────────┘
│ MCP over local HTTP
┌──────────▼───────────┐
│ Guida MCP Server │ Embedded Kestrel on 127.0.0.1:9315
│ │
│ ┌─ Domain Filter ─┐ │ Layer 1: URL whitelist check
│ ├─ Approval Center┤ │ Layer 2: User approves/denies
│ ├─ Audit Logger ─┤ │ Layer 3: Record to mcp-audit.db
│ └─ Tool Handler ─┘ │ Execute via shared services
│ │
└──────────┬───────────┘
│ Service calls
┌──────────▼───────────┐
│ Shared Services │ BrowserAutomation, Store, Queue,
│ │ Search, Network, History, etc.
└──────────┬───────────┘
┌──────────▼───────────┐
│ Browser / WebView2 │ Chromium-based browser engine
└──────────────────────┘

The MCP server is a thin adapter layer. It doesn’t duplicate any business logic — it maps JSON-RPC to the same services that scripts use. The security layers (domain filter, approval, audit) are inserted as middleware in the MCP pipeline.

Connecting a client

To connect Claude Code or another MCP client to Guida, add this to your MCP client configuration:

{
"mcpServers": {
"guida": {
"url": "http://127.0.0.1:9315/"
}
}
}

That’s it. The client discovers available tools via the tools/list method and starts making calls. Guida’s Approval Center handles monitored requests.

For more details on the tools available and workspace configuration, see the MCP Integration docs and Custom Tools guide.