Conduit SDK
Drop-in MCP client for Python, TypeScript, and Rust
Conduit replaces your existing MCP client with a single import swap. Your agent code works unchanged. The SDK transparently routes every call through the DataGrout intelligence layer, giving you discovery, planning, policy enforcement, and cost tracking without rewriting anything.
Installation
Python
pip install datagrout-conduit
TypeScript / Node.js
npm install datagrout-conduit
Rust
cargo add datagrout-conduit
Connect to Your Server
You need your server URL (from the dashboard) and an authentication credential.
Python
from datagrout.conduit import Client
client = Client(
"https://gateway.datagrout.ai/servers/YOUR_SERVER_ID/mcp",
auth={"bearer": "dg_your_token_here"},
)
await client.connect()
TypeScript
import { Client } from '@datagrout/conduit';
const client = new Client({
url: 'https://gateway.datagrout.ai/servers/YOUR_SERVER_ID/mcp',
auth: { bearer: 'dg_your_token_here' },
});
await client.connect();
Rust
use datagrout_conduit::{ClientBuilder, Transport};
let client = ClientBuilder::new()
.url("https://gateway.datagrout.ai/servers/YOUR_SERVER_ID/mcp")
.auth_bearer("dg_your_token_here")
.build()?;
client.connect().await?;
Standard MCP Operations
Conduit supports the full MCP protocol surface. These calls behave identically to any MCP client.
List Tools
tools = client.list_tools()
for tool in tools:
print(tool.name, tool.description)
Call a Tool
result = client.call_tool(
"salesforce@1/get_leads@1",
{"limit": 10}
)
DataGrout Extensions
Beyond standard MCP, Conduit exposes three methods that access the intelligence layer directly.
discover()
Find tools by meaning, not by name. Returns ranked matches based on semantic similarity to your query.
results = client.discover(
query="create an invoice",
limit=5,
min_score=0.5
)
for match in results:
print(match.tool.name, match.score)
Use goal instead of query when you want multi-step planning:
plan = client.discover(
goal="sync qualified leads to invoices"
)
Filter to a specific integration:
results = client.discover(
query="list customers",
integration="quickbooks"
)
guide()
Start an interactive decision tree to build a workflow step-by-step.
session = client.guide(goal="export invoices to PDF")
# System returns options at each step
print(session.message)
for option in session.options:
print(option.id, option.label)
# Select a choice by ID
session = client.guide(choice="1.2")
See Guide Mode for the full walkthrough.
perform()
Execute a tool directly through the intelligence layer. Equivalent to call_tool but routes through policy enforcement, cost tracking, and optional output transformations.
result = client.perform(
"quickbooks@1/create_invoice@1",
{"customer_id": "123", "amount": 1500.00}
)
Cost Tracking
Every tool call returns a receipt with credit costs. Use extract_meta() to access it.
Python
from datagrout.conduit import extract_meta
result = await client.call_tool("salesforce@1/get_leads@1", {"limit": 10})
meta = extract_meta(result)
if meta:
print(meta.receipt.net_credits)
print(meta.receipt.savings)
TypeScript
import { extractMeta } from '@datagrout/conduit';
const result = await client.callTool('salesforce@1/get_leads@1', { limit: 10 });
const meta = extractMeta(result);
if (meta) {
console.log(meta.receipt.netCredits);
console.log(meta.receipt.savings);
}
Rust
let result = client.call_tool("salesforce@1/get_leads@1", json!({"limit": 10})).await?;
let meta = client.extract_meta(&result)?;
println!("Cost: {} credits", meta.receipt.actual_credits);
See Credits and Receipts for receipt fields and BYOK discounts.
Transport Options
Conduit supports two transport protocols. Both provide identical access to the intelligence layer.
| Transport | Protocol | Streaming | Use When |
|---|---|---|---|
Transport.Mcp |
JSON-RPC 2.0 over SSE | Yes | Your agent framework supports MCP |
Transport.JsonRpc |
JSON-RPC 2.0 over HTTP POST | No | Legacy systems, simple HTTP clients |
# MCP transport (streaming, persistent connection)
client = ClientBuilder().transport(Transport.Mcp).build()
# JSON-RPC transport (stateless HTTP POST)
client = ClientBuilder().transport(Transport.JsonRpc).build()
Authentication
Conduit supports three authentication methods: bearer tokens, OAuth 2.1, and mutual TLS.
Bearer Token
The simplest option. Create a token in your server settings.
Python
client = Client(
"https://gateway.datagrout.ai/servers/YOUR_UUID/mcp",
auth={"bearer": "your-token"},
)
Rust
let client = ClientBuilder::new()
.url("https://gateway.datagrout.ai/servers/YOUR_UUID/mcp")
.auth_bearer("your-token")
.build()?;
OAuth 2.1 (client_credentials)
For machine-to-machine authentication. The SDK handles token exchange and refresh automatically.
Python
client = Client(
"https://gateway.datagrout.ai/servers/YOUR_UUID/mcp",
client_id="your-client-id",
client_secret="your-client-secret",
)
Rust
let client = ClientBuilder::new()
.url("https://gateway.datagrout.ai/servers/YOUR_UUID/mcp")
.auth_client_credentials("your-client-id", "your-client-secret")
.build()?;
Mutual TLS (mTLS)
Certificate-based authentication for production agents. After bootstrapping, no tokens or secrets are needed โ the client certificate is the credential.
Bootstrap once, connect forever:
# First run: register identity with the DataGrout CA
client = await Client.bootstrap_identity(
url="https://gateway.datagrout.ai/servers/YOUR_UUID/mcp",
auth_token="your-access-token",
name="my-agent",
)
# All subsequent runs: mTLS auto-discovered from ~/.conduit/
client = Client("https://gateway.datagrout.ai/servers/YOUR_UUID/mcp")
Auto-discovery searches:
-
CONDUIT_MTLS_CERT/CONDUIT_MTLS_KEYenv vars (inline PEM) -
CONDUIT_IDENTITY_DIRenv var (directory path) -
~/.conduit/ -
.conduit/relative to cwd
Multiple agents on one machine:
client = Client(
"https://gateway.datagrout.ai/servers/YOUR_UUID/mcp",
identity_dir="/opt/agents/agent-a/.conduit",
identity_auto=True,
)
See Authentication for the full reference.
Full Example
Connect, discover a tool, execute it, and check the cost.
from datagrout.conduit import Client, extract_meta
async with Client(
"https://gateway.datagrout.ai/servers/YOUR_SERVER_ID/mcp",
auth={"bearer": "dg_your_token_here"},
) as client:
# Find the right tool by intent
matches = await client.discover(query="list recent invoices", limit=3)
tool = matches[0].tool
# Execute it
result = await client.call_tool(tool.name, {"limit": 25})
# Check cost
meta = extract_meta(result)
if meta:
print(f"Credits: {meta.receipt.net_credits}, savings: {meta.receipt.savings}")
Related
- Quick Start โ Set up your first server
- Core Concepts โ Servers, integrations, tools, policies
- Credits and Receipts โ Cost model and receipt fields
- Authentication โ Full auth reference