Architecture
MCP-Web provides the glue to enable AI agents to control and interact with your frontend app. The key architectural design aspect of MCP-Web is that it treats the frontend as the source of truth and main control surface.
This is accomplished by having the frontend define tools and exposing those directly to AI via a bridge server that links browser sessions to an MCP server. This way, both user and AI interactions can trigger the same state changes and actions, which ensures user agency while still allowing automation and integration through AI.
MCP-Web vs Classic MCP Server
To better understand the difference let's compare MCP-Web approach shown above to a "classic" web app plus MCP server architecture:
Classic MCP Server Setup
AI Agent ↔ MCP Server ↔ Database ↔ WebSocket/SSE ↔ Frontend
╰─ calls ─╯ ╰─ updates ─╯ ╰─ informs ─╯ ╰─ notifies ─╯- MCP server manipulates backend resources (database, APIs, files)
- Frontend receives updates via WebSocket/polling
- Source of truth: Database
- AI changes → DB → Frontend
MCP-Web Setup
AI Agent ↔ MCP Server + WebSocket/SSE ↔ Frontend ↔ Database
╰─ calls ─╯ ╰─ notifies ─╯ ╰─ updates ─╯- MCP server routes directly to frontend state and actions
- Frontend is both the execution environment and source of truth
- Source of truth: Frontend
- AI changes → Frontend (optionally → DB)
Key Insight
With MCP-Web, the frontend becomes the main point of control for reading and writing data.
Why MCP-Web's Approach?
As with everything, MCP-Web's approach of making the frontend the main point of control has pros and cons and it depends on your use case whether it's useful or not.
Choose MCP-Web when:
- Rich ephemeral UI state: Selections, filters, animations, layouts that don't belong in a database
- Multiple views of data: Same data resource has many visual representations
- Frontend-first validation: UI enforces constraints and business logic
- Preserve user agency: User can see and interrupt AI actions in real-time
- No backend modifications: Add AI capabilities without changing (or needing) the backend
Choose classic MCP server when:
- Frontend is a thin view layer over backend resources
- Multi-user collaboration requires database as source of truth
- AI needs to trigger non-user facing tools
How MCP-Web Works
Instead of having AI communicate with a backend database and have the backend push changes to the frontend, MCP-Web lets AI communicate directly with the frontend via dual server that is both an MCP server and a websocket server connected to your frontend browser sessions. This is accomplished via three packages: Web, Bridge, Client. These three packages communicate as follows:
Frontend ↔ MCPWeb() ↔ MCPWebBridge() ↔ AI App/Agent
╰─ Runs ─╯ ╰─ WS / SSE ─╯ ╰─ HTTP (Remote MCP) or STDIO ─╯- Frontend app: runs
MCPWeb MCPWeb(): registers and executes frontend toolsMCPWebBridge(): exposes tools and forwards calls as an MCP server- AI agent: connects via Remote MCP (HTTP) or via
MCPWebClient()(STDIO)
Connection Options
AI agents can connect to the bridge in two ways:
Remote MCP (Recommended): Direct HTTP connection to the bridge server. The AI agent connects via URL with a token query parameter for session routing. This is the simplest setup with no intermediate process required.
Stdio via MCPWebClient: Uses
@mcp-web/clientas a stdio wrapper that the AI agent spawns as a subprocess. This approach is primarily useful when building agent servers that handle frontend-triggered queries.
One can say that with MCP-Web, the frontend becomes the MCP server by executing the tool calls. This inversion of control might seem odd at first but it makes sense when you think about it.
MCP-Web's bridge server is just a thin layer that exposes the registered tools and forwards tool calls and responses between the frontend and client.
The optional AI agent here serves as a way to enable "two-way communication" in that it allows the frontend to issue queries. This is most useful if you want to reuse the already registered tools.
MCP As The Main Tool Protocol
MCP-Web uses the Model Context Protocol (MCP) as the primary communication standard between AI agents and your frontend application. The obvious benefit here is that it allows you to integrate frontend tools easily with the MCP ecosystem.
Tool Exposure and Call Flow
When your frontend registers tools using mcp.addTool(), mcp.addStateTools(), or mcp.addApp() they are exposed to AI agents through the MCP protocol as follows:
1. Frontend calls mcp.addTool()
↓
2. MCPWeb (packages/core) validates tool definition
↓
3. Tool is sent to Bridge via WebSocket
↓
4. Bridge stores tool in session registry
↓
5. MCP Client (packages/client) exposes tool to AI agent
↓
6. AI agent sees tool in available tools listWhen an AI agent calls a tool, the flow reverses:
1. AI agent calls tool via MCP Client
→ tools/call { name: "create_todo", arguments: {...} }
2. MCP Client forwards to Bridge via HTTP
→ POST /tool-call
→ { toolName: "create_todo", toolInput: {...} }
3. Bridge identifies target session
→ Looks up which session has "create_todo" tool
→ If multiple, uses session routing logic
4. Bridge sends to Frontend via WebSocket
→ { type: "tool-call", toolName: "create_todo", toolInput: {...} }
5. MCPWeb executes tool handler
→ const result = await handler(toolInput)
→ Validates with Zod schemas
6. Frontend sends result back via WebSocket
→ { type: "tool-response", result: {...} }
7. Bridge forwards to MCP Client via HTTP response
← { content: [...] }
8. MCP Client returns to AI agent
← Tool result in MCP formatSession-Based Tool Routing
It's worth noting that tool calls are not just token scoped but also session scoped. In other words, you can run the same frontend app multiple times in different browser tabs and each session registers its own set of tools.
The Bridge server manages multiple sessions and routes tool calls as follows:
Single Session:
- If only one frontend is connected, tools are automatically routed to that session
- No need for AI to identify which session to call
Multiple Sessions:
- Each session has unique tools or the same tools for different instances
- The Bridge aggregates all tools and may prefix them with session identifiers
- AI agents can use the
list_active_sessionstool to see all connected frontends - Tool calls can specify which session to target
Frontend-Triggered Queries Design
In a classic MCP setup, requests always get triggered by the AI agent. This it works well for scenarios where the user is only interfacing with the AI agent but in the context of MCP-Web users might be working with both: an AI agent and your frontend app.
In this case, it'd be nice to query AI directly from the frontend and reuse the existing MCP tools. MCP-Web supports this through frontend-triggered queries using a separate lightweight Agent API that makes use of the same MCP tools you've registered.
::: note MCP Sampling MCP's sampling concept allows servers to issue queries to a connected AI agent but those queries need to be approached. This makes sense but there are also scenarios where manual approval isn't a great user experience. This is what frontend-triggered queries are useful for. :::
Query Flow
When you issue a query via mcp.query(), the query goes through the bridge to the agent server. The bridge registers the query and scopes which tools the agent can call during query execution.
Frontend Bridge Agent Server
│ │ │
│ mcp.query() │ │
├──────────────────►│ PUT /query │
│ ├────────────────────►│
│ ← query_accepted │ │
│◄──────────────────┤ │
│ │ │
│ ← forwarded │ Tool calls │
│◄──────────────────│◄────────────────────┤
│ returns result → │ │
│──────────────────►│────────────────────►│
│ │ │
│ ← forwarded │ ← query_progress │
│◄──────────────────┤◄────────────────────┤
│ │ │
│ ← forwarded │ ← query_complete │
│◄──────────────────┤◄────────────────────┤
│ │ │The bridge server acts as an intermediary that:
- Routes frontend-triggered queries to the agent server
- Scopes which tools are accessible during query execution
- Forwards tool calls back to the frontend for execution
::: note For details on how to use and implement frontend-triggered queries see our dedicated guide. :::