Skip to content

Commit 8a9fc5b

Browse files
authored
Merge pull request #5 from juntao/main
Add MCP support
2 parents 0c7ef11 + 76c046f commit 8a9fc5b

File tree

4 files changed

+181
-85
lines changed

4 files changed

+181
-85
lines changed

Dockerfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ RUN apt-get update && apt-get install -y curl build-essential && \
99
# Add cargo to PATH
1010
ENV PATH="/root/.cargo/bin:${PATH}"
1111

12+
# Install openmcp proxy
13+
# RUN curl -sSfL 'https://raw.githubusercontent.com/decentralized-mcp/proxy/refs/heads/master/install.sh' | bash
14+
RUN curl -LO https://github.com/decentralized-mcp/proxy/releases/latest/download/openmcp-aarch64-unknown-linux-gnu.tgz
15+
RUN tar zxvf openmcp-aarch64-unknown-linux-gnu.tgz
16+
RUN cp openmcp /usr/local/bin/
17+
1218
# Set working directory
1319
WORKDIR /app
1420

README.md

Lines changed: 136 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Rust Project Generator API
1+
# Rust Coder
22

3-
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.
3+
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.
44

55
---
66

@@ -91,6 +91,113 @@ The API provides the following endpoints:
9191

9292
### 🎯 Generate a Project
9393

94+
**Endpoint:** `POST /generate-sync`
95+
96+
**Example:**
97+
98+
```bash
99+
curl -X POST http://localhost:8000/generate-sync \
100+
-H "Content-Type: application/json" \
101+
-d '{"description": "A command-line calculator in Rust", "requirements": "Should support addition, subtraction, multiplication, and division"}'
102+
```
103+
104+
#### 📥 Request Body:
105+
106+
```
107+
{
108+
"description": "A command-line calculator in Rust",
109+
"requirements": "Should support addition, subtraction, multiplication, and division"
110+
}
111+
```
112+
113+
#### 📤 Response:
114+
115+
```
116+
[filename: Cargo.toml]
117+
... ...
118+
119+
[filename: src/main.rs]
120+
... ...
121+
```
122+
123+
### 🛠 Compile a Project
124+
125+
**Endpoint:** `POST /compile`
126+
127+
**Example:**
128+
129+
```bash
130+
curl -X POST http://localhost:8000/compile \
131+
-H "Content-Type: application/json" \
132+
-d '{
133+
"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}"
134+
}'
135+
```
136+
137+
#### 📥 Request Body:
138+
139+
```
140+
{
141+
"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}"
142+
}
143+
```
144+
145+
#### 📤 Response:
146+
147+
```
148+
{
149+
"success":true,
150+
"files":["Cargo.toml","src/main.rs"],
151+
"build_output":"Build successful",
152+
"run_output":"Hello, World!\n"
153+
}
154+
```
155+
156+
### 🩹 Compile and fix errors
157+
158+
**Endpoint:** `POST /compile-and-fix`
159+
160+
**Example:**
161+
162+
```bash
163+
curl -X POST http://localhost:8000/compile-and-fix \
164+
-H "Content-Type: application/json" \
165+
-d '{
166+
"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}",
167+
"description": "A simple hello world program",
168+
"max_attempts": 3
169+
}'
170+
```
171+
172+
#### 📥 Request Body:
173+
174+
```
175+
{
176+
"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}",
177+
"description": "A simple hello world program",
178+
"max_attempts": 3
179+
}
180+
```
181+
182+
#### 📤 Response:
183+
184+
```
185+
[filename: Cargo.toml]
186+
[package]
187+
name = "hello_world"
188+
version = "0.1.0"
189+
edition = "2021"
190+
191+
[dependencies]
192+
193+
[filename: src/main.rs]
194+
fn main() {
195+
println!("Hello, World!"); // Missing closing parenthesis
196+
}
197+
```
198+
199+
### 🎯 Generate a Project Async
200+
94201
**Endpoint:** `POST /generate`
95202

96203
**Example:**
@@ -143,6 +250,24 @@ curl http://localhost:8000/project/123e4567-e89b-12d3-a456-426614174000
143250
}
144251
```
145252

253+
### 📌 Get Generated Files
254+
255+
**Endpoint:** `GET /project/{project_id}/files/path_to_file`
256+
257+
**Example:**
258+
259+
```bash
260+
curl http://localhost:8000/project/123e4567-e89b-12d3-a456-426614174000/files/src/main.rs
261+
```
262+
263+
#### 📤 Response:
264+
265+
```
266+
fn main() {
267+
... ...
268+
}
269+
```
270+
146271
---
147272

148273
## 🔧 MCP (Model-Compiler-Processor) tools
@@ -153,19 +278,14 @@ The MCP server is available via the HTTP SSE transport via the `http://localhost
153278
pip install cmcp
154279
```
155280

156-
### 🛠 Compile Rust Code
281+
### 🎯 Generate a new project
157282

158-
**tool:** `compile`
283+
**tool:** `generate`
159284

160285
#### 📥 Request example:
161286

162287
```bash
163-
cmcp http://localhost:3000 tools/call -d '{ \
164-
"name": "compile", \
165-
"arguments": { \
166-
"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}" \
167-
} \
168-
}'
288+
cmcp http://localhost:3000 tools/call name=generate arguments:='{"description": "A command-line calculator in Rust", "requirements": "Should support addition, subtraction, multiplication, and division"}'
169289
```
170290

171291
#### 📤 Response:
@@ -176,30 +296,24 @@ cmcp http://localhost:3000 tools/call -d '{ \
176296
"content": [
177297
{
178298
"type": "text",
179-
"text": "success",
299+
"text": "[filename: Cargo.toml] ... [filename: src/main.rs] ... ",
180300
"annotations": null
181301
}
182302
],
183303
"isError": false
184304
}
185305
```
186-
187306
### 🩹 Compile and Fix Rust Code
188307

189-
**tool:** `compileAndFix`
308+
**tool:** `compile_and_fix`
190309

191-
### 📥 Request example:
310+
#### 📥 Request example:
192311

193312
```bash
194-
cmcp http://localhost:3000 tools/call -d '{ \
195-
"name": "compileAndFix", \
196-
"arguments": { \
197-
"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}" \
198-
} \
199-
}'
313+
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}" }'
200314
```
201315

202-
### 📤 Response:
316+
#### 📤 Response:
203317

204318
```json
205319
{
@@ -215,37 +329,6 @@ cmcp http://localhost:3000 tools/call -d '{ \
215329
}
216330
```
217331

218-
### 🎯 Generate a new project
219-
220-
**tool:** `generate`
221-
222-
### 📥 Request example:
223-
224-
```bash
225-
cmcp http://localhost:3000 tools/call -d '{ \
226-
"name": "generate", \
227-
"arguments": { \
228-
"description": "A command-line calculator in Rust", "requirements": "Should support addition, subtraction, multiplication, and division" \
229-
} \
230-
}'
231-
```
232-
233-
### 📤 Response:
234-
235-
```json
236-
{
237-
"meta": null,
238-
"content": [
239-
{
240-
"type": "text",
241-
"text": "[filename: Cargo.toml] ... [filename: src/main.rs] ... ",
242-
"annotations": null
243-
}
244-
],
245-
"isError": false
246-
}
247-
```
248-
249332
---
250333

251334
## 📂 Project Structure
@@ -295,4 +378,4 @@ Contributions are welcome! Feel free to submit a Pull Request. 🚀
295378
---
296379

297380
## 📜 License
298-
Licensed under [No license]](LICENSE).
381+
Licensed under [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html).

app/mcp_tools.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import httpx
2+
import sys
3+
import json
4+
import os
5+
from dotenv import load_dotenv
6+
from mcp.server.fastmcp import FastMCP
7+
8+
mcp = FastMCP("Rust compiler tools")
9+
10+
@mcp.tool()
11+
async def generate(description: str, requirements: str) -> str:
12+
"""Generate a new Rust cargo project from the description and requirements"""
13+
14+
async with httpx.AsyncClient() as client:
15+
response = await client.post("http://host.docker.internal:8000/generate-sync", json={'description': description, 'requirements': requirements})
16+
return response.text
17+
18+
@mcp.tool()
19+
async def compile_and_fix(code: str) -> str:
20+
"""Compile a Rust cargo project and fix any compiler errors"""
21+
22+
async with httpx.AsyncClient() as client:
23+
response = await client.post("http://host.docker.internal:8000/compile-and-fix", json={'code': code, 'description': 'A Rust project', 'max_attempts': 3})
24+
return response.text
25+
26+
if __name__ == "__main__":
27+
mcp.run(transport="stdio")

docker-compose.yml

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,24 @@ services:
66
ports:
77
- "8000:8000"
88
environment:
9-
- LLM_API_KEY=dummy-key
10-
- LLM_API_BASE=http://host.docker.internal:8080/v1 # This accesses your host machine from Docker
11-
- LLM_MODEL=Qwen2.5-Coder-3B-Instruct
12-
- LLM_EMBED_MODEL=gte-Qwen2-1.5B-instruct
13-
- LLM_EMBED_SIZE=1536
9+
- LLM_API_KEY=${LLM_API_KEY}
10+
- LLM_API_BASE=${LLM_API_BASE:-https://coder.gaia.domains/v1}
11+
- LLM_MODEL=${LLM_MODEL:-Qwen2.5-Coder-32B-Instruct-Q5_K_M}
12+
- LLM_EMBED_MODEL=${LLM_EMBED_MODEL:-nomic-embed}
13+
- LLM_EMBED_SIZE=${LLM_EMBED_SIZE:-768}
1414
- QDRANT_HOST=qdrant
1515
- QDRANT_PORT=6333
16-
- SKIP_VECTOR_SEARCH=true # Add this to avoid embedding API issues
1716
command: uvicorn app.main:app --host 0.0.0.0 --port 8000
1817
depends_on:
1918
- qdrant
2019

21-
# Commenting out MCP services temporarily
22-
# mcp-server:
23-
# build: .
24-
# environment:
25-
# - MCP_TRANSPORT=sse
26-
# - MCP_HOST=0.0.0.0
27-
# - MCP_PORT=3001
28-
# - LLM_API_KEY=${LLM_API_KEY}
29-
# - LLM_API_BASE=${LLM_API_BASE:-https://coder.gaia.domains/v1}
30-
# - LLM_MODEL=${LLM_MODEL:-Qwen2.5-Coder-32B-Instruct-Q5_K_M}
31-
# - LLM_EMBED_MODEL=${LLM_EMBED_MODEL:-nomic-embed}
32-
# - LLM_EMBED_SIZE=${LLM_EMBED_SIZE:-768}
33-
# - QDRANT_HOST=qdrant
34-
# - QDRANT_PORT=6333
35-
# command: python -m app.mcp_server
36-
# depends_on:
37-
# - qdrant
38-
39-
# mcp-proxy:
40-
# image: russellluo/mcp-proxy:0.4.0
41-
# ports:
42-
# - "3000:3000"
43-
# volumes:
44-
# - ./mcp-proxy-config.json:/app/config.json
45-
# depends_on:
46-
# - mcp-server
20+
mcp-server:
21+
build: .
22+
command: openmcp run -p 0.0.0.0:3000 -- python app/mcp_tools.py
23+
ports:
24+
- "3000:3000"
25+
depends_on:
26+
- api
4727

4828
qdrant:
4929
image: qdrant/qdrant

0 commit comments

Comments
 (0)