Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
974 changes: 974 additions & 0 deletions mcp-proxy/Cargo.lock

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions mcp-proxy/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "mcp-proxy"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.7.2"
tokio = { version = "1.34.0", features = ["full"] }
serde = { version = "1.0.193", features = ["derive"] }
serde_json = "1.0.108"
tower = "0.4.13"
tower-http = { version = "0.5.0", features = ["trace"] }
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
bytes = "1.5.0"
thiserror = "1.0.50"
anyhow = "1.0.75"
uuid = { version = "1.6.1", features = ["v4", "serde"] }
57 changes: 57 additions & 0 deletions mcp-proxy/src/handlers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use axum::{
extract::Json,
http::StatusCode,
response::{IntoResponse, Response},
};
use serde_json::json;

use crate::{mcp, python_client};

// Health check handler
pub async fn health_check() -> impl IntoResponse {
(StatusCode::OK, Json(json!({"status": "ok"})))
}

// Execute code handler
pub async fn execute_code(
Json(request): Json<mcp::McpRequest>,
) -> Result<Json<mcp::McpResponse>, AppError> {
// Execute the code using the Python client
let response = python_client::execute_code(request.code, request.session_id).await?;

// Convert the Python response to an MCP response
let mcp_response = mcp::convert_to_mcp_response(
&response.status,
response.output.as_deref(),
response.error.as_deref(),
&response.session_id,
);

Ok(Json(mcp_response))
}

// Application error type
#[derive(Debug, thiserror::Error)]
pub enum AppError {
#[error("Python client error: {0}")]
PythonClientError(#[from] anyhow::Error),
}

// Convert AppError to an HTTP response
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, error_message) = match self {
AppError::PythonClientError(err) => (
StatusCode::INTERNAL_SERVER_ERROR,
format!("Failed to execute code: {}", err),
),
};

let body = Json(json!({
"status": "error",
"error": error_message,
}));

(status, body).into_response()
}
}
35 changes: 35 additions & 0 deletions mcp-proxy/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
mod python_client;
mod mcp;
mod handlers;

use axum::{
routing::{get, post},
Router,
};
use std::net::SocketAddr;
use tower_http::trace::TraceLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

#[tokio::main]
async fn main() {
// Initialize tracing
tracing_subscriber::registry()
.with(tracing_subscriber::EnvFilter::new(
std::env::var("RUST_LOG").unwrap_or_else(|_| "info".into()),
))
.with(tracing_subscriber::fmt::layer())
.init();

// Build our application with routes
let app = Router::new()
.route("/", get(handlers::health_check))
.route("/execute", post(handlers::execute_code))
.layer(TraceLayer::new_for_http());

// Run the server
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
tracing::info!("MCP Proxy listening on {}", addr);

let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}
66 changes: 66 additions & 0 deletions mcp-proxy/src/mcp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use serde::{Deserialize, Serialize};

// MCP Request structure
#[derive(Debug, Deserialize)]
pub struct McpRequest {
pub code: String,
#[serde(default)]
pub session_id: Option<String>,
}

// MCP Response structure
#[derive(Debug, Serialize)]
pub struct McpResponse {
pub status: String,
pub content: McpContent,
pub session_id: String,
}

// MCP Content structure
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
pub enum McpContent {
#[serde(rename = "text")]
Text { text: String },
#[serde(rename = "error")]
Error { error: String },
}

impl McpResponse {
// Create a successful response
pub fn success(output: String, session_id: String) -> Self {
Self {
status: "success".to_string(),
content: McpContent::Text { text: output },
session_id,
}
}

// Create an error response
pub fn error(error_message: String, session_id: String) -> Self {
Self {
status: "error".to_string(),
content: McpContent::Error { error: error_message },
session_id,
}
}
}

// Convert from Python response to MCP response
pub fn convert_to_mcp_response(
python_status: &str,
python_output: Option<&str>,
python_error: Option<&str>,
session_id: &str,
) -> McpResponse {
match python_status {
"ok" => {
let output = python_output.unwrap_or("").to_string();
McpResponse::success(output, session_id.to_string())
}
_ => {
let error = python_error.unwrap_or("Unknown error").to_string();
McpResponse::error(error, session_id.to_string())
}
}
}
99 changes: 99 additions & 0 deletions mcp-proxy/src/python_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use anyhow::{Context, Result};
use bytes::{BufMut, BytesMut};
use serde::{Deserialize, Serialize};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;

// Python REPL server connection details
const PYTHON_SERVER_HOST: &str = "127.0.0.1";
const PYTHON_SERVER_PORT: u16 = 8000;

// Request to the Python REPL server
#[derive(Debug, Serialize)]
pub struct PythonRequest {
pub code: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
}

// Response from the Python REPL server
#[derive(Debug, Deserialize)]
pub struct PythonResponse {
pub status: String,
pub output: Option<String>,
pub error: Option<String>,
pub session_id: String,
}

// Client for communicating with the Python REPL server
pub struct PythonClient {
stream: TcpStream,
}

impl PythonClient {
// Connect to the Python REPL server
pub async fn connect() -> Result<Self> {
let addr = format!("{}:{}", PYTHON_SERVER_HOST, PYTHON_SERVER_PORT);
let stream = TcpStream::connect(&addr)
.await
.context(format!("Failed to connect to Python REPL server at {}", addr))?;

let mut client = Self { stream };

// Read the initial greeting message
let _greeting = client.read_response().await?;

Ok(client)
}

// Execute Python code on the server
pub async fn execute(&mut self, code: String, session_id: Option<String>) -> Result<PythonResponse> {
let request = PythonRequest { code, session_id };
self.send_request(&request).await?;
self.read_response().await
}

// Send a request to the Python REPL server
async fn send_request(&mut self, request: &PythonRequest) -> Result<()> {
// Serialize the request to JSON
let json = serde_json::to_string(request)?;
let json_bytes = json.as_bytes();

// Create a buffer for the message
let mut buf = BytesMut::with_capacity(4 + json_bytes.len());

// Write the message length (4 bytes, big-endian)
buf.put_u32(json_bytes.len() as u32);

// Write the JSON message
buf.put_slice(json_bytes);

// Send the message
self.stream.write_all(&buf).await?;

Ok(())
}

// Read a response from the Python REPL server
async fn read_response(&mut self) -> Result<PythonResponse> {
// Read the message length (4 bytes)
let mut length_buf = [0u8; 4];
self.stream.read_exact(&mut length_buf).await?;
let message_length = u32::from_be_bytes(length_buf) as usize;

// Read the message content
let mut message_buf = vec![0u8; message_length];
self.stream.read_exact(&mut message_buf).await?;

// Parse the JSON response
let response: PythonResponse = serde_json::from_slice(&message_buf)?;

Ok(response)
}
}

// Execute code in a session
pub async fn execute_code(code: String, session_id: Option<String>) -> Result<PythonResponse> {
let mut client = PythonClient::connect().await?;
client.execute(code, session_id).await
}
1 change: 1 addition & 0 deletions mcp-proxy/target/.rustc_info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rustc_fingerprint":2324622560586367277,"outputs":{"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.84.0 (9fc6b4312 2025-01-07)\nbinary: rustc\ncommit-hash: 9fc6b43126469e3858e2fe86cafb4f0fd5068869\ncommit-date: 2025-01-07\nhost: x86_64-unknown-linux-gnu\nrelease: 1.84.0\nLLVM version: 19.1.5\n","stderr":""}},"successes":{}}
3 changes: 3 additions & 0 deletions mcp-proxy/target/CACHEDIR.TAG
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Signature: 8a477f597d28d172789f06886806bc55
# This file is a cache directory tag created by cargo.
# For information about cache directory tags see https://bford.info/cachedir/
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
efd0f83a8019ac13
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rustc":6294317376553613522,"features":"[\"default\", \"std\"]","declared_features":"[\"backtrace\", \"default\", \"std\"]","target":13708040221295731214,"profile":13232757476167777671,"path":7594539865118149722,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/anyhow-01ea0f2ab80a119a/dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"metadata":17154292783084528516,"config":2202906307356721367,"compile_kind":0}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file has an mtime of when this was started.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
b33dc64224bb9ee9
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rustc":6294317376553613522,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[434603458838584,"build_script_build",false,1417536021250756847]],"local":[{"RerunIfChanged":{"output":"debug/build/anyhow-3d186dd9d16c37da/output","paths":["build/probe.rs"]}},{"RerunIfEnvChanged":{"var":"RUSTC_BOOTSTRAP","val":null}}],"rustflags":[],"metadata":0,"config":0,"compile_kind":0}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file has an mtime of when this was started.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
82b947703eb67fe2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rustc":6294317376553613522,"features":"[\"default\", \"std\"]","declared_features":"[\"backtrace\", \"default\", \"std\"]","target":9658695707525313347,"profile":10243973527296709326,"path":8358799484023572341,"deps":[[434603458838584,"build_script_build",false,16834098221570997683]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/anyhow-fb5f84a7d2c8163f/dep-lib-anyhow","checksum":false}}],"rustflags":[],"metadata":17154292783084528516,"config":2202906307356721367,"compile_kind":0}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file has an mtime of when this was started.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
9c7bed26e8297378
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rustc":6294317376553613522,"features":"[]","declared_features":"[]","target":2335875696846802167,"profile":13232757476167777671,"path":18041046293230365407,"deps":[[2730833547707790158,"syn",false,1809274253427376006],[13033644984628948268,"proc_macro2",false,7537023756866017703],[16133888191189175860,"quote",false,6211031460239494645]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/async-trait-4601d76a9cb06033/dep-lib-async_trait","checksum":false}}],"rustflags":[],"metadata":2009543531008976451,"config":2202906307356721367,"compile_kind":0}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file has an mtime of when this was started.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1474b0e0025a803b
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rustc":6294317376553613522,"features":"[]","declared_features":"[]","target":4416014774196737203,"profile":13232757476167777671,"path":9339615681791396735,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/autocfg-072974cf7fdf4d76/dep-lib-autocfg","checksum":false}}],"rustflags":[],"metadata":13102859075309379048,"config":2202906307356721367,"compile_kind":0}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file has an mtime of when this was started.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ca7749d8a41d1f3c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rustc":6294317376553613522,"features":"[\"default\", \"form\", \"http1\", \"json\", \"matched-path\", \"original-uri\", \"query\", \"tokio\", \"tower-log\", \"tracing\"]","declared_features":"[\"__private_docs\", \"default\", \"form\", \"http1\", \"http2\", \"json\", \"macros\", \"matched-path\", \"multipart\", \"original-uri\", \"query\", \"tokio\", \"tower-log\", \"tracing\", \"ws\"]","target":3327719205906166049,"profile":10243973527296709326,"path":14016913757709051031,"deps":[[554324495028472449,"memchr",false,10982985675788412631],[2572418701297921572,"rustversion",false,13081833641310775782],[3930354675071354477,"percent_encoding",false,3909604213048664135],[4804940174145429021,"tower",false,3845161706480092065],[4890845594570020611,"sync_wrapper",false,13797059006967462098],[5204382251033773414,"tower_service",false,2904772517905767244],[5610835587450752656,"tokio",false,17316614667768662442],[5844868078238010658,"http_body",false,9686507975855012088],[6690072151007321369,"hyper",false,17500695075370365526],[7036887387399673543,"async_trait",false,8679326983935327132],[7470442545028885647,"mime",false,3360036936557804656],[8147480371320816545,"http",false,15122312623306456055],[10487968590454907062,"hyper_util",false,17671690803379872145],[10821342338875855840,"tower_layer",false,9163566659632187980],[11809678037142197677,"pin_project_lite",false,9400973148351151033],[11949335968185532509,"itoa",false,9988621486467999164],[12398318913033227710,"serde",false,12741560500920019506],[12440384873867622747,"bytes",false,11203799039886824476],[12569419213557908511,"serde_path_to_error",false,5281433963486532109],[13774998135715020687,"http_body_util",false,12105703551606651641],[14446744633799657975,"matchit",false,18144916110714728345],[15501288286569156197,"serde_urlencoded",false,12811466866351208657],[16132118061651035107,"tracing",false,15080484123469381427],[16476303074998891276,"futures_util",false,13350960091503094033],[17239433591084179946,"axum_core",false,14473559709654366739],[18111160300975844916,"serde_json",false,9855391303268906272]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/axum-2579e3ca071fb3bf/dep-lib-axum","checksum":false}}],"rustflags":[],"metadata":17576717817111726285,"config":2202906307356721367,"compile_kind":0}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file has an mtime of when this was started.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
13ba5a29df69dcc8
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rustc":6294317376553613522,"features":"[\"tracing\"]","declared_features":"[\"__private_docs\", \"tracing\"]","target":3991675658898913955,"profile":10243973527296709326,"path":15812081663977849266,"deps":[[2572418701297921572,"rustversion",false,13081833641310775782],[4890845594570020611,"sync_wrapper",false,13797059006967462098],[5204382251033773414,"tower_service",false,2904772517905767244],[5844868078238010658,"http_body",false,9686507975855012088],[7036887387399673543,"async_trait",false,8679326983935327132],[7470442545028885647,"mime",false,3360036936557804656],[8147480371320816545,"http",false,15122312623306456055],[10821342338875855840,"tower_layer",false,9163566659632187980],[11809678037142197677,"pin_project_lite",false,9400973148351151033],[12440384873867622747,"bytes",false,11203799039886824476],[13774998135715020687,"http_body_util",false,12105703551606651641],[16132118061651035107,"tracing",false,15080484123469381427],[16476303074998891276,"futures_util",false,13350960091503094033]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/axum-core-fddc4034be3c9014/dep-lib-axum_core","checksum":false}}],"rustflags":[],"metadata":14881847943984526847,"config":2202906307356721367,"compile_kind":0}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file has an mtime of when this was started.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
97169ab7c4181d2e
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rustc":6294317376553613522,"features":"[]","declared_features":"[\"arbitrary\", \"bytemuck\", \"compiler_builtins\", \"core\", \"example_generated\", \"rustc-dep-of-std\", \"serde\", \"std\"]","target":4580331566439999389,"profile":10243973527296709326,"path":6355042024004971841,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/bitflags-2550653c0a7f0348/dep-lib-bitflags","checksum":false}}],"rustflags":[],"metadata":14564035643000669268,"config":2202906307356721367,"compile_kind":0}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file has an mtime of when this was started.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1c1451d3dde37b9b
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rustc":6294317376553613522,"features":"[\"default\", \"std\"]","declared_features":"[\"default\", \"extra-platforms\", \"serde\", \"std\"]","target":11760690125712218560,"profile":7317859028274326701,"path":802236102184809444,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/bytes-e8aece475e4ffcf5/dep-lib-bytes","checksum":false}}],"rustflags":[],"metadata":11501112221997671841,"config":2202906307356721367,"compile_kind":0}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file has an mtime of when this was started.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
376058bbb398f6d2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rustc":6294317376553613522,"features":"[]","declared_features":"[\"compiler_builtins\", \"core\", \"rustc-dep-of-std\"]","target":11601024444410784892,"profile":10243973527296709326,"path":1175956265451947015,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/cfg-if-ccd6001793aa8495/dep-lib-cfg_if","checksum":false}}],"rustflags":[],"metadata":8462187951337715540,"config":2202906307356721367,"compile_kind":0}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file has an mtime of when this was started.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c1dd7a3b4e769156
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rustc":6294317376553613522,"features":"[\"default\", \"std\"]","declared_features":"[\"default\", \"std\"]","target":10602123296753431656,"profile":10243973527296709326,"path":14484458910522089397,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/fnv-dbd1d5183e430dc6/dep-lib-fnv","checksum":false}}],"rustflags":[],"metadata":17205452474433819084,"config":2202906307356721367,"compile_kind":0}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file has an mtime of when this was started.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
36fcd491cea15104
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"rustc":6294317376553613522,"features":"[\"alloc\", \"default\", \"std\"]","declared_features":"[\"alloc\", \"default\", \"std\"]","target":18403430730656100250,"profile":10243973527296709326,"path":5056093745493379151,"deps":[[3930354675071354477,"percent_encoding",false,3909604213048664135]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/form_urlencoded-8e436f64533fa2d4/dep-lib-form_urlencoded","checksum":false}}],"rustflags":[],"metadata":8992655875151632007,"config":2202906307356721367,"compile_kind":0}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file has an mtime of when this was started.
Loading