docs-use-connect.md
Smithery gives you a simple REST interface for connecting to MCP servers. Instead of implementing the MCP protocol directly, handling OAuth flows, and managing credentials yourself, Smithery handles all of it for you.The auth and credential layer is powered by the open-source agent.pw.
Smithery lets you add MCP server integrations to your app without managing the complexity yourself:
auth_required.Typed SDK
# 1. Log in to Smithery
smithery auth login
# 2. Connect to the Exa search server
smithery mcp add exa --id exa
# 3. List available tools
smithery tool list exa
# 4. Call a tool
smithery tool call exa search '{"query": "latest news about MCP"}'
npm install @smithery/api @ai-sdk/mcp ai @ai-sdk/anthropic
import { createMCPClient } from '@ai-sdk/mcp';
import { generateText } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { createConnection } from '@smithery/api/mcp';
const { transport } = await createConnection({
mcpUrl: 'https://mcp.exa.ai',
});
const mcpClient = await createMCPClient({ transport });
const tools = await mcpClient.tools();
const { text } = await generateText({
model: anthropic('claude-sonnet-4-20250514'),
tools,
prompt: 'Search for the latest news about MCP.',
});
await mcpClient.close();
npm install @smithery/api @modelcontextprotocol/sdk
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { createConnection } from '@smithery/api/mcp';
const { transport } = await createConnection({
mcpUrl: 'https://mcp.exa.ai',
});
// Connect using the MCP SDK Client
const mcpClient = new Client({ name: 'my-app', version: '1.0.0' });
await mcpClient.connect(transport);
// Use the MCP SDK's ergonomic API
const { tools } = await mcpClient.listTools();
const result = await mcpClient.callTool({
name: 'search',
arguments: { query: 'latest news about MCP' }
});
Typed SDKs are in preview. Breaking changes may happen without notice.
Every MCP server published on Smithery gets a typed TypeScript SDK generated from its tool and trigger schemas. Use it when you already have a live Smithery connection and want typed tool calls instead of string-based callTool calls. Create or reuse a connection first, then pass its namespace and connectionId.
npm install https://pkg.smithery.ai/exa
import { Exa } from '@smithery/exa';
const exa = new Exa({
namespace: 'my-app',
connectionId: 'exa',
});
const result = await exa.tools.search({
query: 'latest news about MCP',
});
For tools with output schemas, the typed SDK returns structuredContent typed from that schema. If a server returns structured data as a JSON or XML string, the SDK parses it first, converts XML into JSON-shaped data, and validates the parsed value before returning the result.SDKs are served from pkg.smithery.ai paths shaped like namespace/slug. The class name is the PascalCase form of the slug, so smithery-ai/github exports Github; if there is no slug, the namespace becomes the class name, like exa exporting Exa.
// Use callTool when a tool was added after your SDK was generated.
const result = await exa.callTool('search', { query: 'latest news about MCP' });
Some MCP servers require configuration like API keys or project IDs. How you pass each config value depends on the server’s schema — some values go as headers (typically API keys), while others go as query parameters in the MCP URL.Check the server’s page on smithery.ai to see what configuration it requires and where each value should go.
cURL
# Add a server with config (API key as header, project ID as query param)
smithery mcp add \
'@browserbasehq/mcp-browserbase?browserbaseProjectId=your-project-id' \
--id my-browserbase \
--headers '{"browserbaseApiKey": "your-browserbase-api-key"}'
import Smithery from '@smithery/api';
import { createConnection } from '@smithery/api/mcp';
const smithery = new Smithery();
// 1. Create a connection with the server's config
// - API keys go in `headers`
// - Other config goes as query params in `mcpUrl`
const conn = await smithery.connections.set('my-browserbase', {
namespace: 'my-app',
mcpUrl: 'https://mcp.browserbase.com/mcp?browserbaseProjectId=your-project-id',
headers: {
'browserbaseApiKey': 'your-browserbase-api-key',
},
});
// conn.status.state === "connected" — ready to use immediately
// 2. Get a transport for the connection
const { transport } = await createConnection({
client: smithery,
namespace: 'my-app',
connectionId: conn.connectionId,
});
curl -X POST "https://smithery.run/my-app" \
-H "Authorization: Bearer $SMITHERY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"mcpUrl": "https://mcp.browserbase.com/mcp?browserbaseProjectId=your-project-id",
"headers": {
"browserbaseApiKey": "your-browserbase-api-key"
}
}'
Unlike OAuth-based servers that return auth_required, servers configured with API keys return connected immediately when all required fields are provided upfront. If any required fields are missing, the connection returns input_required with the config schema and missing fields — see Handling Configuration below.
Each server’s config schema specifies whether a field is passed as a header or query parameter via the x-from metadata. See Session Configuration for details on how servers declare their config transport.
When your agent serves multiple users, you’ll need to track which connections belong to which user. Use the metadata field to associate connections with your users, then filter by metadata to retrieve a specific user’s connections.
When a user wants to connect an integration (e.g., GitHub), create a connection with their userId in metadata:
TypeScript
smithery mcp add github \
--id user-123-github \
--name "GitHub" \
--metadata '{"userId": "user-123"}'
# If OAuth is required, the CLI outputs the auth URL:
# → auth_required
# → https://auth.smithery.ai/...
# Visit the URL to authorize
const conn = await smithery.connections.set('user-123-github', {
namespace: 'my-app',
mcpUrl: 'https://github.run.tools',
name: 'GitHub',
metadata: { userId: 'user-123' }
});
if (conn.status.state === 'auth_required') {
// Redirect user to the hosted Smithery setup flow
redirect(conn.status.setupUrl);
}
When your agent needs to know what tools are available for a user, list their connections:
TypeScript
smithery mcp list --metadata '{"userId": "user-123"}'
const result = await smithery.connections.list('my-app', {
metadata: { userId: 'user-123' }
});
// Show the user their connected integrations
for (const conn of result.connections) {
console.log(`${conn.name}: ${conn.status.state}`);
}
Create MCP clients for each connection and aggregate their tools:
TypeScript
# List tools for a connection
smithery tool list user-123-github
# Call a tool
smithery tool call user-123-github search_repositories \
'{"query": "mcp"}'
const allTools = [];
for (const conn of result.connections) {
if (conn.status.state === 'connected') {
const { transport } = await createConnection({
namespace: 'my-app',
connectionId: conn.connectionId,
});
const client = await createMCPClient({ transport });
allTools.push(...await client.tools());
}
}
// Now your agent has tools from all the user's connected integrations
const { text } = await generateText({
model: anthropic('claude-sonnet-4-20250514'),
tools: allTools,
prompt: userMessage,
});
Or skip the iteration entirely and hand a single namespace URL to an MCP client.
A namespace URL bundles all of a namespace’s connections behind one MCP endpoint, so the same set of tools is portable across clients (Claude.ai, Cursor, ChatGPT, MCP Inspector) without configuring each connection in each app:
https://mcp.smithery.run/{namespace}
Tool names come back prefixed with their connection ID — notion-personal.search, user-123-github.search_repositories — so they stay unique. On tools/call, Connect strips the prefix and forwards to the matching connection.To restrict the URL to one user’s connections, mint a service token scoped to metadata.userId — same metadata model as Multi-User Setup. The endpoint also advertises protected-resource metadata, so MCP clients run the OAuth flow on their own without extra wiring.
A namespace is a globally unique identifier that groups your connections. Create one namespace per application or environment (e.g., my-app, my-app-staging). If you don’t specify a namespace, the SDK uses your first existing namespace or creates one automatically.
A connection is a long-lived session to an MCP server that persists until terminated. Each connection:
connectionId (developer-defined or auto-generated)metadata for filtering (e.g., userId to associate connections with your users)serverInfo with the MCP server’s name and versioncreateConnection Options
| Option | Type | Description |
|---|---|---|
client | Smithery? | The Smithery client instance. If not provided, auto-created using SMITHERY_API_KEY env var |
mcpUrl | string? | The MCP server URL. Required when connectionId is not provided |
namespace | string? | If omitted, uses first existing namespace or creates one |
connectionId | string? | If omitted, an ID is auto-generated |
Returns a SmitheryConnection object (transport, connectionId, url). Throws SmitheryAuthorizationError if OAuth authorization is required (see Handling Authorization).
When you create or retrieve a connection, it includes a status field:
| Status | Description |
|---|---|
connected | Connection is ready to use |
auth_required | OAuth authorization needed. Includes setupUrl |
input_required | Server needs configuration (e.g., API keys). Includes setupUrl, http (the config schema), and missing (fields not yet provided) |
error | Connection failed. Includes error message |
Smithery uses two authentication methods:
| Token | Use Case | Access |
|---|---|---|
| API Key | Backend only | Full namespace access |
| Service Token | Browser, mobile, agents | Scoped access to specific connections |
Get your API key from smithery.ai/account/api-keys.
Never expose your API key to untrusted clients or agents. Use scoped service tokens for browser and mobile apps.
When an MCP server requires OAuth:
auth_required with a hosted setupUrlsetupUrlYou don’t need to register OAuth apps, configure redirect URIs, or handle token exchange. Smithery manages the OAuth relationship with upstream providers and stores credentials securely on your behalf.
When you need to send a user through OAuth, prefer creating or updating the connection first and redirecting to the hosted setupUrl. That gives you a stable connectionId to retry with after the user returns to your app.
TypeScript
# Connect to a server that requires OAuth
smithery mcp add github
# If auth is required, the CLI outputs the setup URL:
# → auth_required
# → https://auth.smithery.ai/...
# → connection_id: abc-123-github
# Visit the URL to authorize, then retry
const conn = await smithery.connections.set('abc-123-github', {
namespace: 'my-app',
mcpUrl: 'https://github.run.tools',
});
if (conn.status?.state === 'auth_required') {
redirect(conn.status.setupUrl);
}
// Save conn.connectionId and retry with it after the user returns
After the user completes authorization and returns to your app, retry with the saved connectionId:
TypeScript
# After authorization, the connection is ready
smithery tool list abc-123-github
const { transport } = await createConnection({
connectionId: savedConnectionId,
});
const mcpClient = await createMCPClient({ transport });
const tools = await mcpClient.tools();
input_required)When a server requires configuration that wasn’t provided, the connection returns input_required with:
setupUrl — a hosted Smithery setup page you can redirect the user to instead of building your own formhttp — the config schema (headers and query parameters the server accepts)missing — which fields still need to be providedIn a TTY terminal, the CLI prompts for missing values automatically. Otherwise, provide them explicitly:
cURL
# Interactive: CLI prompts for missing fields
smithery mcp add browserbase --id my-browserbase
# Non-interactive: pass config upfront
smithery mcp add \
'https://mcp.browserbase.com/mcp?browserbaseProjectId=your-project-id' \
--id my-browserbase \
--headers '{"browserbaseApiKey": "your-api-key"}'
const conn = await smithery.connections.set('my-browserbase', {
namespace: 'my-app',
mcpUrl: 'https://mcp.browserbase.com/mcp',
});
if (conn.status.state === 'input_required') {
// Option 1: redirect(conn.status.setupUrl)
// Option 2: render your own form from conn.status.http
// conn.status.http has the config schema, conn.status.missing lists unfilled fields
const updated = await smithery.connections.set('my-browserbase', {
namespace: 'my-app',
mcpUrl: 'https://mcp.browserbase.com/mcp?browserbaseProjectId=your-project-id',
headers: { browserbaseApiKey: 'your-api-key' },
});
}
# Create — returns input_required if config is missing
curl -X PUT "https://smithery.run/my-app/my-browserbase" \
-H "Authorization: Bearer $SMITHERY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"mcpUrl": "https://mcp.browserbase.com/mcp"}'
# Update with required config (same endpoint, PUT is an upsert)
curl -X PUT "https://smithery.run/my-app/my-browserbase" \
-H "Authorization: Bearer $SMITHERY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"mcpUrl": "https://mcp.browserbase.com/mcp?browserbaseProjectId=your-project-id",
"headers": { "browserbaseApiKey": "your-api-key" }
}'
MCP requests to a connection in input_required state will be rejected until the required configuration is provided. While input_required, the mcpUrl can be updated with query parameters as long as the host and path remain the same.
Service tokens let you safely use Smithery from browsers, mobile apps, and AI agents without exposing your API key. Your backend mints a scoped token, then your client uses it to call tools directly.
cURL
smithery auth token --policy '[{
"namespaces": "my-app",
"resources": "connections",
"operations": ["read", "execute"],
"metadata": { "userId": "user-123" },
"ttl": "1h"
}]'
// Create a token scoped to a specific user's connections
const { token } = await smithery.tokens.create({
policy: [
{
namespaces: 'my-app',
resources: 'connections',
operations: ['read', 'execute'],
metadata: { userId: 'user-123' },
ttl: '1h',
},
],
})
// Send `token` to your client — safe for browser use
curl -X POST https://api.smithery.ai/tokens \
-H "Authorization: Bearer $SMITHERY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"policy": [
{
"namespaces": "my-app",
"resources": "connections",
"operations": ["read", "execute"],
"metadata": { "userId": "user-123" },
"ttl": "1h"
}
]
}'
This token can only access connections in my-app where metadata.userId matches user-123. Initialize the client with the token:
TypeScript
# Use the scoped token to call tools
SMITHERY_API_KEY=$TOKEN smithery tool list user-123-github
const smithery = new Smithery({ apiKey: token })
const { transport } = await createConnection({
client: smithery,
namespace: 'my-app',
connectionId: 'user-123-github',
})
Need workspace-level scoping, read-only tokens, or token narrowing? See Token Scoping for the full guide.
For full API documentation, see the API Reference section in the sidebar.
Use the CLI or an MCP client over your connection’s transport:
TypeScript
# List available tools
smithery tool list user-123-github
# Call a tool
smithery tool call user-123-github search_repositories \
'{"query": "mcp"}'
const { transport } = await createConnection({
client: smithery,
namespace: 'my-app',
connectionId: 'user-123-github',
})
const mcpClient = await createMCPClient({ transport })
const tools = await mcpClient.tools()
const result = await mcpClient.callTool({
name: 'search_repositories',
arguments: { query: 'mcp' },
})
await mcpClient.close()
Was this page helpful?
YesNo
⌘I