From 8c77d270394d27bb783e772bea6a27531081aa45 Mon Sep 17 00:00:00 2001 From: Michael Yuan Date: Tue, 27 May 2025 03:52:11 -0500 Subject: [PATCH 1/4] Add openmcp to the docker image --- Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Dockerfile b/Dockerfile index bab48b1..1ff10f7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,12 @@ RUN apt-get update && apt-get install -y curl build-essential && \ # Add cargo to PATH ENV PATH="/root/.cargo/bin:${PATH}" +# Install openmcp proxy +# RUN curl -sSfL 'https://raw.githubusercontent.com/decentralized-mcp/proxy/refs/heads/master/install.sh' | bash +RUN curl -LO https://github.com/decentralized-mcp/proxy/releases/latest/download/openmcp-aarch64-unknown-linux-gnu.tgz +RUN tar zxvf openmcp-aarch64-unknown-linux-gnu.tgz +RUN cp openmcp /usr/local/bin/ + # Set working directory WORKDIR /app From 09618f4401603917f43e6f9dcbf9b884e7d3c146 Mon Sep 17 00:00:00 2001 From: Michael Yuan Date: Tue, 27 May 2025 03:53:27 -0500 Subject: [PATCH 2/4] Create a MCP server container based on openmcp and mcp_tools.py --- docker-compose.yml | 44 ++++++++++++-------------------------------- 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index ecfb632..7d09ea9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,44 +6,24 @@ services: ports: - "8000:8000" environment: - - LLM_API_KEY=dummy-key - - LLM_API_BASE=http://host.docker.internal:8080/v1 # This accesses your host machine from Docker - - LLM_MODEL=Qwen2.5-Coder-3B-Instruct - - LLM_EMBED_MODEL=gte-Qwen2-1.5B-instruct - - LLM_EMBED_SIZE=1536 + - LLM_API_KEY=${LLM_API_KEY} + - LLM_API_BASE=${LLM_API_BASE:-https://coder.gaia.domains/v1} + - LLM_MODEL=${LLM_MODEL:-Qwen2.5-Coder-32B-Instruct-Q5_K_M} + - LLM_EMBED_MODEL=${LLM_EMBED_MODEL:-nomic-embed} + - LLM_EMBED_SIZE=${LLM_EMBED_SIZE:-768} - QDRANT_HOST=qdrant - QDRANT_PORT=6333 - - SKIP_VECTOR_SEARCH=true # Add this to avoid embedding API issues command: uvicorn app.main:app --host 0.0.0.0 --port 8000 depends_on: - qdrant - # Commenting out MCP services temporarily - # mcp-server: - # build: . - # environment: - # - MCP_TRANSPORT=sse - # - MCP_HOST=0.0.0.0 - # - MCP_PORT=3001 - # - LLM_API_KEY=${LLM_API_KEY} - # - LLM_API_BASE=${LLM_API_BASE:-https://coder.gaia.domains/v1} - # - LLM_MODEL=${LLM_MODEL:-Qwen2.5-Coder-32B-Instruct-Q5_K_M} - # - LLM_EMBED_MODEL=${LLM_EMBED_MODEL:-nomic-embed} - # - LLM_EMBED_SIZE=${LLM_EMBED_SIZE:-768} - # - QDRANT_HOST=qdrant - # - QDRANT_PORT=6333 - # command: python -m app.mcp_server - # depends_on: - # - qdrant - - # mcp-proxy: - # image: russellluo/mcp-proxy:0.4.0 - # ports: - # - "3000:3000" - # volumes: - # - ./mcp-proxy-config.json:/app/config.json - # depends_on: - # - mcp-server + mcp-server: + build: . + command: openmcp run -p 0.0.0.0:3000 -- python app/mcp_tools.py + ports: + - "3000:3000" + depends_on: + - api qdrant: image: qdrant/qdrant From acb9a52543c454839e710eb8a1b2426a0aff4ab3 Mon Sep 17 00:00:00 2001 From: Michael Yuan Date: Tue, 27 May 2025 03:54:37 -0500 Subject: [PATCH 3/4] Create mcp_tools.py --- app/mcp_tools.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 app/mcp_tools.py diff --git a/app/mcp_tools.py b/app/mcp_tools.py new file mode 100644 index 0000000..ff3f503 --- /dev/null +++ b/app/mcp_tools.py @@ -0,0 +1,27 @@ +import httpx +import sys +import json +import os +from dotenv import load_dotenv +from mcp.server.fastmcp import FastMCP + +mcp = FastMCP("Rust compiler tools") + +@mcp.tool() +async def generate(description: str, requirements: str) -> str: + """Generate a new Rust cargo project from the description and requirements""" + + async with httpx.AsyncClient() as client: + response = await client.post("http://host.docker.internal:8000/generate-sync", json={'description': description, 'requirements': requirements}) + return response.text + +@mcp.tool() +async def compile_and_fix(code: str) -> str: + """Compile a Rust cargo project and fix any compiler errors""" + + async with httpx.AsyncClient() as client: + response = await client.post("http://host.docker.internal:8000/compile-and-fix", json={'code': code, 'description': 'A Rust project', 'max_attempts': 3}) + return response.text + +if __name__ == "__main__": + mcp.run(transport="stdio") From 76c046feb98b4a1275a8836bb04fff4e1ae112b8 Mon Sep 17 00:00:00 2001 From: Michael Yuan Date: Tue, 27 May 2025 03:57:18 -0500 Subject: [PATCH 4/4] Update README.md --- README.md | 189 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 136 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 800dc43..4c3316e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rust Project Generator API +# Rust Coder -An API service that generates fully functional Rust projects from natural language descriptions. This service leverages LLMs to create Rust code, compiles it, and automatically fixes any errors. +API and MCP services that generate fully functional Rust projects from natural language descriptions. These services leverage LLMs to create complete Rust cargo projects, compile Rust source code, and automatically fix compiler errors. --- @@ -91,6 +91,113 @@ The API provides the following endpoints: ### 🎯 Generate a Project +**Endpoint:** `POST /generate-sync` + +**Example:** + +```bash + curl -X POST http://localhost:8000/generate-sync \ + -H "Content-Type: application/json" \ + -d '{"description": "A command-line calculator in Rust", "requirements": "Should support addition, subtraction, multiplication, and division"}' +``` + +#### 📥 Request Body: + +``` +{ + "description": "A command-line calculator in Rust", + "requirements": "Should support addition, subtraction, multiplication, and division" +} +``` + +#### 📤 Response: + +``` +[filename: Cargo.toml] +... ... + +[filename: src/main.rs] +... ... +``` + +### 🛠 Compile a Project + +**Endpoint:** `POST /compile` + +**Example:** + +```bash +curl -X POST http://localhost:8000/compile \ +-H "Content-Type: application/json" \ +-d '{ + "code": "[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}" +}' +``` + +#### 📥 Request Body: + +``` +{ + "code": "[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}" +} +``` + +#### 📤 Response: + +``` +{ + "success":true, + "files":["Cargo.toml","src/main.rs"], + "build_output":"Build successful", + "run_output":"Hello, World!\n" +} +``` + +### 🩹 Compile and fix errors + +**Endpoint:** `POST /compile-and-fix` + +**Example:** + +```bash +curl -X POST http://localhost:8000/compile-and-fix \ +-H "Content-Type: application/json" \ +-d '{ + "code": "[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!\" // Missing closing parenthesis\n}", + "description": "A simple hello world program", + "max_attempts": 3 +}' +``` + +#### 📥 Request Body: + +``` +{ + "code": "[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!\" // Missing closing parenthesis\n}", + "description": "A simple hello world program", + "max_attempts": 3 +} +``` + +#### 📤 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 +} +``` + +### 🎯 Generate a Project Async + **Endpoint:** `POST /generate` **Example:** @@ -143,6 +250,24 @@ curl http://localhost:8000/project/123e4567-e89b-12d3-a456-426614174000 } ``` +### 📌 Get Generated Files + +**Endpoint:** `GET /project/{project_id}/files/path_to_file` + +**Example:** + +```bash +curl http://localhost:8000/project/123e4567-e89b-12d3-a456-426614174000/files/src/main.rs +``` + +#### 📤 Response: + +``` +fn main() { + ... ... +} +``` + --- ## 🔧 MCP (Model-Compiler-Processor) tools @@ -153,19 +278,14 @@ The MCP server is available via the HTTP SSE transport via the `http://localhost pip install cmcp ``` -### 🛠 Compile Rust Code +### 🎯 Generate a new project -**tool:** `compile` +**tool:** `generate` #### 📥 Request example: ```bash -cmcp http://localhost:3000 tools/call -d '{ \ - "name": "compile", \ - "arguments": { \ - "code: "[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}" \ - } \ -}' +cmcp http://localhost:3000 tools/call name=generate arguments:='{"description": "A command-line calculator in Rust", "requirements": "Should support addition, subtraction, multiplication, and division"}' ``` #### 📤 Response: @@ -176,30 +296,24 @@ cmcp http://localhost:3000 tools/call -d '{ \ "content": [ { "type": "text", - "text": "success", + "text": "[filename: Cargo.toml] ... [filename: src/main.rs] ... ", "annotations": null } ], "isError": false } ``` - ### 🩹 Compile and Fix Rust Code -**tool:** `compileAndFix` +**tool:** `compile_and_fix` -### 📥 Request example: +#### 📥 Request example: ```bash -cmcp http://localhost:3000 tools/call -d '{ \ - "name": "compileAndFix", \ - "arguments": { \ - "code: "[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!\" // Missing closing parenthesis \n}" \ - } \ -}' +cmcp http://localhost:3000 tools/call name=compile_and_fix arguments:='{"code": "[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!\" // Missing closing parenthesis \n}" }' ``` -### 📤 Response: +#### 📤 Response: ```json { @@ -215,37 +329,6 @@ cmcp http://localhost:3000 tools/call -d '{ \ } ``` -### 🎯 Generate a new project - -**tool:** `generate` - -### 📥 Request example: - -```bash -cmcp http://localhost:3000 tools/call -d '{ \ - "name": "generate", \ - "arguments": { \ - "description": "A command-line calculator in Rust", "requirements": "Should support addition, subtraction, multiplication, and division" \ - } \ -}' -``` - -### 📤 Response: - -```json -{ - "meta": null, - "content": [ - { - "type": "text", - "text": "[filename: Cargo.toml] ... [filename: src/main.rs] ... ", - "annotations": null - } - ], - "isError": false -} -``` - --- ## 📂 Project Structure @@ -295,4 +378,4 @@ Contributions are welcome! Feel free to submit a Pull Request. 🚀 --- ## 📜 License -Licensed under [No license]](LICENSE). +Licensed under [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html).