Skip to content

Commit 6c64ab2

Browse files
committed
fix: add initial server with run and codebase initialization
1 parent cb3b725 commit 6c64ab2

File tree

3 files changed

+2373
-0
lines changed

3 files changed

+2373
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[project]
2+
name = "codegen-mcp-server"
3+
version = "0.1.0"
4+
description = "Add your description here"
5+
readme = "README.md"
6+
requires-python = ">=3.13"
7+
dependencies = [
8+
"codegen>=0.14.5",
9+
"mcp>=1.2.1",
10+
]
11+
12+
[tool.poetry.scripts]
13+
codegen-mcp-server = "server:main"
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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+
@dataclass
8+
class CodebaseState:
9+
"""Class to manage codebase state and parsing."""
10+
parse_task: Optional[asyncio.Task] = None
11+
parsed_codebase: Optional[Codebase] = None
12+
log_buffer: List[str] = field(default_factory=list)
13+
14+
async def parse(self, path: str) -> Codebase:
15+
"""Parse the codebase at the given path."""
16+
codebase = Codebase(path)
17+
self.parsed_codebase = codebase
18+
return codebase
19+
20+
def reset(self) -> None:
21+
"""Reset the state."""
22+
if self.parsed_codebase:
23+
self.parsed_codebase.reset()
24+
self.log_buffer.clear()
25+
26+
# Initialize FastMCP server
27+
mcp = FastMCP(
28+
"codegen-mcp-server",
29+
instructions="""This server provides tools to parse and modify a codebase using codemods.
30+
It can initiate parsing, check parsing status, and execute codemods.""",
31+
)
32+
33+
# Initialize state
34+
state = CodebaseState()
35+
36+
def capture_output(*args, **kwargs) -> None:
37+
"""Capture and log output messages."""
38+
for arg in args:
39+
state.log_buffer.append(str(arg))
40+
41+
@mcp.tool(name="parse_codebase", description="Initiate codebase parsing")
42+
async def parse_codebase(
43+
codebase_path: Annotated[str, "path to the codebase to be parsed"]
44+
) -> Dict[str, str]:
45+
if not state.parse_task or state.parse_task.done():
46+
state.parse_task = asyncio.create_task(state.parse(codebase_path))
47+
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."}
48+
return {"message": "Codebase is already being parsed."}
49+
50+
@mcp.tool(name="check_parsing_status", description="Check if codebase parsing has completed")
51+
async def check_parsing_status() -> Dict[str, str]:
52+
if not state.parse_task:
53+
return {"message": "No codebase provided to parse."}
54+
if state.parse_task.done():
55+
return {"message": "Codebase parsing completed."}
56+
return {"message": "Codebase parsing in progress."}
57+
58+
@mcp.tool(name="execute_codemod", description="Execute a codemod on the codebase")
59+
async def execute_codemod(
60+
codemod: Annotated[str, "The python codemod code to execute on the codebase"]
61+
) -> Dict[str, Any]:
62+
if not state.parse_task or not state.parse_task.done():
63+
return {"error": "Codebase is not ready for codemod execution."}
64+
65+
try:
66+
codebase = await state.parse_task
67+
# TODO: Implement proper sandboxing for code execution
68+
context = {
69+
"codebase": state.parsed_codebase,
70+
"print": capture_output,
71+
}
72+
exec(codemod, context)
73+
74+
logs = "\n".join(state.log_buffer)
75+
76+
state.reset()
77+
return {
78+
"message": "Codemod executed and codebase reset.",
79+
"logs": logs
80+
}
81+
except Exception as e:
82+
return {
83+
"error": f"Error executing codemod: {str(e)}",
84+
"details": {
85+
"type": type(e).__name__,
86+
"message": str(e)
87+
}
88+
}
89+
90+
if __name__ == "__main__":
91+
print('starting codegen-mcp-server')
92+
run = mcp.run_stdio_async()
93+
print('codegen-mcp-server started')
94+
asyncio.run(run)

0 commit comments

Comments
 (0)