pub struct McpProxy { /* private fields */ }Expand description
An MCP proxy that aggregates multiple backend servers.
Implements Service<RouterRequest> so it can be used with any tower-mcp
transport (HTTP, WebSocket, stdio) and composed with tower middleware.
Each backend’s capabilities are namespaced to avoid collisions, and
individual backends can have their own Tower middleware stack applied
via McpProxyBuilder::backend_layer().
Backends can be added dynamically at runtime via add_backend().
All clones of the proxy share the same backend list, so additions are
immediately visible to all request handlers.
Implementations§
Source§impl McpProxy
impl McpProxy
Sourcepub fn builder(
name: impl Into<String>,
version: impl Into<String>,
) -> McpProxyBuilder
pub fn builder( name: impl Into<String>, version: impl Into<String>, ) -> McpProxyBuilder
Create a builder for configuring the proxy.
Sourcepub async fn add_backend(
&self,
namespace: impl Into<String>,
transport: impl ClientTransport,
) -> Result<(), AddBackendError>
pub async fn add_backend( &self, namespace: impl Into<String>, transport: impl ClientTransport, ) -> Result<(), AddBackendError>
Add a backend dynamically from a ClientTransport.
The transport is connected, the MCP initialize handshake runs, and capabilities are discovered. The new backend is immediately available to all clones of this proxy.
§Errors
Returns an error if:
- The namespace is already in use
- The namespace creates an ambiguous prefix with an existing backend
- The transport fails to connect
- The MCP initialize handshake fails
§Example
proxy.add_backend("new-db", StdioClientTransport::spawn("db-server", &[]).await?).await?;
// New backend is immediately available for requestsSourcepub async fn add_backend_with_layer<L>(
&self,
namespace: impl Into<String>,
transport: impl ClientTransport,
layer: L,
) -> Result<(), AddBackendError>where
L: Layer<BackendService> + Send + 'static,
L::Service: Service<RouterRequest, Response = RouterResponse> + Clone + Send + 'static,
<L::Service as Service<RouterRequest>>::Error: Display + Send,
<L::Service as Service<RouterRequest>>::Future: Send,
pub async fn add_backend_with_layer<L>(
&self,
namespace: impl Into<String>,
transport: impl ClientTransport,
layer: L,
) -> Result<(), AddBackendError>where
L: Layer<BackendService> + Send + 'static,
L::Service: Service<RouterRequest, Response = RouterResponse> + Clone + Send + 'static,
<L::Service as Service<RouterRequest>>::Error: Display + Send,
<L::Service as Service<RouterRequest>>::Future: Send,
Add a backend dynamically with a custom middleware-wrapped service.
Like add_backend(), but applies a Tower layer
to the backend’s dispatch service before adding it.
§Example
use std::time::Duration;
use tower::timeout::TimeoutLayer;
proxy.add_backend_with_layer(
"slow-api",
transport,
TimeoutLayer::new(Duration::from_secs(60)),
).await?;Sourcepub async fn remove_backend(&self, namespace: &str) -> bool
pub async fn remove_backend(&self, namespace: &str) -> bool
Remove a backend by namespace name.
The backend’s tools, resources, and prompts are immediately removed from aggregated lists. Downstream clients are notified via list-changed notifications.
Returns true if the backend was found and removed, false if no
backend with that namespace exists.
§Example
if proxy.remove_backend("old-db").await {
println!("Backend removed");
}Sourcepub async fn replace_backend(
&self,
namespace: impl Into<String>,
transport: impl ClientTransport,
) -> Result<(), AddBackendError>
pub async fn replace_backend( &self, namespace: impl Into<String>, transport: impl ClientTransport, ) -> Result<(), AddBackendError>
Sourcepub fn backend_namespaces(&self) -> Vec<String>
pub fn backend_namespaces(&self) -> Vec<String>
Sourcepub fn backend_count(&self) -> usize
pub fn backend_count(&self) -> usize
Return the number of currently registered backends.
Sourcepub async fn health_check(&self) -> Vec<BackendHealth>
pub async fn health_check(&self) -> Vec<BackendHealth>
Check the health of all backends by pinging them concurrently.
Returns a map of namespace to health status. Backends that respond to ping within a reasonable time are considered healthy.
Trait Implementations§
Source§impl Service<RouterRequest> for McpProxy
impl Service<RouterRequest> for McpProxy
Source§type Response = RouterResponse
type Response = RouterResponse
Source§type Error = Infallible
type Error = Infallible
Source§type Future = Pin<Box<dyn Future<Output = Result<RouterResponse, Infallible>> + Send>>
type Future = Pin<Box<dyn Future<Output = Result<RouterResponse, Infallible>> + Send>>
Auto Trait Implementations§
impl !RefUnwindSafe for McpProxy
impl !UnwindSafe for McpProxy
impl Freeze for McpProxy
impl Send for McpProxy
impl Sync for McpProxy
impl Unpin for McpProxy
impl UnsafeUnpin for McpProxy
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<S, R> ServiceExt<R> for Swhere
S: Service<R>,
impl<S, R> ServiceExt<R> for Swhere
S: Service<R>,
Source§fn into_make_service(self) -> IntoMakeService<S>
fn into_make_service(self) -> IntoMakeService<S>
MakeService, that is a Service whose
response is another service. Read moreSource§fn into_make_service_with_connect_info<C>(
self,
) -> IntoMakeServiceWithConnectInfo<S, C>
fn into_make_service_with_connect_info<C>( self, ) -> IntoMakeServiceWithConnectInfo<S, C>
MakeService, that will store C’s
associated ConnectInfo in a request extension such that ConnectInfo
can extract it. Read moreSource§fn handle_error<F, T>(self, f: F) -> HandleError<Self, F, T>
fn handle_error<F, T>(self, f: F) -> HandleError<Self, F, T>
HandleError, that will handle errors
by converting them into responses. Read moreSource§impl<T, Request> ServiceExt<Request> for T
impl<T, Request> ServiceExt<Request> for T
Source§fn ready(&mut self) -> Ready<'_, Self, Request>where
Self: Sized,
fn ready(&mut self) -> Ready<'_, Self, Request>where
Self: Sized,
Source§fn ready_oneshot(self) -> ReadyOneshot<Self, Request>where
Self: Sized,
fn ready_oneshot(self) -> ReadyOneshot<Self, Request>where
Self: Sized,
Source§fn oneshot(self, req: Request) -> Oneshot<Self, Request>where
Self: Sized,
fn oneshot(self, req: Request) -> Oneshot<Self, Request>where
Self: Sized,
Service, calling it with the provided request once it is ready.Source§fn and_then<F>(self, f: F) -> AndThen<Self, F>
fn and_then<F>(self, f: F) -> AndThen<Self, F>
poll_ready method. Read moreSource§fn map_response<F, Response>(self, f: F) -> MapResponse<Self, F>
fn map_response<F, Response>(self, f: F) -> MapResponse<Self, F>
poll_ready method. Read moreSource§fn map_err<F, Error>(self, f: F) -> MapErr<Self, F>
fn map_err<F, Error>(self, f: F) -> MapErr<Self, F>
poll_ready method. Read moreSource§fn map_result<F, Response, Error>(self, f: F) -> MapResult<Self, F>
fn map_result<F, Response, Error>(self, f: F) -> MapResult<Self, F>
Result<Self::Response, Self::Error>)
to a different value, regardless of whether the future succeeds or
fails. Read more