DEV Community

Cover image for How RustAPI Turns Every Endpoint Into an AI Agent Tool In-Process, No Glue Code
Tunay
Tunay

Posted on

How RustAPI Turns Every Endpoint Into an AI Agent Tool In-Process, No Glue Code

Picture this: you've built a solid REST API. FastAPI, Express, Go doesn't matter. It works. Then someone says "we need AI agents to use our API."

Now you're writing a separate MCP server. Maintaining tool definitions that mirror your routes. Keeping schemas in sync. Debugging network timeouts between agent→proxy→API.

What if your framework just... handled this?

MCP in 30 seconds

Model Context Protocol (MCP) is how AI agents call external tools. Claude Desktop uses it. Cursor uses it. VS Code agents use it.

An MCP tool has:

  • A name and description
  • An input schema (JSON Schema)
  • A handler function

That's literally an API endpoint with an OpenAPI spec.

The RustAPI approach: automatic tool registration

use rustapi_rs::prelude::*;
use rustapi_rs::protocol::mcp::{McpConfig, InvocationMode};

#[tokio::main]
async fn main() {
    let app = RustApi::new()
        .route(get_weather)
        .route(post_order);

    // This single call:
    // 1. Reads the OpenAPI spec RustAPI auto-generates
    // 2. Creates MCP tool definitions for every route
    // 3. Wires handlers that dispatch through your middleware stack
    let mcp = McpServer::from_rustapi(
        &app,
        McpConfig::new()
            .name("my-api".into())
            .invocation_mode(InvocationMode::InProcess)
    );

    mcp.serve_stdio().await.unwrap();
}
Enter fullscreen mode Exit fullscreen mode

No manual tool registration. No schema duplication. Your endpoints are the tools.

Architecture: what happens on a tool call

AI Agent
  → MCP Server (stdio/HTTP)
    → RequestInvoker (internal dispatch)
      → Router::dispatch()
        → LayerStack (auth, rate limit, logging, middleware)
          → Your handler function
      ← Response
    ← MCP tool result
  ← Agent sees result
Enter fullscreen mode Exit fullscreen mode

The key: InProcess mode skips the network entirely. The RequestInvoker creates an internal request and dispatches it through the same Router that handles HTTP. Your middleware runs. Your interceptors fire. But no TCP socket. No serialization.

Benchmark reality check


// Test: 1000 sequential MCP tool calls
// RustAPI 0.1.507, Intel i7-12700H, Windows 11

InProcess mode:   27.9 µs/call  (35,842 calls/sec)
Proxy mode:     1350.0 µs/call  (741 calls/sec)
                     ~48x faster
Enter fullscreen mode Exit fullscreen mode

Why does this matter? An agent making 20 tool calls per user query with proxy mode = 27ms overhead. With InProcess = 0.5ms. That's the difference between "snappy" and "loading..."

The CLI: your existing API just got MCP powers

Not using RustAPI? The CLI bridges that gap:

# Install
cargo install cargo-rustapi --features mcp

# From any OpenAPI spec (FastAPI, Express, Go anything with OpenAPI)
rustapi mcp generate --spec ./openapi.json

# Results:
# ✓ Generated MCP tools: getWeather, postOrder, listProducts
# ✓ Server running on http://localhost:9090
# ✓ Connect Claude Desktop to http://localhost:9090/sse
Enter fullscreen mode Exit fullscreen mode

Under the hood, it:

  1. Parses the OpenAPI spec (tolerant of partial/incomplete specs)
  2. Maps HTTP methods + paths → MCP tool names
  3. Maps parameter schemas → MCP input schemas
  4. Generates proxy handlers that call your real API
  5. Spins up a fully typed MCP server

This works with any API that has an OpenAPI spec. FastAPI, Express, Go, Python doesn't matter.

Why stdio transport matters

rustapi mcp generate --spec openapi.json --stdio
Enter fullscreen mode Exit fullscreen mode

Stdio is the native transport for desktop AI clients. Claude Desktop reads MCP server configs and spawns processes. Your API becomes a first-class tool in the desktop agent's arsenal no HTTP server, no port conflicts, no CORS.

Putting it all together: a full example

use rustapi_rs::prelude::*;
use rustapi_rs::protocol::mcp::{McpServer, McpConfig, InvocationMode};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct Weather {
    city: String,
    temp_c: f64,
    humidity: u8,
}

/// Get current weather for a city
#[get("/weather/{city}")]
async fn get_weather(city: Path<String>) -> Result<Json<Weather>, Error> {
    // Real app: call weather API, query DB, etc.
    Ok(Json(Weather {
        city: city.into_inner(),
        temp_c: 22.5,
        humidity: 65,
    }))
}

/// Create a new order
#[post("/orders")]
async fn create_order(
    body: Json<CreateOrderRequest>,
) -> Result<Json<Order>, Error> {
    // ... order logic
}

#[tokio::main]
async fn main() {
    let app = RustApi::new()
        .route(get_weather)
        .route(create_order);

    // Auto-generate MCP tools from routes
    // get_weather → MCP tool "getWeather" with {city: string} input
    // create_order → MCP tool "createOrder" with full request schema
    let mcp = McpServer::from_rustapi(
        &app,
        McpConfig::new()
            .name("my-api".into())
            .invocation_mode(InvocationMode::Auto) // InProcess if possible
    );

    // Serve via stdio for Claude Desktop integration
    mcp.serve_stdio().await.unwrap();
}
Enter fullscreen mode Exit fullscreen mode

The doc comment on get_weather becomes the MCP tool description. The Path<String> becomes the input schema. The return type determines the output. Zero additional code.

Real-world impact

Alexa (@alexabelonix, AI Distribution & Sales) put it best after trying the release:

"this just made AI agents way more useful"

Because right now, connecting agents to real APIs is the bottleneck. Every company building AI agents is building the same MCP glue. RustAPI removes that step entirely.

What's next

  1. MCP Gateway: One endpoint that exposes all deployed RustAPI apps as MCP tools a unified agent interface
  2. RustAPI Cloud: rustapi deploy → your API is live + MCP-toolable at you.rustapi.dev
  3. Streaming tool results: Long-running tools with progress updates for agents

The bet

Within 2 years, "MCP-native" will be as expected as "REST API" is today. Frameworks that don't include it will feel broken. AI agents aren't a fad — they're a new consumer of APIs, just like browsers were in 1995 and mobile apps were in 2008.

RustAPI is built for that world.

Try it

cargo add rustapi-rs --features protocol-mcp
Enter fullscreen mode Exit fullscreen mode

Or use the CLI on any existing API:

cargo install cargo-rustapi --features mcp
rustapi mcp generate --spec ./your-openapi.json
Enter fullscreen mode Exit fullscreen mode

GitHub: Tuntii/RustAPI
Docs: tuntii.github.io/RustAPI

Top comments (0)