Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
189 changes: 136 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.

---

Expand Down Expand Up @@ -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:**
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -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
{
Expand All @@ -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
Expand Down Expand Up @@ -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).
27 changes: 27 additions & 0 deletions app/mcp_tools.py
Original file line number Diff line number Diff line change
@@ -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")
44 changes: 12 additions & 32 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading