Integrating MCP Servers with McpWorkbench for External Tool Access: A Complete Technical Guide
The MCP Workbench in AutoGen Studio provides a WebSocket-based protocol bridge that enables real-time bidirectional communication between the frontend UI and any MCP-compatible external tool server, supporting stdio, SSE, and streamable HTTP transports.
The Microsoft AutoGen repository includes a powerful Model-Context Protocol (MCP) Workbench within AutoGen Studio that simplifies connecting to external tools. This guide explains how to leverage McpWorkbench to integrate MCP servers using a standardized WebSocket gateway architecture that handles protocol translation, session management, and user elicitation.
Architecture Overview
The integration relies on three distinct architectural layers that manage transport, protocol translation, and business logic.
Transport Layer
Located in autogenstudio/web/routes/mcp.py, the mcp_websocket endpoint accepts WebSocket connections and decodes the server_params query string to instantiate the appropriate MCP client. The create_mcp_session helper function determines whether to use stdio, SSE, or streamable HTTP based on the decoded parameters.
Protocol Bridge
The MCPWebSocketBridge class in autogenstudio/mcp/wsbridge.py implements the MCPEventHandler interface. This bridge translates MCP events (initialization, operation results, errors, sampling requests) into JSON messages for the UI, and forwards UI-initiated operations back to the MCP client.
Business Logic Layer
Callbacks for logging protocol messages, handling AI sampling, and managing user input requests reside in autogenstudio/mcp/callbacks.py. Key functions include create_message_handler, create_sampling_callback, and create_elicitation_callback, which convert MCP protocol callbacks into UI-friendly activity logs.
Core Components and File Paths
Understanding the source structure is essential for extending the integration or debugging connection issues.
-
autogenstudio/web/routes/mcp.py: FastAPI router handling the WebSocket endpoint, session creation viacreate_mcp_session, and cleanup logic. -
autogenstudio/mcp/wsbridge.py: Bridge class implementing protocol translation between MCP events and UI JSON messages. -
autogenstudio/mcp/client.py: Wrapsmcp.ClientSession, exposinginitializeandhandle_operationmethods to process tool calls. -
autogenstudio/mcp/callbacks.py: Creates callbacks for logging, AI sampling, and user elicitation handling. -
autogenstudio/mcp/utils.py: Error extraction, JSON serialization helpers, and WebSocket disconnect detection utilities. -
autogen_ext/tools/mcp/_config.py: Pydantic models for server parameters includingStdioServerParams,SseServerParams, andStreamableHttpServerParams. -
frontend/src/components/views/teambuilder/builder/component-editor/fields/workbench/useMcpWebSocket.ts: React hook that builds the WebSocket URL and manages the connection state.
Data Flow Walkthrough
The communication follows a strict sequence from UI initialization through tool execution and response handling.
-
Connection Initiation: The UI constructs a WebSocket URL in the format
ws://<host>/mcp/ws/<session_id>?server_params=<base64-json>, whereserver_paramsencodes the server configuration type and connection details. -
Session Creation: The
mcp_websockethandler decodes the base64 parameters and invokescreate_mcp_sessionto instantiate the appropriate MCP client (stdio, SSE, or HTTP). -
Bridge Registration: The
MCPWebSocketBridgeregisters the client viaset_mcp_clientand callsmcp_client.initialize(), relaying theinitializedevent to the UI. -
Operation Execution: The UI sends JSON messages with
"type": "operation"(e.g.,list_tools,call_tool), which the bridge forwards toMCPClient.handle_operationfor processing by the underlying MCP library. -
Response Handling: Results, errors, and sampling requests flow back through bridge callbacks (
on_operation_result,on_sampling, etc.) as typed JSON messages. -
Elicitation Management: When tools require user input, the bridge stores an
asyncio.Futureinpending_elicitationskeyed by a UUID. The UI receives anelicitation_request, and when the user responds, the bridge resolves the future to continue the MCP operation.
Implementation Examples
Frontend WebSocket Connection
The React hook in useMcpWebSocket.ts demonstrates how to construct the connection URL and manage the WebSocket lifecycle.
import { v4 as uuidv4 } from "uuid";
function buildMcpWsUrl(
host: string,
sessionId: string,
serverParams: StdioServerParams | SseServerParams | StreamableHttpServerParams
) {
const json = JSON.stringify(serverParams);
const b64 = btoa(json);
return `ws://${host}/mcp/ws/${sessionId}?server_params=${b64}`;
}
// Example: Connect to a local stdio-based tool server
const url = buildMcpWsUrl(
"localhost:8081",
uuidv4(),
{
type: "StdioServerParams",
command: "python",
args: ["-m", "my_tool_server"],
env: { OPENAI_API_KEY: "*****" }
}
);
const ws = new WebSocket(url);
ws.onmessage = ev => console.log("MCP message:", JSON.parse(ev.data));
Programmatic Python Access
You can bypass the UI entirely by connecting directly to the WebSocket endpoint using Python.
import asyncio
import json
import base64
import uuid
from websockets import connect
async def main():
# Build base64-encoded params matching the UI format
params = {
"type": "StdioServerParams",
"command": "python",
"args": ["-m", "my_tool_server"],
"env": {}
}
server_params = base64.b64encode(json.dumps(params).encode()).decode()
ws_url = f"ws://localhost:8081/mcp/ws/{uuid.uuid4()}?server_params={server_params}"
async with connect(ws_url) as ws:
# Wait for initialization confirmation
init_msg = json.loads(await ws.recv())
print("Init:", init_msg)
# List available tools
await ws.send(json.dumps({
"type": "operation",
"operation": "list_tools"
}))
tools = json.loads(await ws.recv())
print("Tools:", tools)
# Call a specific tool
await ws.send(json.dumps({
"type": "operation",
"operation": "call_tool",
"tool_name": "my_tool",
"arguments": {"text": "hello"}
}))
result = json.loads(await ws.recv())
print("Result:", result)
asyncio.run(main())
Extending with Custom Operations
To add new operation types, extend the handle_operation method in autogenstudio/mcp/client.py.
# In autogenstudio/mcp/client.py
elif operation_type == "custom_foo":
payload = operation.get("payload", {})
result = await self.session.custom_foo(payload)
await self.event_handler.on_operation_result(
"custom_foo",
{"payload": payload, "result": result}
)
The UI can then invoke this custom operation by sending:
{
"type": "operation",
"operation": "custom_foo",
"payload": { "key": "value" }
}
Configuration and Server Types
The integration supports three transport mechanisms defined in autogen_ext/tools/mcp/_config.py:
- StdioServerParams: For local subprocess-based tools requiring command and arguments
- SseServerParams: For Server-Sent Events HTTP connections
- StreamableHttpServerParams: For modern streamable HTTP-based MCP servers
Each model validates the specific parameters required for its transport type, ensuring type-safe configuration when building the WebSocket URL.
Summary
- The MCP Workbench provides a WebSocket gateway that bridges AutoGen Studio's UI with external MCP-compatible tool servers.
- Key architectural components include the FastAPI router (
mcp.py), protocol bridge (wsbridge.py), and client wrapper (client.py). - The system supports stdio, SSE, and streamable HTTP transports through Pydantic configuration models.
- Data flows through initialization, operation execution, and response handling with support for user elicitation and AI sampling.
- Both frontend TypeScript and backend Python can interact with the Workbench using the same WebSocket protocol.
Frequently Asked Questions
What transport protocols does the MCP Workbench support?
The MCP Workbench supports three transport mechanisms: stdio for local subprocess communication, Server-Sent Events (SSE) for HTTP streaming, and streamable HTTP for modern MCP servers. These are configured via StdioServerParams, SseServerParams, and StreamableHttpServerParams models in autogen_ext/tools/mcp/_config.py.
How does the Workbench handle user input requests from tools?
When an MCP tool requires user input, the bridge stores an asyncio.Future in a pending_elicitations dictionary keyed by a UUID. The UI receives an elicitation_request message and responds with an elicitation_response containing the UUID and user data, which resolves the future and allows the MCP operation to continue execution.
Can I connect to MCP servers without using the AutoGen Studio UI?
Yes, you can connect programmatically by constructing the same WebSocket URL used by the frontend. Encode your server parameters as base64 JSON and connect to ws://<host>/mcp/ws/<session_id>?server_params=<params>. You can then send operation messages and receive responses using any WebSocket client library in Python, TypeScript, or other languages.
Where do I add support for a new MCP server type?
To add a new server type, define a Pydantic model in autogen_ext/tools/mcp/_config.py, import it at the top of autogenstudio/web/routes/mcp.py, and extend the create_mcp_session function with a new conditional branch to instantiate the appropriate MCP client. The bridge and callback layers remain unchanged because they operate on the generic MCP protocol.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →