Host — AppHost
The AppHost mediator: host-side app management and bidirectional tool calls.
AppHost — Host-Side App Management ¶
Stable — MCP Apps host-side APIs (
ext/ui: AppHost).
Demonstrates AppHost mediating between an MCP server and an app bridge with bidirectional tool calls.
What you’ll learn ¶
- Create MCP server with tools — The server provides two tools: echo (returns input) and time (returns current time).
- Connect client to server via in-process transport — The client connects without HTTP — using InProcessTransport for direct dispatch.
- Create InProcessAppBridge with app-provided tools — The bridge simulates an MCP App (iframe). It registers two tools that the host/model can call directly.
- Create AppHost and wire everything together — AppHost wires up bidirectional routing and fetches the initial app tool list.
- ListAllTools — aggregated server + app tools — ListAllTools merges tools from the MCP server and the app bridge into a single list.
- CallAppTool — host invokes an app-provided tool — The host calls a tool registered by the app. The bridge dispatches to the Go handler.
- App calls server tool via bridge → AppHost → Client — The app calls a server-side tool through the bridge. AppHost forwards to the MCP server via the Client.
- Dynamic registration — app adds a tool at runtime — The app registers a new tool after startup. AppHost detects the change and refreshes its cache.
Flow ¶
sequenceDiagram
participant Srv as MCP Server
participant Client as MCP Client
participant Host as AppHost
participant Bridge as InProcessAppBridge
Note over Srv,Bridge: Step 1: Create MCP server with tools
Srv->>Srv: RegisterTool("server_echo")
Srv->>Srv: RegisterTool("server_time")
Note over Srv,Bridge: Step 2: Connect client to server via in-process transport
Client->>Srv: initialize
Srv-->>Client: capabilities, serverInfo
Note over Srv,Bridge: Step 3: Create InProcessAppBridge with app-provided tools
Bridge->>Bridge: RegisterTool("app_greet")
Bridge->>Bridge: RegisterTool("app_counter")
Note over Srv,Bridge: Step 4: Create AppHost and wire everything together
Host->>Bridge: SetRequestHandler (app→host)
Host->>Bridge: SetNotificationHandler (list_changed)
Host->>Bridge: Start()
Host->>Bridge: Send(tools/list) — initial fetch
Bridge-->>Host: {tools: [app_greet, app_counter]}
Note over Srv,Bridge: Step 5: ListAllTools — aggregated server + app tools
Host->>Client: ListTools() — server tools
Client-->>Host: [server_echo, server_time]
Host->>Bridge: cached app tools
Bridge-->>Host: [app_greet, app_counter]
Note over Srv,Bridge: Step 6: CallAppTool — host invokes an app-provided tool
Host->>Bridge: Send(tools/call, {name: "app_greet", args: {name: "World"}})
Bridge-->>Host: ToolResult {text: "Hello, World!"}
Note over Srv,Bridge: Step 7: App calls server tool via bridge → AppHost → Client
Bridge->>Host: SendToHost(tools/call, {name: "server_echo"})
Host->>Client: Call(tools/call, params)
Client->>Srv: JSON-RPC tools/call
Srv-->>Client: ToolResult
Client-->>Host: CallResult
Host-->>Bridge: Response
Note over Srv,Bridge: Step 8: Dynamic registration — app adds a tool at runtime
Bridge->>Bridge: RegisterTool("app_dice")
Bridge->>Host: notifications/tools/list_changed
Host->>Bridge: Send(tools/list) — refresh
Bridge-->>Host: {tools: [app_greet, app_counter, app_dice]}
Steps ¶
Step 1: Create MCP server with tools ¶
References: MCP Specification
The server provides two tools: echo (returns input) and time (returns current time).
Step 2: Connect client to server via in-process transport ¶
The client connects without HTTP — using InProcessTransport for direct dispatch.
Step 3: Create InProcessAppBridge with app-provided tools ¶
References: MCP Apps Extension
The bridge simulates an MCP App (iframe). It registers two tools that the host/model can call directly.
Step 4: Create AppHost and wire everything together ¶
AppHost wires up bidirectional routing and fetches the initial app tool list.
Step 5: ListAllTools — aggregated server + app tools ¶
ListAllTools merges tools from the MCP server and the app bridge into a single list.
Step 6: CallAppTool — host invokes an app-provided tool ¶
The host calls a tool registered by the app. The bridge dispatches to the Go handler.
Step 7: App calls server tool via bridge → AppHost → Client ¶
The app calls a server-side tool through the bridge. AppHost forwards to the MCP server via the Client.
Step 8: Dynamic registration — app adds a tool at runtime ¶
The app registers a new tool after startup. AppHost detects the change and refreshes its cache.
Cleanup ¶
AppHost.Close() closes the bridge. The caller closes the Client separately.
In a real application, you’d defer these in the appropriate scope.
References ¶
Run it ¶
go run ./examples/host/01-apphost/
Pass --non-interactive to skip pauses:
go run ./examples/host/01-apphost/ --non-interactive
What to verify ¶
- Step 5: ListAllTools shows 4 tools (2 server + 2 app)
- Step 6: CallAppTool returns “Hello, World!” and counter increments to 2
- Step 7: App calls server_echo, result includes “echo: from the app”
- Step 8: After dynamic registration, 3 app tools listed (app_greet, app_counter, app_dice)