Code2MCP: Transforming Code Repositories into MCP Services

August 18, 2026 · View on GitHub

Code2MCP: Transforming Code Repositories into MCP Services

Official Repository arXiv License: MIT Github stars

Chaoqian Ouyang (欧阳超前)*Logo,     Ling YUE (岳凌)*Logo,     Shimin Di (邸世民)Logo,     Libin Zheng (郑立彬)Logo,    

Linan Yue (岳立楠)Logo,     Shaowu Pan (潘韶武)Logo,     Jian Yin (印鉴)Logo,     Min-Ling Zhang (张敏灵)Logo,    

* Equal ContributionCorresponding Author

Project Overview

Code2MCP Workflow Overview

Code2MCP is an automated workflow system that transforms existing code repositories into MCP (Model Context Protocol) services. The system follows a minimal intrusion principle, preserving the original repository's core code while only adding service-related files and tests.

Core Features

  1. Intelligent Code Analysis

    • AST-first source analysis by default, with optional LLM enrichment
    • Automatic identification of real core modules, public functions, classes, signatures, imports, and file paths
    • Smart generation of MCP service code
  2. MCP Service Generation

    • Automatic generation of mcp_service.py, adapter.py, and other core files
    • Support for multiple project structures (src/, source/, root directory, etc.)
    • Ranks safer wrapper candidates first and avoids complex parameters, unsafe paths, and classes that require constructor arguments
  3. Workflow Automation

    • Complete 7-node workflow: download -> analysis -> env -> generate -> run -> review -> finalize
    • Automatic environment configuration and test validation
    • Comprehensive logging and status tracking
    • Intelligent error recovery and retry mechanisms
  4. End-to-End Automation

    • Generates HuggingFace Spaces/Docker deployment scaffolding
    • Automatic client configuration after a validated local or remote service is available
    • Runtime validation is required before a conversion is marked successful

Quick Start

1. Create a Python Environment

Code2MCP requires Python 3.10 or newer because FastMCP does not support Python 3.9.

Conda example:

conda create -n code2mcp python=3.12 -y
conda activate code2mcp

venv example, when your python is already 3.10+:

python -m venv .venv

Windows PowerShell:

.\.venv\Scripts\Activate.ps1

Bash/macOS/Linux:

source .venv/bin/activate

Confirm the version:

python --version

2. Configure Environment Variables

Copy the environment variables template:

cp env.example .env

Windows PowerShell:

Copy-Item .\env.example .\.env

Edit .env and fill OPENAI_API_KEY before running:

MODEL_PROVIDER=openai
OPENAI_API_KEY=sk-...

If you already have a local Codex/OpenAI auth cache, you may use Codex auth instead:

MODEL_PROVIDER=openai-codex
OPENAI_API_KEY=
OPENAI_CODEX_AUTH_FILE=C:\Users\<you>\.codex\auth.json

3. Install Dependencies

python -m pip install -U pip
python -m pip install -r requirements.txt

The default Codex model is controlled by OPENAI_CODEX_MODEL. Override it if your account uses a different Codex backend model name. Generated OpenAI Responses API copy examples use OPENAI_RESPONSES_MODEL when set, then OPENAI_MODEL, and finally gpt-5. They intentionally do not use OPENAI_CODEX_MODEL, because Codex auth/cache models and public OpenAI API example models are separate paths.

Code2MCP requires Python 3.10 or newer for FastMCP. If the python on PATH is older than 3.10, use a modern interpreter for installation and set CODE2MCP_PYTHON before running validation:

python --version
CODE2MCP_PYTHON=C:\path\to\python.exe

4. Run Workflow

Default Hugging Face preparation. This runs analysis, environment setup, generation, and finalize, then writes MCP files and deployment scaffolding. It does not push to Hugging Face unless AUTO_DEPLOY_HF=true and HF_PUSH=true:

python main.py https://github.com/<owner>/<repo>

Analysis is AST-first by default. LLM analysis can be enabled with CODE2MCP_ANALYSIS_LLM=true, but LLM output is filtered against static source evidence and cannot introduce tools for symbols that do not exist.

Generation, review, and finalize use deterministic service, adapter, README, repair-analysis, and summary fallbacks by default. Optional LLM-written adapter, README, review repair, and finalize analysis can be enabled with CODE2MCP_ADAPTER_LLM=true, CODE2MCP_README_LLM=true, CODE2MCP_REVIEW_LLM=true, and CODE2MCP_FINALIZE_LLM=true, but these are not required for validation and may add latency.

Generate files only, without runtime validation. This still runs analysis and environment preparation before generation, then skips run/review validation after generation. It returns a generated state, not a validated success:

python main.py https://github.com/<owner>/<repo> --generate-only

Validated local run. This generates local Docker scripts after validation. It does not start a long-running Docker service unless CODE2MCP_LOCAL_AUTORUN=true:

python main.py https://github.com/<owner>/<repo> local

Local directories and file:// URLs are supported. Code2MCP copies them into an isolated workspace/<repo>/source directory and ignores generated artifacts such as .git, mcp_output, deployment, and virtual environments:

python main.py file:///C:/path/to/repo local
python main.py E:\path\to\repo local

Runtime validation uses scripts/validate_mcp_service.py with a real FastMCP Client. By default CODE2MCP_CLIENT_VALIDATION_REQUIRE_SEMANTIC_SUCCESS=true, CODE2MCP_CLIENT_VALIDATION_REQUIRE_MEANINGFUL_RESULT=true, and CODE2MCP_CLIENT_VALIDATION_SEMANTIC_POLICY=all, meaning at least one executed tool must return a structured {"success": true} result with a non-empty result payload, and any executed tool that returns success=false fails validation. All safely sampleable tools are called by default, while complex/path-like tools are skipped unless explicitly requested. Set CODE2MCP_MAX_CLIENT_CALLS=<n> or workflow option max_client_calls only when you intentionally want to cap validation for debugging.

Generation focuses on public functions by default. Class wrappers are disabled unless CODE2MCP_ENABLE_CLASS_WRAPPERS=true, because many classes require project state or data and object construction alone is rarely a useful MCP tool.

Environment setup installs the core MCP runtime first, then prefers package metadata or AST-discovered import packages over full requirements.txt files. This avoids treating docs/dev/heavy optional dependencies as mandatory for smoke validation. Set CODE2MCP_INSTALL_FULL_REQUIREMENTS_FIRST=true when you intentionally want requirements installed before the lightweight strategy, and CODE2MCP_INSTALL_HEAVY_IMPORT_DEPS=true when deeper native/scientific dependency installation is acceptable.

5. Deployment Guide

5.1 Generated deployment/ layout

workspace/<repo>/deployment/
- Dockerfile
- requirements.txt
- app.py
- run_docker.sh
- run_docker.ps1
- port.json
- connection_hint.json
- <repo_name>/
  - mcp_output/
    - start_mcp.py
    - mcp_plugin/
    - README_MCP.md
  - source/ (original repository files)

5.2 Which path to follow

  • python main.py https://github.com/<owner>/<repo> uses the default hf target and prepares Hugging Face deployment files.
  • python main.py https://github.com/<owner>/<repo> local uses the local target and prepares local Docker scripts after validation.

5.3 Hugging Face Spaces

By default Code2MCP creates the deployment/ directory but does not push to Hugging Face. To push automatically, both of these must be true in .env:

AUTO_DEPLOY_HF=true
HF_PUSH=true

The generated deployment folder includes:

  • Dockerfile: starts workspace/<repo>/mcp_output/start_mcp.py with MCP_TRANSPORT=http and MCP_PORT=7860
  • requirements.txt: merged runtime requirements with fastmcp and pydantic included as a baseline
  • deployment_manifest.json: records the entrypoint, transport, port, and /mcp path

When pushed to Hugging Face, the usable MCP endpoint is:

https://{your-username}-{space-name}.hf.space/mcp
git clone https://huggingface.co/spaces/{your-username}/{space-name} {local-dir}
cd {local-dir}

Copy all files from workspace/<repo>/deployment/ into {local-dir} root (do not include the deployment folder itself), then:

git add .

Remove local Git hooks if your environment enforces hooks:

  • Bash:
    rm -rf .git/hooks
    
  • PowerShell:
    Remove-Item -Recurse -Force .git\hooks
    
git commit -m "Init"
git push

If git push fails due to large/binary files, use Git LFS and retry:

git lfs install
git lfs track "*.bin" "*.pt" "*.onnx" "*.h5" "*.npz" "*.pkl" "*.pickle" "*.tar" "*.gz" "*.zip" "*.7z" "*.so" "*.dll" "*.dylib" "*.png" "*.jpg" "*.jpeg"
git add .gitattributes
git add .
git commit -m "Use Git LFS"
git push

If large files already exist in history:

git lfs migrate import --include="*.bin,*.pt,*.onnx,*.h5,*.npz,*.pkl,*.pickle,*.tar,*.gz,*.zip,*.7z,*.so,*.dll,*.dylib,*.png,*.jpg,*.jpeg"
git push --force

Use the generated connection guide to choose the right payload for your agent:

python scripts/connect_agent.py --repo-root workspace/<repo> --open-guide --remote-url https://{your-username}-{space-name}.hf.space --probe-remote

If --remote-url is provided without --probe-remote, Code2MCP still writes copyable payloads, but remote ChatGPT/OpenAI readiness stays false because the HTTPS MCP endpoint has not been verified with a FastMCP client. Remote config writes require --probe-remote.

For clients that accept MCP JSON, the remote server shape is:

{
  "mcpServers": {
    "{alias}": {
      "url": "https://{your-username}-{space-name}.hf.space/mcp"
    }
  }
}

5.4 Local (port allocation & reuse)

  • Port range: 7860–7999
  • Strategy: derive a preferred port from repository name; if taken, probe the next available
  • Record: workspace/<repo>/deployment/port.json
  • Connection hint: workspace/<repo>/deployment/connection_hint.json
  • Generated local scripts only build and start the Docker HTTP service. They do not modify Cursor, Claude, VS Code, or any other agent configuration.
  • Code2MCP does not launch the local Docker service automatically unless CODE2MCP_LOCAL_AUTORUN=true.

No port conflict concerns

  • The launcher derives a stable per-repository preferred port in 7860-7999.
  • It probes availability with a bind test; if taken, it increments to the next free port.
  • The chosen port is persisted to workspace/<repo>/deployment/port.json and the HTTP MCP URL is written to workspace/<repo>/deployment/connection_hint.json.
  • On subsequent runs, it tries the recorded port first; if busy, it automatically picks the next free one.
  • Multiple concurrent runs safely spread across free ports without clashes.

After starting the local Docker service, open workspace/<repo>/mcp_output/agent_connect.html or run:

python scripts/connect_agent.py --repo-root workspace/<repo> --client cursor --remote --remote-url http://localhost:<port> --probe-remote --write
python scripts/connect_agent.py --repo-root workspace/<repo> --client vscode --remote --remote-url http://localhost:<port> --probe-remote
python scripts/connect_agent.py --repo-root workspace/<repo> --client openai --remote-url http://localhost:<port> --probe-remote

End-to-End Automation

What Happens:

  1. Analyzes real source files under workspace/<repo>/source
  2. Creates an isolated Python environment with the core MCP validation packages
  3. Generates MCP service files from discovered public functions/classes
  4. Runs import/create_app/tool-registration smoke tests and FastMCP Client tool calls
  5. Attempts review/fix/regeneration on failure
  6. Writes a final status: validated, generated, or failed
  7. Writes deployment/local launch scripts without starting a long-running service by default

Workflow Process

  1. Download Node: Clone repository to workspace/{repo_name}/
  2. Analysis Node: Analyze real source files and identify public modules/functions/classes
  3. Env Node: Create isolated environment with core MCP validation packages and validate original project
  4. Generate Node: Generate MCP service code from verified analysis results
  5. Run Node: Execute import/create_app/tool-registration smoke tests and FastMCP Client tool calls
  6. Review Node: Analyze runtime failures with heuristic evidence by default, record failed client-called tools, attempt deterministic generated-file fixes when safe, or regenerate while avoiding previously failed tools. Set CODE2MCP_REVIEW_LLM=true only when you want LLM-written review analysis and direct repairs.
  7. Finalize Node: Compile results, write validated, generated, or failed status, generate connection/deployment artifacts, and use deterministic reports unless CODE2MCP_FINALIZE_LLM=true

validated means the generated service passed runtime smoke tests and client-level MCP tool validation. generated means files were produced with --generate-only, but the service was not verified. failed means Code2MCP could not prove the generated service runs.

Security Validation

Generated tools that expose path-like inputs (file_path, path, directory, and similar names) must call _safe_resolve_path before invoking project code. The guard rejects absolute paths, URI schemes, home/UNC/network paths, .. traversal, hidden path segments, sensitive path segments such as secret/token/password/key/credential/private/auth, and any path resolving outside the source directory.

The generator quality gate does not only check for the helper name. It compiles the helper in isolation and runs unsafe samples such as traversal, hidden files, URI paths, absolute paths, and sensitive path segments. A weak or placeholder helper fails generation/review and cannot be reported as validated.

Reusable safety policy helpers live under src/security/. Parameter and tool validation rules are centralized there so generation and client validation can share the same skip decisions without hard-coding them in the workflow path.

Benchmark Validation

The repository includes scripts to validate Code2MCP against a curated CSV benchmark list.

Resolve repo names to real GitHub repositories:

python scripts/resolve_benchmark_repos.py --csv "D:\download\WeiXin\xwechat_files\wxid_d88haf3if05n12_cb61\msg\file\2025-12\Repo汇总-Sheet1(1).csv"

Run the first 50 valid repositories with resumable logging:

python scripts/run_benchmark.py --manifest benchmark/repositories_resolved.json --limit 50 --resume

The benchmark runs the workflow and then invokes the generated MCP service through scripts/validate_mcp_service.py. By default it requires at least one called tool to return {"success": true} with a non-empty result payload; use --no-require-semantic-success or --no-require-meaningful-result only for transport-only diagnostics. Use --semantic-policy any|all|none to tune how returned {"success": ...} payloads are interpreted. Benchmark validation also calls all safely sampleable tools by default; pass --max-client-calls <n> only for capped exploratory runs. Each result records the Code2MCP commit and whether the working tree was dirty, so benchmark evidence can be traced back to the exact code version. Outputs are written under benchmark/ and are intentionally ignored by git: results*.json, benchmark_report*.md, per-repository logs, and artifact snapshots containing fresh workflow_summary.json, run_log.json, analysis.json, env_info.json, and error_analysis.json when available.

Output Structure

Complete structure for each converted project:

Output Structure

Successfully Converted Project Examples

  • UFL: Finite element symbolic language → MCP finite element analysis
  • dalle-mini: Higher-quality, controllable text-to-image → MCP image generation
  • ESM: Protein structure/variant scoring (real artifacts) → MCP protein analysis
  • deep-searcher: Query rewrite, multi-hop, credible sources → MCP search
  • TextBlob: Deterministic tokenize/POS/sentiment → MCP NLP preprocessing
  • dateutil: Correct timezones/rrule edge cases → MCP time utilities
  • sympy: Exact symbolic math/solve/codegen → MCP math reasoning

Key Features

  • Smart Import Handling: Automatic identification of correct module import paths
  • Professional Documentation: Automatic generation of English README and comments
  • Comprehensive Test Coverage: Includes basic functionality tests and health checks
  • Detailed Report Generation: Provides complete conversion process reports
  • Intelligent Dependency Management: Automatic handling of complex Python package dependencies

Usage Example

python main.py https://github.com/username/repo

Quick Agent Connection

Code2MCP writes reusable connection files for every generated service:

workspace/<repo>/mcp_output/agent_connect.html
workspace/<repo>/mcp_output/agent_connection.json
workspace/<repo>/mcp_output/agent_mcp_config.json
workspace/<repo>/mcp_output/cursor_mcp_config.json

For a local MCP service, no Hugging Face deployment is required. After the workflow is validated, open the copy guide and choose the agent you use:

python scripts/connect_agent.py --repo-root workspace/<repo> --open-guide

The guide shows what to copy for Cursor, Claude Desktop, Claude Code, VS Code, Windsurf, Cline, Gemini CLI, ChatGPT, OpenAI API, generic MCP clients, local stdio mode, and remote HTTP mode.

GPT / ChatGPT note:

  • ChatGPT apps and the OpenAI Responses API use remote MCP servers, not local stdio command/args.
  • Deploy the generated service to an HTTPS MCP endpoint first, then copy the ChatGPT or OpenAI API card from agent_connect.html.
  • The OpenAI API card contains a tools entry with type: "mcp" and server_url.

If you intentionally want Code2MCP to write Cursor config for you:

python scripts/connect_agent.py --repo-root workspace/<repo> --client cursor --write

To preview the MCP JSON without writing any client config:

python scripts/connect_agent.py --repo-root workspace/<repo> --client generic

To verify a task-level agent call, run the generated MCP service through a real FastMCP client with a natural-language task and explicit arguments:

python scripts/agent_validate_mcp_service.py --repo-root workspace/<repo> --task "format 1536 bytes as a natural size" --arguments-file args.json --expect-contains "kB"

This harness lists tools, selects the best matching tool by weighted name/description/schema overlap, refuses ambiguous selection unless --expect-tool is provided, calls the tool, and checks the returned result. It requires {"success": true} and a non-empty result by default; use --no-require-success --no-require-meaningful-result only for transport-only diagnostics. Prefer --arguments-file for JSON on Windows shells. It is meant for scenario validation after the general smoke/client validation has already passed.

You can also connect immediately after a successful conversion:

python main.py https://github.com/<owner>/<repo> local --connect-client cursor --connect-write

Safety behavior:

  • Client config writes are refused unless workflow_summary.json says the MCP service is validated.
  • Use --allow-unvalidated only when intentionally testing an unverified service.
  • Existing Cursor config is merged under mcpServers; if a config file already exists, a timestamped backup is created first.
  • The HTML guide never writes client files; it only displays copyable configuration.

For remote services, deploy first and then pass the remote base URL:

python scripts/connect_agent.py --repo-root workspace/<repo> --client cursor --remote-url https://<space>.hf.space --remote --probe-remote --write
python scripts/connect_agent.py --repo-root workspace/<repo> --client vscode --remote-url https://<space>.hf.space --remote --probe-remote
python scripts/connect_agent.py --repo-root workspace/<repo> --client openai --remote-url https://<space>.hf.space --probe-remote

Citation

If you use Code2MCP in your research, please cite our paper:

@article{ouyang2025code2mcp,
  title={Code2MCP: Transforming Code Repositories into MCP Services},
  author={Ouyang, Chaoqian and Yue, Ling and Di, Shimin and Zheng, Libin and Yue, Linan and Pan, Shaowu and Yin, Jian and Zhang, Min-Ling},
  journal={arXiv preprint arXiv:2509.05941},
  year={2025}
}