Skip to main content
Glama

judge0-mcp

Judge0 评测栈包装成 MCP 服务的本地算法题评测系统

它向 MCP 客户端(如 VS Code Copilot、Claude Desktop、WorkBuddy 等)暴露 7 个工具,让大模型完成 「读题 → 样例自测 → 全量隐藏数据提交」的完整评测闭环;判题参数、提交次数、数据访问边界等 均由服务端强制,模型无法绕过。适用于大模型编程能力评测、算法教学实验与自动化判题场景。

特性

  • 7 个 MCP 工具:题库浏览、题面/样例下发、样例自测、全量提交、结果查询、统计聚合。

  • 判题参数服务端注入:语言 id、编译选项、CPU/wall 时限、内存全部取自配置与题库,调用方传入一律无效。

  • 提交约束:按模式限制每题提交次数;完全相同的代码经 MD5 去重后拒绝且不消耗次数。

  • 数据边界:隐藏测试数据不进入模型工作区;提交结果只回传状态/耗时/内存/分数,绝不回传 expected_output

  • 工作区防护:题面与样例只能拷入 AGENT_WORKSPACE 内,拒绝路径穿越。

  • 评测机故障处理:Judge0 返回 Internal Error 时自动重试,整批仍故障则不消耗提交次数。

  • 实验记录:每次工具调用自动写入 JSONL(runs/<run_id>.jsonl),内置统计脚本一键出报告。

  • 配置与题库解耦:基础设施在 config.json,题库在 problems.json,代码内不写死题目。

  • 可移植:路径全部可配置(配置文件 + 环境变量),无任何机器相关硬编码。

Related MCP server: multivon-mcp

架构

flowchart LR
    A["MCP 客户端<br/>(Copilot / Claude / WorkBuddy)"] -- "stdio (JSON-RPC)" --> B["server.py<br/>FastMCP 服务"]
    B -- "HTTP :2358" --> C["Judge0 Server"]
    C -- "队列" --> D["Judge0 Workers"]
    D -- "isolate 沙箱" --> E["编译 & 执行<br/>Python 3.8.1 / GCC 9.2.0"]
    B -. "读题面/样例" .-> F["statement/"]
    B -. "读隐藏数据" .-> G["data/"]
    B -. "写实验记录" .-> H["runs/*.jsonl"]
  • Judge0 通常部署在 WSL2 / Linux(Docker),MCP 服务可跑在 Windows 或同一 Linux 环境。

  • 隐藏测试数据只由服务端读取,模型只能看到判题结论。

目录结构

.
├── server.py                 # ★ MCP 服务主程序(7 工具)
├── config.json               # 基础设施配置(路径/并发/约束/语言表/题面头部模板)
├── problems.example.json     # 题库模板(复制为 problems.json 后填入真实题目)
├── problems.json             # 题库元数据(本地资产,不随仓库发布)
├── analyze_runs.py           # 实验统计脚本(聚合 runs/*.jsonl)
├── requirements.txt          # Python 依赖
├── mcp.example.json          # MCP 客户端配置模板
├── docs/agent-prompt.md      # 被测模型的系统提示词参考
├── tools/pack_dataset.py     # 数据集打包脚本(题库材料 → 带校验清单的 zip)
├── statement/                # 题面 + 公开样例压缩包(本地资产)
├── data/<id>/                # 隐藏测试数据(本地资产,不入版本库)
├── judge0-v1.13.1/           # Judge0 部署包(compose + 启动脚本 + 配置模板)
├── cache/samples/<id>/       # 启动时预解压的样例(运行时生成)
└── runs/<run_id>.jsonl       # 实验记录(运行时生成)

为什么 statement/data/ 存在但不在版本库里:题面、样例与测试数据版权归原始出题方所有, 通过 .gitignore 排除、由使用者自行准备。两者都放在仓库目录内,使相对路径可预期、开箱即用; 位置可通过 config.json 或环境变量重定向。

前置条件

要求

Python

≥ 3.10(开发验证环境为 CPython 3.13.5)

Judge0

可访问的 Judge0 CE 1.13.1 实例(默认 http://localhost:2358

Docker

若自行部署 Judge0:Docker Engine ≥ 20(含 docker compose v2);磁盘 ≥ 15 GB

题库材料

题面 Markdown、公开样例压缩包、隐藏测试数据(见下节)

快速开始

1. 准备 Judge0 后端

若已有可用实例,直接跳过。若需自建,本仓库在 judge0-v1.13.1/ 提供了自包含部署包:

cd judge0-v1.13.1
bash start_judge0.sh        # 首次运行会生成带随机密码的 judge0.conf,然后拉镜像并启动

脚本会依次完成:生成 judge0.conf → 环境检查 → 拉取镜像 → 启动 db/redis → 等待 postgres → 启动 server/workers → 等待 API → 真实提交冒烟验证。看到以下输出即表示评测链路可用:

==> ✅ Judge0 已就绪, 评测链路正常 (http://localhost:2358)

WSL2 下 cgroup v2 与官方 Judge0 镜像的 isolate 沙箱不兼容(所有提交返回 Internal Error), 本部署包已改用社区兼容镜像,详见 judge0-v1.13.1/README.md

验证服务:

curl -s http://localhost:2358/about          # 版本信息
curl -s http://localhost:2358/languages      # 语言列表

2. 创建 Python 环境

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt

3. 准备题库与数据

题库材料不入库,需要自行放置:

Copy-Item problems.example.json problems.json    # 然后填入真实题目元数据

材料

放置位置

说明

题库元数据

problems.json

复制 problems.example.json 后填写(字段说明见模板内 _readme

题面 + 公开样例

statement/

<id>.md<id>.zip,zip 内含 <id>N.in / <id>N.ans

隐藏测试数据

paths.data_dir(默认仓库内的 data/

每题目录下 <id>N.in / <id>N.ans

路径均可通过 config.json 或环境变量重定向(见「环境变量」)。若已有打包好的数据集, 用 tools/pack_dataset.py 生成的 zip 解包即可(该包内含 MANIFEST.sha256 校验清单)。

4. 接入 MCP 客户端

复制 mcp.example.json,把占位符替换为实际路径,然后填入客户端的 MCP 配置:

{
  "mcpServers": {
    "judge0-mcp": {
      "command": "<REPO_ROOT>/.venv/Scripts/python.exe",   // 必须用装了依赖的 venv 解释器
      "args": ["<REPO_ROOT>/mcp-server/server.py"],
      "env": {
        "AGENT_WORKSPACE": "<WORKSPACE_DIR>",              // 模型工作区(题面/样例拷入处)
        "MODEL_NAME": "<MODEL_NAME>",                      // 当次被测模型名(实验记录维度)
        "MODE": "iterative",                               // iterative | one-shot
        "RUN_ID": "<RUN_ID>",                              // 每次实验唯一 id(JSONL 文件名)
        "JUDGE0_BASE": "http://localhost:2358"
      }
    }
  }
}

Agent 无法篡改这些变量(服务端只读 env),因此 MODEL_NAME / RUN_ID / MODE 是可靠的统计维度。 每次正式实验前记得更换 RUN_IDMODEL_NAME,并重启 MCP 服务进程。

5. 自检

# 依赖与工具注册
.\.venv\Scripts\python.exe -c "import sys; sys.path.insert(0,'mcp-server'); import server, asyncio; print(asyncio.run(server.mcp.list_tools()))"

随后在 MCP 客户端中让模型执行一次完整闭环:list_problemsinit_problemrun_test(样例 AC) → submit_code(满分)。若通过,说明接入成功。

工具参考

工具

签名

说明

题库列表

list_problems()

返回每题 problem_idname、点数、分值、时空限制、可用语言、init_state

初始化题目

init_problem(problem_id, target_dir=None)

把题面与公开样例拷入工作区,题面头部注入【评测约定】;幂等

题目详情

get_problem(problem_id)

元数据白名单(含 io_modesample_groups),不含题面正文与内部元数据

样例自测

run_test(problem_id, code, lang, sample_no=None, stdin=None)

sample_no 判定样例;stdin 只运行不判题。返回 verdict/stdout/time/memory/CE 编译输出

正式提交

submit_code(problem_id, code, lang)

全量隐藏测试点批测,返回逐点状态、分数、final_statusfailed_summary

结果查询

get_result(submission_id)

仅用于 submit_code 返回 pending 时

统计聚合

get_statistics()

聚合 runs/*.jsonl(供研究者,不建议被测模型调用)

lang 取值由 config.jsonlanguages 定义(默认 python3 / cpp); 不接受语言 id 或编译参数,传入会报错。

服务端强制约束

约束

行为

提交次数

iterative 模式每题最多 3 次;one-shot 模式仅 1 次。超出直接拒绝

重复代码

MD5 去重,命中则拒绝且不消耗次数

判题参数

语言 id / 编译选项 / 时限 / 内存全部由服务端注入

IO 预检

检测到 freopen / ifstream / fstream 等文件 IO 时返回 warnings(仅警告,不拒绝)

样例自测

iterative 不限次(同题第 10 次起软提醒);one-shot 硬拒绝

评测机故障

单点自动重试;整批仍有 IE/EF 时返回 machine_failure: true不消耗次数、不登记 MD5

隐藏数据

只读不写;返回值不含 expected_output

工作区

init_problem 目标必须位于 AGENT_WORKSPACE 内,否则拒绝

批测

并发上限 judge0.max_workers;超过 judge0.batch_timeout_seconds 返回 pending

记录

每次工具调用追加写入 runs/<run_id>.jsonl

配置

config.json

内容

server

MCP 服务名、版本、instructions(提供给客户端的工具使用说明)

paths

problems_file / statement_dir / cache_dir / runs_dir / data_dir(相对本文件;可被环境变量覆盖)

judge0

base_url、超时与轮询参数、max_workers、WSL 回退开关、状态码映射、MLE 归类阈值

constraints

提交次数上限、run_test 软提醒阈值、故障重试策略、失败类型优先级、IO 预检正则

languages

语言槽位名 → id / display / compiler_options

statement_header

题面头部【评测约定】模板({languages}{compile_options}{cpu_limit}{wall_limit}{memory_mb} 等占位符)

环境变量

变量

作用

AGENT_WORKSPACE

模型工作区根目录;init_problem 只能写入此目录内。未设置时拒绝 init

MODEL_NAME

被测模型名,写入 JSONL 供统计归组

MODE

iterativeone-shot,决定提交上限与 run_test 可用性

RUN_ID

本次实验 id,决定 JSONL 文件名

JUDGE0_BASE

Judge0 地址(默认取 config.jsonjudge0.base_url

JUDGE0_CONFIG_FILE

指定的 config.json 路径

JUDGE0_PROBLEMS_FILE

题库文件路径

JUDGE0_STATEMENT_DIR

题面与样例目录

JUDGE0_CACHE_DIR

样例缓存目录

JUDGE0_RUNS_DIR

实验记录目录

JUDGE0_DATA_DIR

隐藏测试数据目录(默认 data/

路径优先级:环境变量 > config.json > 内置默认

评测约定与规格

服务端在 init_problem 时把以下约定注入题面头部(内容由 config.jsonstatement_header 渲染):

  • 评测一律使用标准 stdin/stdout,禁止文件 IO;原题面中「见选手目录下的 x.in」等说法一律忽略。

  • 列出可用语言及其运行时版本,以及 C++ 的固定编译选项

  • 列出 CPU / wall 时限与内存上限。

  • 说明公开样例位置(工作区内的 sample/)。

编译选项

C++ 统一使用 -O2 -std=c++14 -static(与官方评测环境一致)。若某题确实需要其他标准, 可在 problems.json 中用 compiler_options 按题覆盖,无需改代码。

本地放宽与 Judge0 语义差异

说明

时限

本地评测机通常慢于官方评测机,可在 problems.json 放宽 time_limit_cpu / time_limit_wall;官方原始值可另存字段供报告对照

内存

Judge0 沙箱有 max_memory_limit 硬上限(默认部署下为 512000 KB),题库中的 memory_limit_kb 不得超过它

比对方式

Judge0 为 token 级比对,容忍行尾空白与末尾换行

MLE 归类

Judge0 1.13.1 无独立 MLE 状态:超内存表现为 SIGKILL(exit_code=137)或内存逼近上限,服务端结合二者归类为 MLE

CE 延迟

compile_output 可能延迟返回,服务端按 token 轮询

编码

提交与查询统一使用 base64_encoded=true(编译输出可能含非 UTF-8)

实验模式

模式

语义

run_test

每题提交上限

iterative

联网做题环境:可用评测机对公开样例判题,据此迭代

允许(第 10 次起软提醒)

3

one-shot

竞赛环境:评测机只运行最终提交

禁止(硬拒绝)

1

两种模式下模型都可以在本地工作区自行编译、运行与构造边界数据;区别只在于是否允许调用评测机自测。 详细的被测模型提示词见 docs/agent-prompt.md

统计与取数

每次工具调用都会追加写入 runs/<run_id>.jsonl(每行一条 JSON),关键字段:

tsrun_idmodel_namemodetoolproblem_idargs_digestverdictscoresubmit_counttest_summaryelapsed_seconds,以及按工具附加的 sample_norun_test_countpendingsubmission_idmachine_failureie_pointsfirst_error_type 等。

一键生成报告:

.\.venv\Scripts\python.exe analyze_runs.py                 # 默认聚合 mcp-server/runs/
.\.venv\Scripts\python.exe analyze_runs.py --runs <dir>    # 指定目录

输出 8 段:[1] 各题提交分布 · [2] 模型×模式的题级最终结果 · [3] final_status 分布 · [4] first_error_type 分布 · [5] 单题 run_test 次数分布 · [6] 模型×模式汇总 · [7] run 明细 · [8] 每题完成用时(首次 init → 最终提交)。

口径说明:通过率与分数按「题级最终结果」= 该 (run, 题) 最后一次 submit_code 计算; AC 判定会结合 score 与失败摘要校准,不单纯信任记录中的 verdict 字段。

如何新增或调整一道题

  1. 题面:把 Markdown 放到 statement/<id>.md

  2. 公开样例:打包为 statement/<id>.zip,内含 <id>1.in / <id>1.ans …(可带子目录,服务端会展平)。

  3. 隐藏数据:放到 <data_dir>(默认仓库内的 data/)下的 <id>/ 目录,命名 <id>1.in / <id>1.ans …, 编号从 1 连续到 test_point_count

  4. 题库元数据:在 problems.json 增加一个键(键名即 problem_id,需与上面文件名前缀一致), 字段含义见 problems.example.json_readme

  5. 自检

    • 启动服务,确认无「样例缓存初始化失败」告警;

    • list_problems() 能看到新题;

    • init_problem("<id>") 后工作区有 题面.md(含注入头部)与 sample/

    • 用一份正确解法 submit_code 应为满分,用一份错误解法应得到预期失败类型。

调整时限/内存只需改 problems.json 对应字段;调整语言或编译选项改 config.jsonlanguages (按题覆盖用 problems.jsoncompiler_options)。

常见问题

  • 客户端里看不到工具 / 启动即报错:确认 command 指向装了依赖的 venv 解释器(系统 Python 可能缺少 fastmcp);查看服务端 stderr 有无 [fatal][warn] 输出。

  • [fatal] 未找到题库文件:从 problems.example.json 复制出 problems.json,或用 JUDGE0_PROBLEMS_FILE 指定路径。

  • init_problem 报「未配置 AGENT_WORKSPACE」:在 MCP 配置的 env 中设置该变量。

  • 样例缓存初始化失败:检查 statement/ 下的 .zip 是否完整(坏包会在启动时告警)。

  • 所有提交返回 Internal Error(13):Judge0 沙箱与运行环境不兼容(WSL2 + cgroup v2 常见), 详见 judge0-v1.13.1/README.md 的处理办法。

  • localhost:2358 突然不可达(WSL2 端口转发失效):服务端会自动尝试 WSL 的真实 IP (由 judge0.wsl_fallback 控制),日志会打印切换后的地址。

  • 清空某次实验记录:删除 runs/<run_id>.jsonl 即可。

许可证

本仓库以 GNU General Public License v3.0(GPL-3.0) 发布,完整条款见 LICENSE

之所以采用 GPL-3.0:本仓库的 judge0-v1.13.1/docker-compose.ymljudge0-v1.13.1/judge0.conf.example 改编自 Judge0 的同名文件 (Judge0 以 GPL-3.0 发布,Copyright (C) 2016-2020 Herman Zvonimir Došilović)。GPL-3.0 要求分发 修改版本时标注修改并整体以同一许可授权,故本仓库整体适用 GPL-3.0。

第三方组件

组件

许可

在本仓库中的形态

Judge0

GPL-3.0

以 Docker 镜像方式运行(源码不在本仓库);docker-compose.ymljudge0.conf.example 为其文件的修改版(修改声明见文件头部与 judge0-v1.13.1/README.md

FastMCP

Apache-2.0

Python 依赖(见 requirements.txt

HTTPX

BSD-3-Clause

Python 依赖(见 requirements.txt

题面 / 样例 / 测试数据

归原始出题方所有

不包含在本仓库中(由 .gitignore 排除,属本地材料)

免责

本程序不提供任何担保,详见 GPL-3.0 第 15 条(Disclaimer of Warranty)与第 16 条 (Limitation of Liability)。

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A Model Context Protocol (MCP) server that enables LLMs to run ANY code safely in isolated Docker containers.
    121
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    MCP server for Codabench REST API that enables AI agents to drive a full participant ML-benchmark workflow: discover competitions, download data, submit, poll, and read leaderboards.
    16
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    An MCP server that lets AI models run code in 31 languages, evaluate symbolic math and logic problems, and measure complexity—exposed as 48 tools for execution, session management, translation, optimization, and more.
    2
    49
    3
    Apache 2.0