gopher-mcp-rust 0.1.2-10

Rust SDK for Gopher Orch - AI Agent orchestration framework
Documentation

gopher-mcp-rust - Rust SDK

Rust SDK for Gopher Orch - AI Agent orchestration framework with native C++ performance.

Table of Contents


Features

  • Native Performance - Powered by C++ core with Rust bindings via libloading
  • AI Agent Framework - Build intelligent agents with LLM integration
  • MCP Protocol - Model Context Protocol client and server support
  • Tool Orchestration - Manage and execute tools across multiple MCP servers
  • State Management - Built-in state graph for complex workflows
  • Memory Safety - Rust's ownership system with zero-cost abstractions
  • OAuth 2.0 Authentication - JWT validation with JWKS support (feature-gated)

When to Use This SDK

This SDK is ideal for:

  • Rust applications that need high-performance AI agent orchestration
  • Systems programming requiring MCP protocol support with memory safety
  • CLI tools integrating AI agents with native performance
  • WebAssembly targets (with appropriate native library builds)
  • Embedded systems needing lightweight agent infrastructure

Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Your Application                         │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  Rust SDK (gopher_mcp_rust)                 │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │ GopherAgent │  │ConfigBuilder│  │ Error Types         │  │
│  └─────────────┘  └─────────────┘  └─────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
                              │ FFI (libloading)
                              ▼
┌─────────────────────────────────────────────────────────────┐
│              Native Library (libgopher-orch)                │
│  ┌───────────────┐  ┌───────────────┐  ┌─────────────────┐  │
│  │ Agent Engine  │  │ LLM Providers │  │ MCP Client      │  │
│  │               │  │ - Anthropic   │  │ - HTTP/SSE      │  │
│  │               │  │ - OpenAI      │  │ - Tool Registry │  │
│  └───────────────┘  └───────────────┘  └─────────────────┘  │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    MCP Servers                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │ Weather API │  │ Database    │  │ Custom Tools        │  │
│  └─────────────┘  └─────────────┘  └─────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

Installation

Option 1: From crates.io

[dependencies]
gopher-mcp-rust = "0.1.2"

Option 2: Git Dependency

[dependencies]
gopher-mcp-rust = { git = "https://github.com/GopherSecurity/gopher-mcp-rust.git" }

Option 3: Build from Source

See Building from Source section below.

With Auth Feature

Enable OAuth 2.0 / JWT authentication support:

[dependencies]
gopher-mcp-rust = { version = "0.1.2", features = ["auth"] }

# Or with git
gopher-mcp-rust = { git = "https://github.com/GopherSecurity/gopher-mcp-rust.git", features = ["auth"] }

Quick Start

use gopher_mcp_rust::{GopherAgent, ConfigBuilder};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create an agent with API key (fetches server config from remote API)
    let config = ConfigBuilder::new()
        .with_provider("AnthropicProvider")
        .with_model("claude-3-haiku-20240307")
        .with_api_key("your-api-key")
        .build();

    let agent = GopherAgent::create(config)?;

    // Run the agent
    let result = agent.run("What is the weather in Tokyo?")?;
    println!("{}", result);

    // Agent is automatically cleaned up when dropped
    Ok(())
}

Building from Source

This SDK wraps a native C++ library via libloading. You must build the native library before using the SDK.

Prerequisites

Requirement Version Notes
Rust >= 1.64 Stable toolchain
Cargo Latest Comes with Rust
Git Latest For cloning and submodules
CMake >= 3.15 Native library build system
C++ Compiler C++14+ Clang (macOS), GCC (Linux), MSVC (Windows)

Platform-specific requirements:

  • macOS: Xcode Command Line Tools (xcode-select --install)
  • Linux: build-essential, libssl-dev
  • Windows: Visual Studio 2019+ with C++ workload

Step 1: Clone the Repository

git clone https://github.com/GopherSecurity/gopher-mcp-rust.git
cd gopher-mcp-rust

Step 2: Build Everything

Using build.sh (recommended)

The build.sh script handles everything automatically:

./build.sh

Using build.sh with Multiple GitHub Accounts:

If you have multiple GitHub accounts configured with SSH host aliases, use the GITHUB_SSH_HOST environment variable:

# Use custom SSH host alias for cloning private submodules
GITHUB_SSH_HOST=your-ssh-alias ./build.sh

# Example: if your ~/.ssh/config has "Host github-work" for work account
GITHUB_SSH_HOST=github-work ./build.sh

What happens during build:

  1. Submodule update - Initializes and updates submodules (with SSH URL rewriting if GITHUB_SSH_HOST is set)
  2. CMake configure - Configures the C++ build with Release settings
  3. Native compilation - Compiles C++ to shared libraries
  4. Library installation - Copies libraries to native/lib/
  5. Dependency copying - Copies required dependencies (gopher-mcp, fmt)
  6. macOS fixes - Fixes dylib install names for proper runtime loading
  7. Cargo build - Compiles Rust SDK
  8. Tests - Runs Cargo tests

Step 3: Verify the Build

# Check native libraries were built
ls -la native/lib/

# Expected output (macOS):
# libgopher-orch.dylib
# libgopher-mcp.dylib
# libgopher-mcp-event.dylib
# libfmt.dylib

# Verify Rust build
cargo build

Step 4: Run Tests

cargo test

Native Library Details

Library Location

After building, native libraries are installed to:

native/
├── lib/                          # Shared libraries
│   ├── libgopher-orch.dylib     # Main orchestration library (macOS)
│   ├── libgopher-orch.so        # Main orchestration library (Linux)
│   ├── libgopher-mcp.dylib      # MCP protocol library
│   ├── libgopher-mcp-event.dylib # Event handling
│   └── libfmt.dylib             # Formatting library
└── include/                      # C++ headers (for development)
    └── orch/
        └── core/

Platform-Specific Library Names

Platform Library Extension Example
macOS .dylib libgopher-orch.dylib
Linux .so libgopher-orch.so
Windows .dll gopher-orch.dll

Library Search Order

The SDK searches for the native library in this order:

  1. native/lib/ relative to executable
  2. ./native/lib/ relative to working directory
  3. CARGO_MANIFEST_DIR/native/lib/ (compile time)
  4. System library paths

API Documentation

GopherAgent

The main struct for creating and running AI agents:

use gopher_mcp_rust::{GopherAgent, ConfigBuilder, AgentResult};

// Initialize the library (called automatically on first create)
gopher_mcp_rust::init()?;

// Create with API key (fetches server config from remote API)
let config = ConfigBuilder::new()
    .with_provider("AnthropicProvider")
    .with_model("claude-3-haiku-20240307")
    .with_api_key("your-api-key")
    .build();

let agent = GopherAgent::create(config)?;

// Or create with JSON server config
let server_config = r#"
    {
        "succeeded": true,
        "data": {
            "servers": [{
                "serverId": "server1",
                "name": "My MCP Server",
                "transport": "http_sse",
                "config": {"url": "http://localhost:3001/mcp"}
            }]
        }
    }
"#;

let agent = GopherAgent::create_with_server_config(
    "AnthropicProvider",
    "claude-3-haiku-20240307",
    server_config,
)?;

// Run a query
let result = agent.run("Your prompt here")?;

// Run with custom timeout (default: 60000ms)
let result = agent.run_with_timeout("Your prompt here", 30000)?;

// Run with detailed result information
let detailed: AgentResult = agent.run_detailed("Your prompt here");
// Returns AgentResult with: response(), status(), iteration_count(), tokens_used()

// Manual cleanup (optional - happens automatically on drop)
drop(agent);

// Shutdown library
gopher_mcp_rust::shutdown();

ConfigBuilder

Builder for creating agent configurations:

use gopher_mcp_rust::ConfigBuilder;

// With API key
let config = ConfigBuilder::new()
    .with_provider("AnthropicProvider")
    .with_model("claude-3-haiku-20240307")
    .with_api_key("your-api-key")
    .build();

// With server config
let config = ConfigBuilder::new()
    .with_provider("AnthropicProvider")
    .with_model("claude-3-haiku-20240307")
    .with_server_config(r#"{"succeeded": true, "data": {"servers": []}}"#)
    .build();

// Check configuration
assert!(config.has_api_key());
assert!(!config.has_server_config());

Error Handling

The SDK provides typed errors for different failure scenarios:

use gopher_mcp_rust::{GopherAgent, ConfigBuilder, Error};

fn main() {
    let config = ConfigBuilder::new()
        .with_provider("AnthropicProvider")
        .with_model("claude-3-haiku-20240307")
        .with_api_key("invalid-key")
        .build();

    match GopherAgent::create(config) {
        Ok(agent) => {
            match agent.run("query") {
                Ok(result) => println!("{}", result),
                Err(Error::Timeout(msg)) => eprintln!("Query timed out: {}", msg),
                Err(e) => eprintln!("Query error: {}", e),
            }
        }
        Err(Error::Library(msg)) => eprintln!("Library not found: {}", msg),
        Err(Error::Config(msg)) => eprintln!("Invalid config: {}", msg),
        Err(Error::Agent(msg)) => eprintln!("Agent error: {}", msg),
        Err(e) => eprintln!("Error: {}", e),
    }
}

Examples

Basic Usage with API Key

use gopher_mcp_rust::{GopherAgent, ConfigBuilder};
use std::env;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = env::var("GOPHER_API_KEY")?;

    let config = ConfigBuilder::new()
        .with_provider("AnthropicProvider")
        .with_model("claude-3-haiku-20240307")
        .with_api_key(&api_key)
        .build();

    let agent = GopherAgent::create(config)?;

    let answer = agent.run("What time is it in London?")?;
    println!("Answer: {}", answer);

    Ok(())
}

Using Local MCP Servers

use gopher_mcp_rust::{GopherAgent, ConfigBuilder};

const SERVER_CONFIG: &str = r#"{
    "succeeded": true,
    "code": 200,
    "message": "OK",
    "data": {
        "servers": [
            {
                "version": "1.0.0",
                "serverId": "weather-server",
                "name": "Weather Service",
                "transport": "http_sse",
                "config": {
                    "url": "http://localhost:3001/mcp",
                    "headers": {}
                },
                "connectTimeout": 5000,
                "requestTimeout": 30000
            }
        ]
    }
}"#;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = ConfigBuilder::new()
        .with_provider("AnthropicProvider")
        .with_model("claude-3-haiku-20240307")
        .with_server_config(SERVER_CONFIG)
        .build();

    let agent = GopherAgent::create(config)?;

    let result = agent.run("What is the weather in New York?")?;
    println!("{}", result);

    Ok(())
}

Running the Example

# Run with the convenience script (starts servers automatically)
cd examples
./client_example_json_run.sh

# Or manually:
# Terminal 1: Start server3001
cd examples/server3001 && npm install && npm run dev

# Terminal 2: Start server3002
cd examples/server3002 && npm install && npm run dev

# Terminal 3: Run the Rust client
ANTHROPIC_API_KEY=your-key cargo run --example client_example_json

Auth MCP Server Example

The examples/auth directory contains a complete OAuth 2.0 protected MCP server example using Axum:

cd examples/auth

# Run with auth disabled (development mode)
./run_example.sh --no-auth

# Run with full OAuth support
./run_example.sh

Features:

  • OAuth 2.0 / OIDC discovery endpoints (RFC 8414, RFC 9728)
  • JWT token validation via native library
  • Scope-based authorization for MCP tools
  • Example weather tools with different scope requirements

Available Tools:

Tool Scope Required Description
get-weather None Get current weather for a city
get-forecast mcp:read Get 5-day weather forecast
get-weather-alerts mcp:admin Get weather alerts for a region

Using the Auth Client:

use gopher_mcp_rust::GopherAuthClient;

// Create auth client with JWKS endpoint
let client = GopherAuthClient::new(
    "https://auth.example.com/.well-known/jwks.json",
    "https://auth.example.com"
)?;

// Validate a JWT token
let result = client.validate_token("eyJ...", 60);
if result.valid {
    println!("Token is valid!");
    println!("Subject: {}", result.payload.sub);
    println!("Scopes: {:?}", result.payload.scope);
}

// Extract payload without validation
let payload = client.extract_payload("eyJ...")?;

See examples/auth/README.md for full documentation.


Development

Project Structure

gopher-mcp-rust/
├── src/
│   ├── lib.rs                    # Library entry point
│   ├── agent.rs                  # GopherAgent implementation
│   ├── config.rs                 # Configuration builder
│   ├── error.rs                  # Error types
│   ├── result.rs                 # AgentResult types
│   └── ffi.rs                    # FFI bindings (libloading)
├── tests/
│   └── ffi_tests.rs              # Integration tests
├── native/                       # Native libraries (generated)
│   ├── lib/                      # Shared libraries (.dylib, .so, .dll)
│   └── include/                  # C++ headers
├── third_party/                  # Git submodules
│   └── gopher-orch/              # C++ implementation
├── examples/                     # Example code
│   ├── client_example_json.rs
│   ├── client_example_json_run.sh
│   ├── server3001/               # Mock weather MCP server
│   └── server3002/               # Mock tools MCP server
├── build.sh                      # Build orchestration script
├── Cargo.toml                    # Cargo build configuration
└── README.md

Build Scripts

Script Description
./build.sh Full build (submodules + native + Rust SDK)
GITHUB_SSH_HOST=alias ./build.sh Build with custom SSH host
cargo build Compile Rust SDK
cargo test Run tests
cargo build --release Release build
cargo run --example client_example_json Run example

Rebuilding Native Library

If you modify the C++ code or switch branches:

# Clean and rebuild
rm -rf third_party/gopher-orch/build native/lib
./build.sh

Updating Submodules

To pull latest changes from native libraries:

# Update to latest commit
cd third_party/gopher-orch
git fetch origin
git checkout <commit-or-branch>
cd ../..

# Rebuild
rm -rf native/lib
./build.sh

Troubleshooting

"Library not found" Error

Cause: Native library not built or not in expected location.

Solution:

# Rebuild native library
./build.sh

# Verify library exists
ls native/lib/libgopher-orch.*

"Submodule is empty" Error

Cause: Git submodules not initialized.

Solution:

git submodule update --init --recursive

CMake Configuration Fails

Cause: Missing dependencies or wrong CMake version.

Solution:

# macOS
brew install cmake

# Linux (Ubuntu/Debian)
sudo apt-get install cmake build-essential libssl-dev

# Verify version
cmake --version  # Should be >= 3.15

Linking Error at Runtime

Cause: libloading can't find the native library.

Solution:

# Run from project root
cargo run --example client_example_json

# Or set library path
export DYLD_LIBRARY_PATH=$PWD/native/lib:$DYLD_LIBRARY_PATH  # macOS
export LD_LIBRARY_PATH=$PWD/native/lib:$LD_LIBRARY_PATH      # Linux

Build Fails on Apple Silicon (M1/M2)

Cause: Architecture mismatch.

Solution:

# Ensure using native arm64 toolchain
arch -arm64 ./build.sh

Rust Version Compatibility

Cause: Using older Rust toolchain.

Solution:

# Update Rust
rustup update stable

# Or use minimum supported version
rustup install 1.64
rustup default 1.64

Contributing

Contributions are welcome! Please read our contributing guidelines.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Ensure submodules are initialized (git submodule update --init --recursive)
  4. Make your changes
  5. Run tests (cargo test)
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

License

Apache License 2.0 - see LICENSE file for details.

Links

Acknowledgments