From 6a4bb890ad2720c7ea6004477174ddf941548caa Mon Sep 17 00:00:00 2001 From: Michael Yuan Date: Wed, 28 May 2025 15:00:07 -0500 Subject: [PATCH 1/4] Improve MCP tool descriptions --- app/mcp_tools.py | 103 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 92 insertions(+), 11 deletions(-) diff --git a/app/mcp_tools.py b/app/mcp_tools.py index ce90a7c..30f28b4 100644 --- a/app/mcp_tools.py +++ b/app/mcp_tools.py @@ -18,16 +18,62 @@ @mcp.tool() async def generate(description: str, requirements: str) -> str: - """Generate a new Rust cargo project from the description and requirements""" + """ + Generate a new Rust cargo project from the description and requirements. The input arguments are - async with httpx.AsyncClient() as client: - response = await client.post(f"{API_BASE_URL}/generate-sync", json={'description': description, 'requirements': requirements}) - return response.text + * description: a text string description of the generated Rust project. + * requiremenets: functional requirements on what the generated Rust project. + + The return value is a text string that contains all files in the project. Each file is seperated by a [filename: path_to_file] line. For example, a project that contains a Cargo.toml file and a src/main.rs file will be returned as the following. + +[filename: Cargo.toml] +[package] +name = "a_command_line_calcu" +version = "0.1.0" +edition = "2021" + +[dependencies] + + +[filename: src/main.rs] +fn main() { + println!("Hello, world!"); +} + + """ + + async with httpx.AsyncClient(timeout=60.0) as client: + try: + response = await client.post(f"{API_BASE_URL}/generate-sync", json={'description': description, 'requirements': requirements}) + response.raise_for_status() + return response.text + except httpx.HTTPError as e: + print(f"HTTP error occurred: {e}") + return f"Error trying to generate a Rust project: {str(e)}" @mcp.tool() async def compile_and_fix(code: str, description: str = "A Rust project", max_attempts: int = 3) -> str: - """Compile a Rust cargo project and fix any compiler errors""" + """ + Compile a Rust cargo project and fix any compiler errors. + + The argument `code` is a text string that contains all files in the project. Each file is seperated by a [filename: path_to_file] line. For example, a project that contains a Cargo.toml file and a src/main.rs file will be returned as the following. + +[filename: Cargo.toml] +[package] +name = "a_command_line_calcu" +version = "0.1.0" +edition = "2021" +[dependencies] + + +[filename: src/main.rs] +fn main() { + println!("Hello, world!"); +} + + The return value is also a text string that contains all files in the project. It is in the same format as the input `code` argument. + """ async with httpx.AsyncClient(timeout=60.0) as client: try: response = await client.post( @@ -35,18 +81,53 @@ async def compile_and_fix(code: str, description: str = "A Rust project", max_at json={'code': code, 'description': description, 'max_attempts': max_attempts} ) response.raise_for_status() - return response.text + + resp_json = json.loads(response.text) + if "combined_text" in resp_json: + return ["combined_text"] + else: + return "Cannot fix the Rust compiler error." + # return response.text except httpx.HTTPError as e: print(f"HTTP error occurred: {e}") - return f"Error calling compile-and-fix API: {str(e)}" + return f"Error trying to fixing the Rust compiler error: {str(e)}" @mcp.tool() async def compile(code: str) -> str: - """Compile a Rust cargo project""" + """ + Compile a Rust cargo project and return the compiler output. + + The argument `code` is a text string that contains all files in the project. Each file is seperated by a [filename: path_to_file] line. For example, a project that contains a Cargo.toml file and a src/main.rs file will be returned as the following. + +[filename: Cargo.toml] +[package] +name = "a_command_line_calcu" +version = "0.1.0" +edition = "2021" + +[dependencies] - async with httpx.AsyncClient() as client: - response = await client.post(f"{API_BASE_URL}/compile", json={'code': code}) - return response.text + +[filename: src/main.rs] +fn main() { + println!("Hello, world!"); +} + + The return value is a text string that contains the Rust compiler output. + """ + async with httpx.AsyncClient(timeout=60.0) as client: + try: + response = await client.post(f"{API_BASE_URL}/compile", json={'code': code}) + response.raise_for_status() + + resp_json = json.loads(response.text) + if "build_output" in resp_json: + return ["build_output"] + else: + return "Rust compiler error." + except httpx.HTTPError as e: + print(f"HTTP error occurred: {e}") + return f"Rust compiler error: {str(e)}" if __name__ == "__main__": # Use transport from environment variable or default to stdio From 9cbc393d07b8bcfc4368cc12d34bef091c4df9df Mon Sep 17 00:00:00 2001 From: Michael Yuan Date: Wed, 28 May 2025 15:02:08 -0500 Subject: [PATCH 2/4] Update Dockerfile to use the openmcp installer We need to make sure that the installer actually works --- Dockerfile | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 44ef1cc..d57b074 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,14 +10,17 @@ RUN apt-get update && apt-get install -y curl build-essential && \ ENV PATH="/root/.cargo/bin:${PATH}" # Directly download and install OpenMCP from source to avoid binary compatibility issues -RUN apt-get install -y git && \ - git clone https://github.com/decentralized-mcp/proxy.git && \ - cd proxy && \ - cargo build --release && \ - cp target/release/openmcp /usr/local/bin/ && \ - chmod +x /usr/local/bin/openmcp && \ - cd .. && \ - rm -rf proxy +# RUN apt-get install -y git && \ +# git clone https://github.com/decentralized-mcp/proxy.git && \ +# cd proxy && \ +# cargo build --release && \ +# cp target/release/openmcp /usr/local/bin/ && \ +# chmod +x /usr/local/bin/openmcp && \ +# cd .. && \ +# rm -rf proxy + +# Install openmcp proxy via the installer +RUN curl -sSfL 'https://raw.githubusercontent.com/decentralized-mcp/proxy/refs/heads/master/install.sh' | bash # Set working directory WORKDIR /app From 24c9d168697d188add2ca989c085cd6636c85246 Mon Sep 17 00:00:00 2001 From: Michael Yuan Date: Wed, 28 May 2025 15:05:02 -0500 Subject: [PATCH 3/4] Update README.md --- README.md | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 4c3316e..bf40bc9 100644 --- a/README.md +++ b/README.md @@ -146,10 +146,13 @@ curl -X POST http://localhost:8000/compile \ ``` { - "success":true, - "files":["Cargo.toml","src/main.rs"], - "build_output":"Build successful", - "run_output":"Hello, World!\n" + "success": true, + "files": [ + "Cargo.toml", + "src/main.rs" + ], + "build_output": "Build successful", + "run_output": "Hello, World!\n" } ``` @@ -182,17 +185,28 @@ curl -X POST http://localhost:8000/compile-and-fix \ #### 📤 Response: ``` -[filename: Cargo.toml] -[package] -name = "hello_world" -version = "0.1.0" -edition = "2021" - -[dependencies] - -[filename: src/main.rs] -fn main() { - println!("Hello, World!"); // Missing closing parenthesis +{ + "success": true, + "attempts": [ + { + "attempt": 1, + "success": false, + "output": " Compiling hello_world v0.1.0 (/tmp/tmpk_0n65md)\nerror: mismatched closing delimiter: `}`\n --> src/main.rs:2:13\n |\n1 | fn main() {\n | - closing delimiter possibly meant for this\n2 | println!(\"Hello, World!\" // Missing closing parenthesis\n | ^ unclosed delimiter\n3 | }\n | ^ mismatched closing delimiter\n\nerror: could not compile `hello_world` (bin \"hello_world\") due to 1 previous error\n" + }, + { + "attempt": 2, + "success": true, + "output": null + } + ], + "final_files": { + "Cargo.toml": "[package]\nname = \"hello_world\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]", + "src/main.rs": "fn main() {\n println!(\"Hello, World!\");\n}" + }, + "build_output": "Build successful", + "run_output": "Hello, World!\n", + "similar_project_used": false, + "combined_text": "[filename: Cargo.toml]\n[package]\nname = \"hello_world\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\n\n[filename: src/main.rs]\nfn main() {\n println!(\"Hello, World!\");\n}" } ``` From 65b5dce053e252a45742869a91fd2cd52e9f1fa3 Mon Sep 17 00:00:00 2001 From: Michael Yuan Date: Wed, 28 May 2025 15:09:24 -0500 Subject: [PATCH 4/4] Start the MCP server in STDIO mode and use openmcp for SSE proxy --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index dd94ea7..64995e4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,7 +24,7 @@ services: environment: - API_HOST=api # Use service name within Docker network - API_PORT=8000 - - MCP_TRANSPORT=sse + - MCP_TRANSPORT=stdio # We use openmcp to map the STDIO MCP server to SSE on our desired port depends_on: - api