{
  "markdown": "# Python Code Validator\n\n**An MCP server that validates, repairs and runs Python against the examples it\nis supposed to satisfy — `validate_python`, `repair_python` and `execute_python`\nover HTTP at `https://api.statemind.ai/mcp`, with a free key and no account.**\n\nA hosted service that proves AI-generated Python does what you asked. State the\nintent — assertions or doctest lines — and the code is run against it inside a\ncontainer with no network and a read-only filesystem; a fix comes back only when\nevery example passes. On the QuixBugs defects that is 41% repaired and 77%\nrefused as not doing what they say, with no false alarms on the corrected\nprograms — where `ruff` and `mypy` flag the defect in none of them\n([the numbers](BENCHMARK.md)).\n\nThe checks that need no intent come with it: syntax and lint diagnostics, an AST\nsecurity policy that also catches calls hidden behind dynamic imports and runtime\nattribute lookups, a bandit pass, a credential scan and deterministic repair —\none verdict with a score. Asking the same question twice inside ten minutes is\nanswered from the first answer and costs nothing (`x-msvc-repeat: 1`).\n\nThis repository holds the client side: the MCP configuration, the CI script and\nthe pre-commit hook. The service itself runs at `https://api.statemind.ai`, so\nthere is nothing to install or host.\n\n## A key, without an account\n\n```bash\ncurl -s -X POST https://api.statemind.ai/v1/keys\n# {\"api_key\": \"msvc_free_…\", \"tier\": \"free\", \"calls_per_day\": 25, \"modes\": [\"static\"]}\n```\n\n25 static checks a day, metered per UTC day, and a few keys per address: enough\nto try it and to run it over a small project, not a supply. Every answer carries\nthe state of the allowance (`x-quota-remaining`, `x-quota-reset`), so a client\ncan back off before it is cut off.\n\n## MCP\n\nRegistered in the official MCP registry as\n`ai.statemind/python-code-validator`, a name verified against the domain that\nserves it rather than a GitHub account. Any MCP client adds it with one\nblock:\n\n```json\n{\n  \"mcpServers\": {\n    \"python-code-validator\": {\n      \"type\": \"http\",\n      \"url\": \"https://api.statemind.ai/mcp\",\n      \"headers\": { \"Authorization\": \"Bearer msvc_free_…\" }\n    }\n  }\n}\n```\n\n- Claude Code: `claude mcp add --transport http python-code-validator https://api.statemind.ai/mcp --header \"Authorization: Bearer msvc_free_…\"`\n- Cursor: `~/.cursor/mcp.json`, same block.\n- VS Code / Copilot: `.vscode/mcp.json` under `\"servers\"`.\n\nA client that only launches a command uses the stdio bridge in this repository\ninstead, which forwards the same tool over HTTPS:\n\n```json\n{\n  \"mcpServers\": {\n    \"python-code-validator\": {\n      \"command\": \"python3\",\n      \"args\": [\"/path/to/python-code-validator/mcp_stdio.py\"]\n    }\n  }\n}\n```\n\nOr as a container, which the `Dockerfile` here builds:\n\n```bash\ndocker build -t python-code-validator .\ndocker run -i --rm -e VALIDATOR_API_KEY python-code-validator\n```\n\nGemini CLI installs the same bridge as an extension, with the instruction file\nthat makes it get used:\n\n```bash\ngemini extensions install jkanselaar/python-code-validator\n```\n\nThree tools, named after what they do to the code:\n\n| tool | runs the code | key |\n| --- | --- | --- |\n| `validate_python` | no | free |\n| `repair_python` — also returns `fixed_code` | no | paid |\n| `execute_python` — also runs it in a sandbox | **yes** | paid |\n\nThe old single `python_code_validator` tool, with its `mode` argument, still\nanswers for clients that already configured it, but is no longer listed.\n\n## Saying what the code was supposed to do\n\nEvery check above passes on a function that computes the wrong answer. The one\nthing that catches it is the intent, and the agent that asked for the code is\nthe only one who has it — so pass it along:\n\n```json\n{\"code\": \"def bitcount(n): …\", \"mode\": \"execute\",\n \"options\": {\"examples\": \"assert bitcount(127) == 7\"}}\n```\n\nDoctest lines (`>>> bitcount(127)` then `7`) work the same way, as do `>>>`\nexamples already written in the source. `execute_python` runs them in the\nsandbox: one that does not hold is a `python:example-mismatch` error, and the\nrepair search returns a fix only when every example passes. On the QuixBugs\ndefect set — real bugs, hidden test inputs deciding correctness — that repairs\n41% and refuses 77% as not doing what they say, with no false alarms on the\ncorrected programs.\n\nRepeating a call costs nothing: the same key asking the same question — same\nmode, same code, same examples — is answered from the answer it already got,\nmarked `x-msvc-repeat: 1`, so an agent that checks its work at every step is not\nbilled for verdicts that cannot have changed.\n\n## Claude Code plugin\n\nAn instruction can be ignored; a hook cannot. The plugin checks every Python\nfile Claude Code writes or edits, in the turn it was written, and hands the\nerrors back to the model instead of to you:\n\n```\n/plugin marketplace add jkanselaar/python-code-validator\n/plugin install python-code-validator@statemind\n```\n\nNothing to configure: it mints and keeps its own free key on first use. A file\nthat comes back accepted is silent, a rejected one stops the turn with the\noffending lines named, and an identical file is not asked about twice. It never\nends a session over its own trouble — an unreachable service or a spent\nallowance lets the turn continue, and the allowance says how to raise it.\n\nSet `VALIDATOR_API_KEY` to use a paid key instead of the free tier, and\n`VALIDATOR_URL` to point at your own deployment. The plugin also carries the\n`validate-python` skill, for the part a hook cannot do: stating the intent as\nexamples and running the code against them.\n\n## Cursor hook\n\nThe same script, wired to Cursor's `postToolUse`, where the verdict comes back\nas context on the conversation instead of as an exit code:\n\n```bash\nmkdir -p .cursor/hooks\nbase=https://raw.githubusercontent.com/jkanselaar/python-code-validator/main\ncurl -sf $base/plugin/hooks/validate_written.py -o .cursor/hooks/validate_written.py\ncurl -sf $base/cursor/hooks.json -o .cursor/hooks.json\n```\n\nProject hooks run from the project root, which is why the command in\n[`cursor/hooks.json`](cursor/hooks.json) is a path relative to it. For a hook\nthat applies to every project instead, put the script in `~/.cursor/hooks/` and\nthe same block in `~/.cursor/hooks.json` with the command\n`python3 ./hooks/validate_written.py --cursor`.\n\n## Making the agent use it\n\nConfiguring the server is not what gets it called: the instruction file is.\n[`AGENTS.md`](AGENTS.md) in this repository is that text, written to be dropped\ninto any project under whichever name the client reads:\n\n```bash\nmkdir -p .github\ncurl -sf https://raw.githubusercontent.com/jkanselaar/python-code-validator/main/AGENTS.md \\\n  | tee AGENTS.md CLAUDE.md GEMINI.md .github/copilot-instructions.md >/dev/null\n```\n\nCursor reads rules with front matter instead, so that one is a separate file —\ncopy [`.cursor/rules/python-code-validator.mdc`](.cursor/rules/python-code-validator.mdc)\ninto `.cursor/rules/` of the project.\n\nThe short version, if you would rather add a line to instructions you already\nhave:\n\n> Write what the code should do as `assert` examples before writing the code,\n> and pass them in `options.examples`. Call `validate_python` after every edit\n> and `execute_python` once a function is finished, not again until what it\n> does has changed. When a call returns `fixed_code`, take it — the service ran\n> it against your examples. Do not present code that came back `valid: false`.\n\n## CI\n\nThe service hands out the client, so a workflow needs no checkout of this\nrepository and no secret:\n\n```yaml\n- run: |\n    curl -sf https://api.statemind.ai/v1/client -o validate.py\n    python3 validate.py --changed-against \"origin/${{ github.base_ref }}\"\n```\n\nOr as an action, from the Marketplace:\n\n```yaml\npermissions:\n  contents: read\n  pull-requests: write   # so the run can comment its result on the pull request\nsteps:\n  - uses: jkanselaar/python-code-validator@v1.22.0\n    with:\n      api-key: ${{ secrets.VALIDATOR_API_KEY }}   # optional; free tier without it\n```\n\nThe changed Python is validated and offending lines are annotated on the diff,\nfailing the job on syntax errors and unsafe patterns. Files the service refuses\noutright (over its 200 kB limit) are skipped with a warning rather than failing\nthe run.\n\nThe run also leaves one comment on the pull request, edited in place on later\npushes rather than repeated: what was accepted, what was repaired and how much of\nthe day's allowance is left. Without `pull-requests: write` nothing is written\nand the job is unaffected; `comment: \"false\"` turns it off.\n\nOn the free tier the action keeps its key in the workflow cache, one per\nrepository per day, so the allowance belongs to the repository rather than to the\nrun. With `api-key` set the cache is skipped.\n\n## Pre-commit\n\n```yaml\nrepos:\n  - repo: https://github.com/jkanselaar/python-code-validator\n    rev: v1.22.0\n    hooks:\n      - id: python-code-validator\n```\n\n## The client itself\n\n`validate.py` is standard library only, so it also works as `python\nvalidate.py file.py` in a Makefile, a git hook or a container:\n\n```\n$ python3 validate.py service.py\n::error file=service.py,line=88,title=SyntaxError::invalid syntax\nFAIL service.py score=0.66\n\n0/1 files accepted\n```\n\n`VALIDATOR_API_KEY` is used when set; otherwise the client mints a free key —\nkeeping it in `VALIDATOR_KEY_FILE` when that names a path, which is how a series\nof runs shares one allowance. `VALIDATOR_URL` points it at another deployment.\n`VALIDATOR_SOURCE` names the caller, which is only ever counted: a run inside a\nworkflow says `github-action` by itself.\n\n## The badge\n\nA repository whose Python is checked on every pull request can say so:\n\n```markdown\n[![Python validated](https://img.shields.io/badge/python-validated-2ea44f?logo=python&logoColor=white)](https://api.statemind.ai/?src=badge)\n```\n\n[![Python validated](https://img.shields.io/badge/python-validated-2ea44f?logo=python&logoColor=white)](https://api.statemind.ai/?src=badge)\n\n## HTTP\n\n```bash\ncurl -s https://api.statemind.ai/v1/validate \\\n  -H \"Authorization: Bearer $VALIDATOR_API_KEY\" \\\n  -H 'content-type: application/json' \\\n  -d '{\"code\": \"def f(:\\n    pass\\n\", \"mode\": \"static\"}'\n```\n\n`mode` is `static`, `repair` or `execute`; `repair` and `execute` need a\nconfigured key. Submitted code is not logged.\n\nA refused call says what to do about it, so a caller with no operator to ask can\nresolve it itself:\n\n```json\n{\"error\": \"payment_required\",\n \"remedy\": {\"action\": \"upgrade_key\", \"hint\": \"A free key covers static only. …\"}}\n```\n\n## Paying for calls\n\nA free key covers 25 static checks a day, and one address gets a few keys a day,\nso the allowance is a trial rather than a supply. Beyond it a key carries\ncredits: a static check costs 1, a repair 3 and a sandboxed run 10, and an\nidentical call repeated within ten minutes is answered from the first one for\nfree.\n\nCredits are bought with a card, without an invoice or anyone to ask:\n\n```bash\ncurl -s -X POST https://api.statemind.ai/v1/keys/checkout \\\n  -H 'content-type: application/json' \\\n  -d '{\"api_key\": \"'\"$VALIDATOR_API_KEY\"'\", \"credits\": 500}'\n```\n\nThat answers with a Stripe Checkout page; the credits are on the key seconds\nafter the card clears (500 credits is €10). An agent with a Gnosis wallet can\ninstead pay in xDAI without a browser — `GET /v1/pricing` states both routes.\n\n## Examples\n\n[`examples/`](examples/) holds three files and the client to send them with: one\nthat passes every check and still returns the wrong number, one the security\npolicy refuses, and one that comes back accepted from the sandbox.\n\n## Licence\n\nMIT.\n",
  "bytes": 11683,
  "sha": "6e3fbd99d4e3873843a4403a20043fee5db15df19343f432841d462f71efe481",
  "repo_slug": "jkanselaar/python-code-validator",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_ai_statemind_python_code_validator_d1cf6536/readme"
}