How Guida's MCP Server Works
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:
- Tools — functions the AI can call (navigate, click, extract, etc.)
- Resources — data the AI can read (open tabs, page content)
- Prompts — reusable templates for common operations
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/listClient → tools/callTool 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:
| Tool | Description |
|---|---|
Navigate | Navigate the active tab to a URL |
Click | Click an element by CSS selector |
GetElements | Query DOM elements and extract attributes |
Screenshot | Capture the visible viewport as PNG |
ExecuteScript | Run a g.* script in the app’s scripting engine |
StoreGet / StorePut | Read/write workspace storage |
QueueEnqueue / QueueDequeue | Manage work queues |
SearchQuery | Full-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:
- Per-session — approved domains that expire when you close the app
- Per-workspace — domains listed in
domains.jsonin your workspace folder - Global — domains always allowed (configured in settings)
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:
- The exact tool name being called
- The exact parameters (URL, selector, script code, etc.)
- Options to approve once, approve for this session, or deny
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:
- Tool name and parameters (first 4000 characters)
- Result or error (first 2000 characters)
- Execution duration
- Timestamp and session ID
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.