Skip to content
Closed
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
3 changes: 2 additions & 1 deletion codemcp/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python3

from .hot_reload_entry import run as run_hot_reload
from .main import codemcp, configure_logging, mcp, run
from .main import cli, codemcp, configure_logging, mcp, run
from .shell import get_subprocess_env, run_command

__all__ = [
Expand All @@ -12,4 +12,5 @@
"codemcp",
"run_command",
"get_subprocess_env",
"cli",
]
5 changes: 3 additions & 2 deletions codemcp/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

# WARNING: do NOT do a relative import, this file must be directly executable
# by filename
from codemcp import mcp, run
from codemcp import cli, mcp

__all__ = ["mcp"]

if __name__ == "__main__":
run()
# Use Click's CLI interface instead of directly calling run()
cli()
89 changes: 89 additions & 0 deletions codemcp/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

import logging
import os
import sys
from pathlib import Path
from typing import Optional

import click
from mcp.server.fastmcp import FastMCP

from .tools.chmod import chmod
Expand Down Expand Up @@ -406,6 +410,91 @@ def filter(self, record):
logging.info("Logs from 'mcp' module are being filtered")


def init_codemcp_project(path: str) -> str:
"""Initialize a new codemcp project.

Args:
path: Path to initialize the project in

Returns:
Message indicating success or failure
"""
import subprocess

try:
# Convert to Path object and resolve to absolute path
project_path = Path(path).resolve()

# Create directory if it doesn't exist
project_path.mkdir(parents=True, exist_ok=True)

# Check if git repository already exists
git_dir = project_path / ".git"
if not git_dir.exists():
# Initialize git repository
subprocess.run(["git", "init"], cwd=project_path, check=True)
print(f"Initialized git repository in {project_path}")
else:
print(f"Git repository already exists in {project_path}")

# Create empty codemcp.toml file if it doesn't exist
config_file = project_path / "codemcp.toml"
if not config_file.exists():
with open(config_file, "w") as f:
f.write("# codemcp configuration file\n\n")
print(f"Created empty codemcp.toml file in {project_path}")
else:
print(f"codemcp.toml file already exists in {project_path}")

# Make initial commit if there are no commits yet
try:
# Check if there are any commits
result = subprocess.run(
["git", "rev-parse", "HEAD"],
cwd=project_path,
check=False,
capture_output=True,
text=True,
)

if result.returncode != 0:
# No commits yet, add codemcp.toml and make initial commit
subprocess.run(
["git", "add", "codemcp.toml"], cwd=project_path, check=True
)
subprocess.run(
["git", "commit", "-m", "chore: initialize codemcp project"],
cwd=project_path,
check=True,
)
print("Created initial commit with codemcp.toml")
else:
print("Repository already has commits, not creating initial commit")
except subprocess.CalledProcessError as e:
print(f"Warning: Failed to create initial commit: {e}")

return f"Successfully initialized codemcp project in {project_path}"
except Exception as e:
return f"Error initializing project: {e}"


@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
"""CodeMCP: Command-line interface for MCP server and project management."""
# If no subcommand is provided, run the MCP server (for backwards compatibility)
if ctx.invoked_subcommand is None:
run()


@cli.command()
@click.argument("path", type=click.Path(), default=".")
def init(path):
"""Initialize a new codemcp project with an empty codemcp.toml file and git repository."""
result = init_codemcp_project(path)
click.echo(result)


def run():
"""Run the MCP server."""
configure_logging()
Expand Down
71 changes: 71 additions & 0 deletions e2e/test_init_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env python3

import subprocess
import tempfile
from pathlib import Path

from codemcp.main import init_codemcp_project


def test_init_command():
"""Test the init command creates a codemcp.toml file and initializes a git repo."""
# Create a temporary directory for testing
with tempfile.TemporaryDirectory() as temp_dir:
# Run the init_codemcp_project function
result = init_codemcp_project(temp_dir)

# Check that the function reports success
assert "Successfully initialized" in result

# Check that codemcp.toml was created
config_file = Path(temp_dir) / "codemcp.toml"
assert config_file.exists()

# Check that git repository was initialized
git_dir = Path(temp_dir) / ".git"
assert git_dir.is_dir()

# Check that a commit was created
result = subprocess.run(
["git", "log", "--oneline"],
cwd=temp_dir,
capture_output=True,
text=True,
check=True,
)
assert "initialize codemcp project" in result.stdout


def test_init_command_existing_repo():
"""Test the init command works with an existing git repository."""
# Create a temporary directory for testing
with tempfile.TemporaryDirectory() as temp_dir:
# Initialize git repository first
subprocess.run(["git", "init"], cwd=temp_dir, check=True)

# Make a dummy commit to simulate existing repository
dummy_file = Path(temp_dir) / "dummy.txt"
dummy_file.write_text("test content")

subprocess.run(
["git", "config", "user.name", "Test User"], cwd=temp_dir, check=True
)
subprocess.run(
["git", "config", "user.email", "test@example.com"],
cwd=temp_dir,
check=True,
)
subprocess.run(["git", "add", "dummy.txt"], cwd=temp_dir, check=True)
subprocess.run(
["git", "commit", "-m", "Initial commit"], cwd=temp_dir, check=True
)

# Run the init_codemcp_project function
result = init_codemcp_project(temp_dir)

# Check that the function reports success
assert "Successfully initialized" in result

# Check that codemcp.toml was created
config_file = Path(temp_dir) / "codemcp.toml"
assert config_file.exists()
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies = [
"pyyaml>=6.0.0",
"pytest-xdist>=3.6.1",
"editorconfig>=0.17.0",
"click>=8.1.8",
]

[dependency-groups]
Expand All @@ -28,7 +29,7 @@ dev = [
]

[project.scripts]
codemcp = "codemcp:run"
codemcp = "codemcp:cli"
codemcp-multi = "codemcp.multi_entry:main"

[build-system]
Expand Down
2 changes: 2 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading