Production-ready MCP client with mTLS identity, OAuth 2.1, semantic discovery, and cost tracking.
- MCP Protocol Compliance: Full JSON-RPC 2.0 over HTTP/SSE support
- mTLS Identity: Auto-discovery, bootstrap, and rotation of client certificates
- OAuth 2.1: Built-in
client_credentialstoken management with auto-refresh - DataGrout Extensions: Semantic discovery, guided workflows, cost tracking
- Type-Safe: Strongly typed Rust APIs with comprehensive error handling
- Async/Await: Built on Tokio for high performance
Add to your Cargo.toml:
[dependencies]
datagrout-conduit = "0.1.0"
tokio = { version = "1", features = ["full"] }
serde_json = "1.0"use datagrout_conduit::{ClientBuilder, Transport};
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create client
let client = ClientBuilder::new()
.url("https://gateway.datagrout.ai/servers/{uuid}/mcp")
.transport(Transport::Mcp)
.auth_bearer("your-token")
.build()?;
// Connect and initialize
client.connect().await?;
// List tools
let tools = client.list_tools().await?;
println!("Found {} tools", tools.len());
// Call a tool
let result = client
.call_tool("salesforce@1/get_lead@1", json!({"id": "123"}))
.await?;
Ok(())
}// 10-100x token efficiency via semantic search
let results = client.discover()
.query("get lead by email")
.integration("salesforce")
.limit(10)
.min_score(0.7)
.execute()
.await?;
for tool in results.tools {
println!("{} (score: {:.2})", tool.tool.name, tool.score);
}// Step-by-step workflow with user choices
let mut session = client.guide()
.goal("create invoice from lead")
.execute()
.await?;
while session.status() != "completed" {
if let Some(options) = session.options() {
// Show options to user and get choice
let chosen = options[0].id.clone();
session = session.choose(&chosen).await?;
}
}
let result = session.complete().await?;// Execute with tracking and receipts
let result = client.perform("salesforce@1/get_lead@1")
.args(json!({"email": "john@example.com"}))
.demux(false)
.execute()
.await?;
// Get cost breakdown
if let Some(receipt) = client.last_receipt().await {
println!("Cost: {} credits", receipt.total_cost);
}let client = ClientBuilder::new()
.url("https://gateway.datagrout.ai/servers/{uuid}/mcp")
.build()?; // MCP transport by defaultFeatures:
- Server-Sent Events (SSE)
- Real-time notifications
- Persistent connection
- Full MCP compliance
let client = ClientBuilder::new()
.url("https://api.example.com/rpc")
.transport(Transport::JsonRpc) // Simple HTTP POST
.build()?;Features:
- Lightweight HTTP POST
- Stateless requests
- Easier debugging
- Lower overhead
let client = ClientBuilder::new()
.url("...")
.auth_bearer("your-token")
.build()?;let client = ClientBuilder::new()
.url("...")
.auth_api_key("your-key")
.build()?;let client = ClientBuilder::new()
.url("...")
.auth_basic("username", "password")
.build()?;let client = ClientBuilder::new()
.url("https://gateway.datagrout.ai/servers/{uuid}/mcp")
.auth_client_credentials("my_client_id", "my_client_secret")
.build()?;The SDK automatically fetches, caches, and refreshes JWTs before they expire.
After bootstrapping, the client certificate handles authentication at the TLS layer — no tokens needed.
// Auto-discover from env vars, CONDUIT_IDENTITY_DIR, or ~/.conduit/
let client = ClientBuilder::new()
.url("https://gateway.datagrout.ai/servers/{uuid}/mcp")
.with_identity_auto()
.build()?;
// Multiple agents on one machine
let client = ClientBuilder::new()
.url("...")
.identity_dir("/opt/agents/agent-a/.conduit")
.with_identity_auto()
.build()?;identity_dir()option (if provided)CONDUIT_MTLS_CERT+CONDUIT_MTLS_KEYenvironment variables (inline PEM)CONDUIT_IDENTITY_DIRenvironment variable (directory path)~/.conduit/identity.pem+~/.conduit/identity_key.pem.conduit/relative to the current working directory
For DataGrout URLs (*.datagrout.ai), auto-discovery runs silently in build().
First-run provisioning — generates a keypair, registers with the DataGrout CA, and saves certs locally. After this, the token is never needed again. Requires the registration feature.
// First run: token needed for registration
let client = ClientBuilder::new()
.url("https://gateway.datagrout.ai/servers/{uuid}/mcp")
.bootstrap_identity("your-access-token", "my-laptop")
.await?
.build()?;
// Or bootstrap with OAuth 2.1 client_credentials
let client = ClientBuilder::new()
.url("https://gateway.datagrout.ai/servers/{uuid}/mcp")
.bootstrap_identity_oauth("client_id", "client_secret", "my-laptop")
.await?
.build()?;
// Subsequent runs: no token needed, mTLS auto-discovered
let client = ClientBuilder::new()
.url("https://gateway.datagrout.ai/servers/{uuid}/mcp")
.build()?;use datagrout_conduit::error::{Error, Result};
match client.call_tool("tool", json!({})).await {
Ok(result) => println!("Success: {:?}", result),
Err(Error::Mcp { code, message, .. }) => {
eprintln!("MCP error {}: {}", code, message);
}
Err(Error::NotInitialized) => {
eprintln!("Call connect() first");
}
Err(e) if e.is_retriable() => {
eprintln!("Retriable error: {}", e);
// Retry logic here
}
Err(e) => eprintln!("Fatal error: {}", e),
}let client = ClientBuilder::new()
.url("...")
.max_retries(5) // Retry up to 5 times on "not initialized"
.build()?;let client = ClientBuilder::new()
.url("...")
.use_intelligent_interface(true) // Expose only semantic discovery tools
.build()?;// List resources
let resources = client.list_resources().await?;
// Read a resource
let contents = client.read_resource("file://path/to/file").await?;// List prompts
let prompts = client.list_prompts().await?;
// Get a prompt
let messages = client.get_prompt(
"template_name",
Some(json!({"var": "value"}))
).await?;See the examples/ directory:
basic.rs- Basic MCP operationsdiscovery.rs- Semantic discovery and performguided_workflow.rs- Step-by-step workflows
Run examples:
cargo run --example basic
cargo run --example discovery
cargo run --example guided_workflow# Run unit tests
cargo test
# Run integration tests (requires server)
cargo test --ignored
# Run with logging
RUST_LOG=debug cargo testBenchmarks on M1 Max:
- Client creation: 50μs
- Request serialization: 2μs
- Response parsing: 3μs
- Full round-trip: 15-50ms (network-bound)
┌──────────────────────┐
│ Your Application │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ Conduit Client │
│ • Builder │
│ • MCP Protocol │
│ • Extensions │
└──────────┬───────────┘
│
┌──────┴──────┐
▼ ▼
┌─────────┐ ┌──────────┐
│ MCP │ │ JSON-RPC │
│Transport│ │Transport │
└────┬────┘ └─────┬────┘
│ │
└──────┬──────┘
▼
┌───────────────────────┐
│ DataGrout Gateway │
│ (MCP Server) │
└───────────────────────┘
| Feature | Rust | Python | TypeScript |
|---|---|---|---|
| mTLS Identity | ✅ Full | ✅ Full | ✅ Full |
| OAuth 2.1 | ✅ Full | ✅ Full | ✅ Full |
| Bootstrap | ✅ Token + OAuth | ✅ Token + OAuth | ✅ Token |
| Type Safety | ✅ Strong | ✅ Compile-time | |
| Async | ✅ Tokio | ✅ asyncio | ✅ Promises |
MIT License - see LICENSE for details.
- DataGrout: https://datagrout.ai
- Documentation: https://library.datagrout.ai/conduit-sdk
- Repository: https://github.com/DataGrout/conduit-sdk
- Issues: https://github.com/DataGrout/conduit-sdk/issues
- MCP Spec: https://modelcontextprotocol.io
- Contact: hello@datagrout.ai