Skip to content

Commit 0577888

Browse files
rushilpatel0tomcodgenfrainfreezetkfosskopekC
authored
add initial server with run and codebase initialization (#507)
# Motivation <!-- Why is this change necessary? --> # Content <!-- Please include a summary of the change --> # Testing <!-- How was the change tested? --> # Please check the following before marking your PR as ready for review - [ ] I have added tests for my changes - [ ] I have updated the documentation or added new documentation as needed --------- Co-authored-by: rushilpatel0 <[email protected]> Co-authored-by: tomcodgen <[email protected]> Co-authored-by: tomcodegen <[email protected]> Co-authored-by: tomcodgen <[email protected]> Co-authored-by: Edo Pujol <[email protected]> Co-authored-by: Jay Hack <[email protected]> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Vishal Shenoy <[email protected]>
1 parent 652423a commit 0577888

File tree

4 files changed

+2823
-0
lines changed

4 files changed

+2823
-0
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Codegen MCP Server
2+
3+
<p align="center">
4+
<a href="https://docs.codegen.com">
5+
<img src="https://i.imgur.com/6RF9W0z.jpeg" />
6+
</a>
7+
</p>
8+
9+
<h2 align="center">
10+
An MCP server implementation that integrates the codegen sdk.
11+
12+
</h2>
13+
14+
<div align="center">
15+
16+
[![Documentation](https://img.shields.io/badge/Docs-docs.codegen.com-purple?style=flat-square)](https://docs.codegen.com)
17+
[![License](https://img.shields.io/badge/Code%20License-Apache%202.0-gray?&color=gray)](https://github.com/codegen-sh/codegen-sdk/tree/develop?tab=Apache-2.0-1-ov-file)
18+
19+
</div>
20+
21+
This example demonstrates how to run a Model Control Protocol (MCP) server that integrates with Codegen. The server provides:
22+
23+
1. A standardized interface for model inference
24+
1. Integration with Codegen's core functionality, parsing codebases and executing codemods
25+
1. Support for various LLM providers through the MCP protocol
26+
27+
## Quick Start
28+
29+
### Prerequisites
30+
31+
- [uv](https://docs.astral.sh/uv/getting-started/installation/)
32+
- [python](https://www.python.org/downloads/) 3.12+
33+
34+
### Direct Execution
35+
36+
1. No installation is necessary, with the following command. Run this command directly or add it your `.json` mcp config file.
37+
38+
```bash
39+
uvx --from 'git+https://github.com/codegen-sh/codegen-sdk.git@ce8cffe#egg=codegen-mcp-server&subdirectory=codegen-examples/examples/codegen-mcp-server' codegen-mcp-server
40+
```
41+
42+
### Example MCP Config
43+
44+
Here is an example mcp config that can be used with Cline or Claude desktop to integrate this MCP server
45+
46+
```json
47+
{
48+
"mcpServers": {
49+
"codegen-mcp": {
50+
"command": "uvx",
51+
"args": [
52+
"--from",
53+
"git+https://github.com/codegen-sh/codegen-sdk.git#egg=codegen-mcp-server&subdirectory=codegen-examples/examples/codegen-mcp-server",
54+
"codegen-mcp-server"
55+
],
56+
"disabled": false,
57+
"autoApprove": []
58+
}
59+
}
60+
}
61+
```
62+
63+
###MCP Tools:
64+
65+
- `parse_codebase`: Parses a codebase located at the provided path.
66+
- `check_parse_status`: Provides the current parsing status for the provided codebase.
67+
- `execute_codemod`: Executes a codemod script on a parsed codebase. This is where the codegen sdk leveraged to run simple or sophisticated codemods on the codebase.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[project]
2+
name = "codegen-mcp-server"
3+
version = "0.1.0"
4+
description = "MCP server implementation adding tools for the Codegen SDK"
5+
readme = "README.md"
6+
requires-python = ">=3.12"
7+
dependencies = [
8+
"codegen>=0.14.5",
9+
"uvicorn>=0.27.1",
10+
"fastapi>=0.110.0",
11+
"pydantic>=2.6.3",
12+
"rich>=13.7.1",
13+
"click>=8.1.7",
14+
"mcp[cli]>=1.2.1",
15+
]
16+
17+
[tool.poetry.scripts]
18+
codegen-mcp-server = "server:main"
19+
[project.scripts]
20+
codegen-mcp-server = "server:main"
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import asyncio
2+
from dataclasses import dataclass, field
3+
from typing import Annotated, Optional, Dict, Any, List
4+
from mcp.server.fastmcp import FastMCP
5+
from codegen import Codebase
6+
7+
8+
@dataclass
9+
class CodebaseState:
10+
"""Class to manage codebase state and parsing."""
11+
12+
parse_task: Optional[asyncio.Task] = None
13+
parsed_codebase: Optional[Codebase] = None
14+
log_buffer: List[str] = field(default_factory=list)
15+
16+
async def parse(self, path: str) -> Codebase:
17+
"""Parse the codebase at the given path."""
18+
codebase = Codebase(path)
19+
self.parsed_codebase = codebase
20+
return codebase
21+
22+
def reset(self) -> None:
23+
"""Reset the state."""
24+
if self.parsed_codebase:
25+
self.parsed_codebase.reset()
26+
self.log_buffer.clear()
27+
28+
29+
# Initialize FastMCP server
30+
mcp = FastMCP(
31+
"codegen-mcp-server",
32+
instructions="""This server provides tools to parse and modify a codebase using codemods.
33+
It can initiate parsing, check parsing status, and execute codemods.""",
34+
)
35+
36+
# Initialize state
37+
state = CodebaseState()
38+
39+
40+
def capture_output(*args, **kwargs) -> None:
41+
"""Capture and log output messages."""
42+
for arg in args:
43+
state.log_buffer.append(str(arg))
44+
45+
46+
@mcp.tool(name="parse_codebase", description="Initiate codebase parsing")
47+
async def parse_codebase(codebase_path: Annotated[str, "path to the codebase to be parsed"]) -> Dict[str, str]:
48+
if not state.parse_task or state.parse_task.done():
49+
state.parse_task = asyncio.create_task(state.parse(codebase_path))
50+
return {"message": "Codebase parsing initiated, this may take some time depending on the size of the codebase. Use the `check_parsing_status` tool to check if the parse has completed."}
51+
return {"message": "Codebase is already being parsed."}
52+
53+
54+
@mcp.tool(name="check_parse_status", description="Check if codebase parsing has completed")
55+
async def check_parse_status() -> Dict[str, str]:
56+
if not state.parse_task:
57+
return {"message": "No codebase provided to parse."}
58+
if state.parse_task.done():
59+
return {"message": "Codebase parsing completed."}
60+
return {"message": "Codebase parsing in progress."}
61+
62+
63+
@mcp.tool(name="execute_codemod", description="Execute a codemod on the codebase")
64+
async def execute_codemod(codemod: Annotated[str, "The python codemod code to execute on the codebase"]) -> Dict[str, Any]:
65+
if not state.parse_task or not state.parse_task.done():
66+
return {"error": "Codebase is not ready for codemod execution."}
67+
68+
try:
69+
await state.parse_task
70+
# TODO: Implement proper sandboxing for code execution
71+
context = {
72+
"codebase": state.parsed_codebase,
73+
"print": capture_output,
74+
}
75+
exec(codemod, context)
76+
77+
logs = "\n".join(state.log_buffer)
78+
79+
state.reset()
80+
return {"message": "Codemod executed and codebase reset.", "logs": logs}
81+
except Exception as e:
82+
return {"error": f"Error executing codemod: {str(e)}", "details": {"type": type(e).__name__, "message": str(e)}}
83+
84+
85+
def main():
86+
print("starting codegen-mcp-server")
87+
run = mcp.run_stdio_async()
88+
print("codegen-mcp-server started")
89+
asyncio.run(run)
90+
91+
92+
if __name__ == "__main__":
93+
main()

0 commit comments

Comments
 (0)