Client-side MCP Connection
Connect to MCP servers from your application to extend Tambo's capabilities
Client-side Support
Client-side MCP integration allows your application to connect to MCP servers that are accessible from the end user's browser, for instance when using a local MCP server.
This is useful for:
- Local MCP servers running on the user's machine
- MCP servers where the user's browser is already authenticated
- Private or internal services behind a firewall, that are only visible from the user's browser
Note: There is currently no support for authenticated MCP servers when using client-side MCP connections.
To implement client-side MCP support, pass mcpServers to TamboProvider and wrap your app with TamboMcpProvider:
import { TamboProvider } from "@tambo-ai/react";
import { TamboMcpProvider, MCPTransport } from "@tambo-ai/react/mcp";
function MyApp() {
return (
<TamboProvider
components={...}
mcpServers={[
{
// MCP server configuration
url: "http://localhost:8123/",
// Optional stable prefix used when multiple MCP servers are configured
// If omitted, a key is derived from the URL hostname (e.g., "https://mcp.linear.app/mcp" -> "linear")
serverKey: "local",
// Optional custom headers, eg.
// { "Authorization": `Bearer ${token}` } or { "X-Api-Key": "1234567890" }
customHeaders: {},
transport: MCPTransport.HTTP, // optional, defaults to HTTP
},
]}
>
<TamboMcpProvider>
{/* Your application components */}
</TamboMcpProvider>
</TamboProvider>
);
}Note: As of
@tambo-ai/react@0.65.0, passmcpServerstoTamboProviderinstead ofTamboMcpProvider.
The TamboMcpProvider establishes connections to the specified MCP servers and makes their tools available to Tambo agents in your application.
Note
When more than one MCP server is configured, Tambo prefixes names to avoid collisions using the
serverKey:
- Prompts:
serverKey:promptName(colon separator)- Tools:
serverKey__toolName(double-underscore separator)If you do not provide
serverKey, Tambo derives one from the server URL (for example,https://mcp.linear.app/mcpbecomeslinear). To keep things predictable across environments, setserverKeyexplicitly. Avoid using:and__in theserverKeysince prompts use:and tools use__as separators; prefer letters, numbers,_, and-.
Control Flow
Working with MCP Resources
MCP servers can expose resources (such as files, documents, or other data) that can be referenced in prompts. Tambo provides hooks and UI components to work with these resources.
Using Resource Hooks
The useTamboMcpResourceList hook fetches all available resources from connected MCP servers:
import { useTamboMcpResourceList } from "@tambo-ai/react/mcp";
function MyComponent() {
const { data: resources, isLoading } = useTamboMcpResourceList();
if (isLoading) return <div>Loading resources...</div>;
return (
<ul>
{resources?.map((entry) => (
<li key={entry.resource.uri}>
{entry.resource.name || entry.resource.uri}
</li>
))}
</ul>
);
}To read a specific resource, use the useTamboMcpResource hook:
import { useTamboMcpResource } from "@tambo-ai/react/mcp";
function ResourceViewer({ uri }: { uri: string }) {
const { data: resource } = useTamboMcpResource(uri);
if (!resource) return null;
return (
<div>
{resource.contents.map((content, i) => (
<div key={i}>{content.text || content.blob}</div>
))}
</div>
);
}Resource Button in Message Input
The MessageInput.McpResourceButton component provides a searchable combobox for inserting resource references into messages:
import { MessageInput } from "@/components/ui/message-input";
function ChatInterface() {
return (
<MessageInput contextKey="my-thread">
<MessageInput.Textarea />
<MessageInput.Toolbar>
<MessageInput.FileButton />
<MessageInput.McpPromptButton />
<MessageInput.McpResourceButton />
<MessageInput.SubmitButton />
</MessageInput.Toolbar>
</MessageInput>
);
}When a user selects a resource from the button, it inserts a reference with the syntax @<resourceUri> (e.g., @file:///path/to/file.txt or @linear:file://issue/123 if multiple servers are configured).
Working with MCP Prompts
MCP servers can also expose prompts - pre-defined message templates that can be inserted into conversations.
Using Prompt Hooks
The useTamboMcpPromptList hook fetches all available prompts:
import { useTamboMcpPromptList } from "@tambo-ai/react/mcp";
function PromptList() {
const { data: prompts } = useTamboMcpPromptList();
return (
<ul>
{prompts?.map((entry) => (
<li key={entry.prompt.name}>
{entry.prompt.name}
{entry.prompt.description && ` - ${entry.prompt.description}`}
</li>
))}
</ul>
);
}To fetch a specific prompt, use useTamboMcpPrompt:
import { useTamboMcpPrompt } from "@tambo-ai/react/mcp";
function PromptInserter({ promptName }: { promptName: string }) {
const { data: prompt } = useTamboMcpPrompt(promptName, {
// Optional arguments for the prompt
arg1: "value1",
});
if (!prompt) return null;
// Extract text from prompt messages
const promptText = prompt.messages
.map((msg) => (msg.content.type === "text" ? msg.content.text : ""))
.filter(Boolean)
.join("\n");
return <div>{promptText}</div>;
}Prompt Button in Message Input
The MessageInput.McpPromptButton component provides a dropdown menu for inserting prompts:
import { MessageInput } from "@/components/ui/message-input";
function ChatInterface() {
return (
<MessageInput contextKey="my-thread">
<MessageInput.Textarea />
<MessageInput.Toolbar>
<MessageInput.McpPromptButton />
<MessageInput.SubmitButton />
</MessageInput.Toolbar>
</MessageInput>
);
}Server Namespacing
When multiple MCP servers are configured, tools, prompts, and resources are automatically prefixed with a serverKey to avoid naming conflicts:
- Tools:
<serverKey>__<toolName>(e.g.,linear__create_issue) - Prompts:
<serverKey>:<promptName>(e.g.,linear:new-issue) - Resources:
<serverKey>:<resourceUri>(e.g.,linear:file://issue/123)
The serverKey is automatically derived from the server URL (e.g., "linear" from "https://mcp.linear.app"), or you can specify it explicitly:
<TamboProvider
mcpServers={[
{
url: "https://mcp.linear.app",
serverKey: "linear", // Optional: explicitly set the key
transport: MCPTransport.HTTP,
},
{
url: "https://api.github.com/mcp",
serverKey: "github",
transport: MCPTransport.HTTP,
},
]}
>
<TamboMcpProvider>{/* Your app */}</TamboMcpProvider>
</TamboProvider>When only one server is configured, no prefixes are applied (backward compatible).