use actix_web::HttpResponse;
use bytes::Bytes;
use futures::StreamExt;
use http_body_util::BodyExt;
use http_body_util::BodyStream;
use rust_mcp_sdk::mcp_http::GenericBody;
pub(crate) async fn to_actix_response(res: http::Response<GenericBody>) -> HttpResponse {
let (parts, body) = res.into_parts();
let status = actix_web::http::StatusCode::from_u16(parts.status.as_u16())
.unwrap_or(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR);
let is_sse = parts
.headers
.get(http::header::CONTENT_TYPE)
.and_then(|v| v.to_str().ok())
.map(|ct| ct.starts_with("text/event-stream"))
.unwrap_or(false);
if is_sse {
let stream = BodyStream::new(body).map(|result| match result {
Ok(frame) => {
let data = frame
.into_data()
.unwrap_or_else(|_| Bytes::from_static(b""));
Ok(data)
}
Err(err) => Err(actix_web::error::ErrorInternalServerError(err.to_string())),
});
let mut builder = HttpResponse::build(status);
for (name, value) in parts.headers.iter() {
if let Ok(v) = value.to_str() {
builder.insert_header((name.as_str(), v));
}
}
return builder.streaming(stream);
}
let bytes = body
.collect()
.await
.map(|collected| collected.to_bytes())
.unwrap_or_default();
let mut builder = HttpResponse::build(status);
for (name, value) in parts.headers.iter() {
if let Ok(v) = value.to_str() {
builder.insert_header((name.as_str(), v));
}
}
builder.body(bytes.to_vec())
}
pub(crate) fn from_actix_request<'a>(
req: &'a actix_web::HttpRequest,
body: Option<&'a str>,
) -> http::Request<&'a str> {
let method =
http::Method::from_bytes(req.method().as_str().as_bytes()).unwrap_or(http::Method::GET);
let uri: http::Uri = req
.uri()
.to_string()
.parse()
.unwrap_or_else(|_| "/".parse().unwrap());
let mut headers = http::HeaderMap::new();
for (name, value) in req.headers().iter() {
if let (Ok(name), Ok(value)) = (
http::HeaderName::from_bytes(name.as_str().as_bytes()),
http::HeaderValue::from_bytes(value.as_bytes()),
) {
headers.insert(name, value);
}
}
rust_mcp_sdk::mcp_http::McpHttpHandler::create_request(method, uri, headers, body)
}
pub(crate) fn to_actix_error(err: rust_mcp_sdk::mcp_http::McpHttpError) -> HttpResponse {
use rust_mcp_sdk::mcp_http::McpHttpError;
let status = match &err {
McpHttpError::SessionIdMissing => actix_web::http::StatusCode::BAD_REQUEST,
McpHttpError::SessionIdInvalid(_) => actix_web::http::StatusCode::NOT_FOUND,
McpHttpError::StreamIoError(_) => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
McpHttpError::HttpError(_) => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
McpHttpError::TransportError(_) => actix_web::http::StatusCode::BAD_GATEWAY,
};
let body = serde_json::json!({ "error": err.to_string() });
HttpResponse::build(status)
.content_type("application/json")
.json(body)
}