SDK · Growth+
Custom MCP servers
Register MCP server endpoints — internal tools, third-party MCPs we haven't pre-built, anything that speaks the MCP protocol. Apps in your org get the URL and auth headers through one SDK call. The bearer token never lives in your app code.
1. Register the MCP server (once, on the dashboard)
On the org page, the “Custom MCP servers” card asks for:
- A slug your app uses to look it up (
acme-tools,internal-billing-mcp, …) - The MCP URL (must be HTTPS)
- Auth:
nonefor public MCPs, orbearerwith a token (encrypted with your org's KMS key)
2. Pull the config in your app
getCustomMcpConfig returns { url, headers } with the bearer Authorization already attached. Plug those two values into whichever MCP client your app uses — Leash is not in the request path between your app and the MCP.
import { LeashIntegrations } from '@leash/sdk/integrations'import { Client } from '@modelcontextprotocol/sdk/client/index.js'import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'const leash = new LeashIntegrations({ apiKey: process.env.LEASH_API_KEY })const cfg = await leash.getCustomMcpConfig('acme-tools')const transport = new StreamableHTTPClientTransport(new URL(cfg.url), {requestInit: { headers: cfg.headers },})const mcp = new Client({ name: 'my-app', version: '1.0.0' })await mcp.connect(transport)const tools = await mcp.listTools()
Why config-handoff and not proxying
We thought about putting Leash in the MCP request path — terminate the MCP client atleash.build/mcp/<slug>, forward to the customer's server. Three reasons we didn't:
- Latency. Tool calls are on the LLM's critical path. Adding an extra hop per call is felt.
- MCP transports change fast. Streamable HTTP, SSE, stdio. Proxying means we'd be reimplementing each transport with our own bugs.
- The thing we're actually solving is “keep the bearer token out of the customer's code.” Once we hand them
headers.Authorization, they're unblocked. Anything else is scope creep.
Failure modes
unknown_mcp_server— slug not registered (or revoked). Check the dashboard.upgrade_required— Growth plan or higher.- The Leash SDK does not validate that the upstream MCP is up. If your customer's MCP is down, your MCP client will surface the error directly.