DEV Community

Cover image for Building My Own Remote MCP Server in Rust (Even Though `mcp-remote` Already Exists 😅)
Rakibul Yeasin
Rakibul Yeasin

Posted on

Building My Own Remote MCP Server in Rust (Even Though `mcp-remote` Already Exists 😅)

Lately, I’ve been using Zed along with Claude CLI - a combo that makes my local workflow feel a bit too nice. Naturally, I started wondering:

“What if I could integrate remote MCP servers directly, without juggling separate plugins or Docker containers?”

Turns out… there’s already a perfectly good solution for that - the mcp-remote package.
But curiosity (and mild developer arrogance) got the better of me.

So I built my own.
In Rust.

Because why take the easy route when you can spend three nights fighting lifetimes and async traits just to prove a point?


Introducing: MCP Remote Proxy

The project is called MCP Remote Proxy - a Rust-based bridge that connects your local MCP client to remote MCP servers over any transport layer.
It acts as a translator between the two worlds, making communication work even when transport protocols don’t match.

In short: it speaks MCP fluently - over HTTP, STDIO, or TCP - and switches automatically when things fail.

It even supports OAuth 2.1 authentication, load balancing, and detailed debug logging when the universe (inevitably) breaks.


Architecture in a Nutshell 🧠

The project is split into modular crates, because monoliths are for the weak:

├── crates/
│   ├── mcp-types/      # Common data types and interfaces
│   ├── mcp-server/     # Local MCP server (STDIO)
│   ├── mcp-client/     # Remote transport logic
│   ├── mcp-proxy/      # Message forwarding core
│   └── mcp-connect/    # CLI entrypoint
└── examples/           # Integration tests & usage demos
Enter fullscreen mode Exit fullscreen mode

Each crate has a specific purpose:

  • 🦀 mcp-server - Handles local STDIO transport and JSON-RPC messaging
  • 🌐 mcp-client - Talks to remote servers via HTTP, STDIO, or TCP
  • 🔁 mcp-proxy - The middleman that forwards, retries, and balances traffic
  • 💻 mcp-connect - A CLI utility that ties everything together

The proxy implements MCP 2024-11-05 spec compliance, JSON-RPC 2.0 message flow, and async communication via Tokio.
It’s a surprisingly clean setup once the compiler stops yelling at you.


Features That Sound Fancier Than They Are

  • Transport Agnostic – Works with HTTP, STDIO, and TCP, and auto-fallbacks between them
  • OAuth 2.1 Authentication – For modern services that don’t trust you yet
  • Smart Fallbacks & Retries – Because connections will fail
  • Load Balancing – Spread requests across multiple remote endpoints
  • MCP-Compliant Logging – STDIO, STDERR, and notification-based debug modes

And yes, it’s built entirely on Tokio, Clap, and Serde, with traits abstracted for easy extension.


Why Bother?

Honestly? Curiosity.
There’s already a working npm package that does this just fine - but the Rust version is faster, native, and way more fun to build.

Plus, watching an LLM agent write half the code while I just sit there pretending to “review” it was weirdly satisfying. 🥲


Example: Connect Your Local Client to a Remote MCP Server

mcp-connect proxy \
  --endpoint "https://mcp.context7.com/mcp" \
  --auth-token "ctx7sk-your-api-key" \
  --fallbacks "stdio,tcp" \
  --debug
Enter fullscreen mode Exit fullscreen mode

That’s it - your local MCP client now speaks to a remote server as if it were running locally.
The proxy negotiates the transport, manages tokens, and logs everything you wish you didn’t have to debug.


Load Balancing Demo

mcp-connect load-balance \
  --endpoints "http://server1:8080/mcp,http://server2:8080/mcp,http://server3:8080/mcp" \
  --transport "http" \
  --auth-token "your-token" \
  --debug
Enter fullscreen mode Exit fullscreen mode

It’s not exactly Kubernetes, but it gets the job done - evenly, and without crying.


The Inevitable Pain Points

Like every Rust project, the first few hours were just:

error[E0495]: cannot infer an appropriate lifetime
Enter fullscreen mode Exit fullscreen mode

But after wrestling with async_trait, Send + Sync bounds, and a few dozen compiler errors later, it finally came together.

The reward: a blazingly fast, transport-flexible proxy that runs anywhere - local, remote, or Dockerized.


Lessons Learned

  1. If you think “someone must’ve already built this,” you’re probably right.
  2. Build it anyway - you’ll learn way more than reading their source.
  3. Let the LLM write the boilerplate. You handle the architecture.

Final Thoughts

Was it necessary?
Absolutely not.

Was it worth it?
Absolutely yes.

Because sometimes dev projects aren’t about reinventing the wheel - they’re about scratching that one annoying curiosity itch until it turns into a Git repo.


🦀 Source: GitHub - MCP Connect


Top comments (0)