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
19 changes: 11 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
44 changes: 29 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
```

Expand Down Expand Up @@ -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}"
}
```

Expand Down
103 changes: 92 additions & 11 deletions app/mcp_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,116 @@

@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(
f"{API_BASE_URL}/compile-and-fix",
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
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading