Skip to main content

systemprompt_api/services/proxy/engine/
handlers.rs

1//! Axum handler adapters for the MCP and agent proxy routes, each delegating
2//! to [`ProxyEngine::proxy_request`]. The service-name path segment is parsed
3//! once here; a malformed one answers 400 `invalid_identifier`.
4//!
5//! Copyright (c) systemprompt.io — Business Source License 1.1.
6//! See <https://systemprompt.io> for licensing details.
7
8use axum::body::Body;
9use axum::extract::{Path, Request, State};
10use axum::response::{IntoResponse, Response};
11use systemprompt_identifiers::ServiceName;
12use systemprompt_runtime::AppContext;
13
14use super::{ProxyEngine, ProxyKind, ProxyTarget};
15use crate::services::proxy::backend::ProxyError;
16
17impl ProxyEngine {
18    pub async fn handle_mcp_request_with_path(
19        &self,
20        path_params: Path<(String, String)>,
21        State(ctx): State<AppContext>,
22        request: Request<Body>,
23    ) -> Response<Body> {
24        let Path((raw_service_name, path)) = path_params;
25        let service_name = match ServiceName::try_new(raw_service_name) {
26            Ok(name) => name,
27            Err(error) => return ProxyError::from(error).into_response(),
28        };
29        let target = ProxyTarget {
30            service_name: &service_name,
31            path: &path,
32            kind: ProxyKind::Mcp,
33        };
34        match self.proxy_request(target, request, ctx).await {
35            Ok(response) => response,
36            Err(e) => e.into_response(),
37        }
38    }
39
40    pub async fn handle_agent_request(
41        &self,
42        path_params: Path<(String,)>,
43        State(ctx): State<AppContext>,
44        request: Request<Body>,
45    ) -> Response<Body> {
46        let Path((raw_service_name,)) = path_params;
47        self.agent_request(&raw_service_name, "", ctx, request)
48            .await
49    }
50
51    pub async fn handle_agent_request_with_path(
52        &self,
53        path_params: Path<(String, String)>,
54        State(ctx): State<AppContext>,
55        request: Request<Body>,
56    ) -> Response<Body> {
57        let Path((raw_service_name, path)) = path_params;
58        self.agent_request(&raw_service_name, &path, ctx, request)
59            .await
60    }
61
62    async fn agent_request(
63        &self,
64        raw_service_name: &str,
65        path: &str,
66        ctx: AppContext,
67        request: Request<Body>,
68    ) -> Response<Body> {
69        let service_name = match ServiceName::try_new(raw_service_name) {
70            Ok(name) => name,
71            Err(error) => return ProxyError::from(error).into_response(),
72        };
73        let target = ProxyTarget {
74            service_name: &service_name,
75            path,
76            kind: ProxyKind::Agent,
77        };
78        match self.proxy_request(target, request, ctx).await {
79            Ok(response) => response,
80            Err(e) => e.to_status_code().into_response(),
81        }
82    }
83}