Python Code Validator
This server validates Python code through static and security analyses, with optional repair and execution (both require a paid key).
Validate: Syntax & lint analysis, AST security scan (including dynamic imports and runtime attribute lookups), Bandit security pass, credential scan.
Repair (paid key): Deterministic repair returns fixed code.
Execute (paid key): Sandboxed execution to observe behavior.
Verdict: Scored verdict for code quality/safety.
Integration: MCP (HTTP/stdio), HTTP API, CI/CD, pre-commit hooks, CLI.
Extras: Filename-aware diagnostics, large file support (up to 200,000 characters), privacy-respecting (code not logged).
Provides a GitHub Action and CI script to validate Python files in workflows, annotating offending lines on the diff and failing on errors.
Provides a pre-commit hook to run Python code validation before each commit.
Provides syntax and lint diagnostics, AST security policy checks, bandit pass, credential scanning, and deterministic repair for Python code.
Python Code Validator
An MCP server that validates, repairs and runs Python against the examples it
is supposed to satisfy — validate_python, repair_python and execute_python
over HTTP at https://api.statemind.ai/mcp, with a free key and no account.
A hosted service that proves AI-generated Python does what you asked. State the
intent — assertions or doctest lines — and the code is run against it inside a
container with no network and a read-only filesystem; a fix comes back only when
every example passes. On the QuixBugs defects that is 41% repaired and 77%
refused as not doing what they say, with no false alarms on the corrected
programs — where ruff and mypy flag the defect in none of them
(the numbers).
The checks that need no intent come with it: syntax and lint diagnostics, an AST
security policy that also catches calls hidden behind dynamic imports and runtime
attribute lookups, a bandit pass, a credential scan and deterministic repair —
one verdict with a score. Asking the same question twice inside ten minutes is
answered from the first answer and costs nothing (x-msvc-repeat: 1).
This repository holds the client side: the MCP configuration, the CI script and
the pre-commit hook. The service itself runs at https://api.statemind.ai, so
there is nothing to install or host.
A key, without an account
curl -s -X POST https://api.statemind.ai/v1/keys
# {"api_key": "msvc_free_…", "tier": "free", "calls_per_day": 25, "modes": ["static"]}25 static checks a day, metered per UTC day, and a few keys per address: enough
to try it and to run it over a small project, not a supply. Every answer carries
the state of the allowance (x-quota-remaining, x-quota-reset), so a client
can back off before it is cut off.
Related MCP server: code-quality-mcp
MCP
Registered in the official MCP registry as
ai.statemind/python-code-validator, a name verified against the domain that
serves it rather than a GitHub account. Any MCP client adds it with one
block:
{
"mcpServers": {
"python-code-validator": {
"type": "http",
"url": "https://api.statemind.ai/mcp",
"headers": { "Authorization": "Bearer msvc_free_…" }
}
}
}Claude Code:
claude mcp add --transport http python-code-validator https://api.statemind.ai/mcp --header "Authorization: Bearer msvc_free_…"Cursor:
~/.cursor/mcp.json, same block.VS Code / Copilot:
.vscode/mcp.jsonunder"servers".
A client that only launches a command uses the stdio bridge in this repository instead, which forwards the same tool over HTTPS:
{
"mcpServers": {
"python-code-validator": {
"command": "python3",
"args": ["/path/to/python-code-validator/mcp_stdio.py"]
}
}
}Or as a container, which the Dockerfile here builds:
docker build -t python-code-validator .
docker run -i --rm -e VALIDATOR_API_KEY python-code-validatorGemini CLI installs the same bridge as an extension, with the instruction file that makes it get used:
gemini extensions install jkanselaar/python-code-validatorThree tools, named after what they do to the code:
tool | runs the code | key |
| no | free |
| no | paid |
| yes | paid |
The old single python_code_validator tool, with its mode argument, still
answers for clients that already configured it, but is no longer listed.
Saying what the code was supposed to do
Every check above passes on a function that computes the wrong answer. The one thing that catches it is the intent, and the agent that asked for the code is the only one who has it — so pass it along:
{"code": "def bitcount(n): …", "mode": "execute",
"options": {"examples": "assert bitcount(127) == 7"}}Doctest lines (>>> bitcount(127) then 7) work the same way, as do >>>
examples already written in the source. execute_python runs them in the
sandbox: one that does not hold is a python:example-mismatch error, and the
repair search returns a fix only when every example passes. On the QuixBugs
defect set — real bugs, hidden test inputs deciding correctness — that repairs
41% and refuses 77% as not doing what they say, with no false alarms on the
corrected programs.
Repeating a call costs nothing: the same key asking the same question — same
mode, same code, same examples — is answered from the answer it already got,
marked x-msvc-repeat: 1, so an agent that checks its work at every step is not
billed for verdicts that cannot have changed.
Claude Code plugin
An instruction can be ignored; a hook cannot. The plugin checks every Python file Claude Code writes or edits, in the turn it was written, and hands the errors back to the model instead of to you:
/plugin marketplace add jkanselaar/python-code-validator
/plugin install python-code-validator@statemindNothing to configure: it mints and keeps its own free key on first use. A file that comes back accepted is silent, a rejected one stops the turn with the offending lines named, and an identical file is not asked about twice. It never ends a session over its own trouble — an unreachable service or a spent allowance lets the turn continue, and the allowance says how to raise it.
Set VALIDATOR_API_KEY to use a paid key instead of the free tier, and
VALIDATOR_URL to point at your own deployment. The plugin also carries the
validate-python skill, for the part a hook cannot do: stating the intent as
examples and running the code against them.
Cursor hook
The same script, wired to Cursor's postToolUse, where the verdict comes back
as context on the conversation instead of as an exit code:
mkdir -p .cursor/hooks
base=https://raw.githubusercontent.com/jkanselaar/python-code-validator/main
curl -sf $base/plugin/hooks/validate_written.py -o .cursor/hooks/validate_written.py
curl -sf $base/cursor/hooks.json -o .cursor/hooks.jsonProject hooks run from the project root, which is why the command in
cursor/hooks.json is a path relative to it. For a hook
that applies to every project instead, put the script in ~/.cursor/hooks/ and
the same block in ~/.cursor/hooks.json with the command
python3 ./hooks/validate_written.py --cursor.
Making the agent use it
Configuring the server is not what gets it called: the instruction file is.
AGENTS.md in this repository is that text, written to be dropped
into any project under whichever name the client reads:
mkdir -p .github
curl -sf https://raw.githubusercontent.com/jkanselaar/python-code-validator/main/AGENTS.md \
| tee AGENTS.md CLAUDE.md GEMINI.md .github/copilot-instructions.md >/dev/nullCursor reads rules with front matter instead, so that one is a separate file —
copy .cursor/rules/python-code-validator.mdc
into .cursor/rules/ of the project.
The short version, if you would rather add a line to instructions you already have:
Write what the code should do as
assertexamples before writing the code, and pass them inoptions.examples. Callvalidate_pythonafter every edit andexecute_pythononce a function is finished, not again until what it does has changed. When a call returnsfixed_code, take it — the service ran it against your examples. Do not present code that came backvalid: false.
CI
The service hands out the client, so a workflow needs no checkout of this repository and no secret:
- run: |
curl -sf https://api.statemind.ai/v1/client -o validate.py
python3 validate.py --changed-against "origin/${{ github.base_ref }}"Or as an action, from the Marketplace:
permissions:
contents: read
pull-requests: write # so the run can comment its result on the pull request
steps:
- uses: jkanselaar/python-code-validator@v1.22.0
with:
api-key: ${{ secrets.VALIDATOR_API_KEY }} # optional; free tier without itThe changed Python is validated and offending lines are annotated on the diff, failing the job on syntax errors and unsafe patterns. Files the service refuses outright (over its 200 kB limit) are skipped with a warning rather than failing the run.
The run also leaves one comment on the pull request, edited in place on later
pushes rather than repeated: what was accepted, what was repaired and how much of
the day's allowance is left. Without pull-requests: write nothing is written
and the job is unaffected; comment: "false" turns it off.
On the free tier the action keeps its key in the workflow cache, one per
repository per day, so the allowance belongs to the repository rather than to the
run. With api-key set the cache is skipped.
Pre-commit
repos:
- repo: https://github.com/jkanselaar/python-code-validator
rev: v1.22.0
hooks:
- id: python-code-validatorThe client itself
validate.py is standard library only, so it also works as python validate.py file.py in a Makefile, a git hook or a container:
$ python3 validate.py service.py
::error file=service.py,line=88,title=SyntaxError::invalid syntax
FAIL service.py score=0.66
0/1 files acceptedVALIDATOR_API_KEY is used when set; otherwise the client mints a free key —
keeping it in VALIDATOR_KEY_FILE when that names a path, which is how a series
of runs shares one allowance. VALIDATOR_URL points it at another deployment.
VALIDATOR_SOURCE names the caller, which is only ever counted: a run inside a
workflow says github-action by itself.
The badge
A repository whose Python is checked on every pull request can say so:
[](https://api.statemind.ai/?src=badge)HTTP
curl -s https://api.statemind.ai/v1/validate \
-H "Authorization: Bearer $VALIDATOR_API_KEY" \
-H 'content-type: application/json' \
-d '{"code": "def f(:\n pass\n", "mode": "static"}'mode is static, repair or execute; repair and execute need a
configured key. Submitted code is not logged.
A refused call says what to do about it, so a caller with no operator to ask can resolve it itself:
{"error": "payment_required",
"remedy": {"action": "upgrade_key", "hint": "A free key covers static only. …"}}Paying for calls
A free key covers 25 static checks a day, and one address gets a few keys a day, so the allowance is a trial rather than a supply. Beyond it a key carries credits: a static check costs 1, a repair 3 and a sandboxed run 10, and an identical call repeated within ten minutes is answered from the first one for free.
Credits are bought with a card, without an invoice or anyone to ask:
curl -s -X POST https://api.statemind.ai/v1/keys/checkout \
-H 'content-type: application/json' \
-d '{"api_key": "'"$VALIDATOR_API_KEY"'", "credits": 500}'That answers with a Stripe Checkout page; the credits are on the key seconds
after the card clears (500 credits is €10). An agent with a Gnosis wallet can
instead pay in xDAI without a browser — GET /v1/pricing states both routes.
Examples
examples/ holds three files and the client to send them with: one
that passes every check and still returns the wrong number, one the security
policy refuses, and one that comes back accepted from the sandbox.
Licence
MIT.
Available Tools
3 toolsexecute_pythonExecute PythonAIdempotentInspect
Everything repair does, and then RUNS the code in a throwaway container — no network, read-only filesystem, killed at options.timeout_s — reporting exit code, stdout and stderr. Any '>>>' examples in the code are run too, and one that does not print what it says is an error the other tools cannot see. This is a side effect: do not submit code you do not want executed. Use it when you need proof that the code runs, or that it does what it says. Alternatives: validate_python for the diagnosis and repair_python for the fix, neither of which runs anything. Auth: a key is required. This call needs a paid key and answers HTTP 402 without one. Credits are bought without an account, 10 per call: GET /v1/pricing says where to send the xDAI. Or pay for this one call with no key at all: call it without one and the result carries x402 payment requirements ($0.1 in USD Coin on eip155:8453); sign them and repeat the call with the payment in _meta['x402/payment']. Arguments: code: the whole file, 1..200000 bytes of UTF-8 measured after encoding (empty is refused with 400, larger with 413); a fragment is fine, but line and column numbers in the answer count from 1 in what you sent. language: must be 'python'; anything else is 400, and the field may be omitted. options.max_iterations (1..10, default 3) caps the fix/verify rounds: raise it for a file with several independent faults, leave it for a snippet. options.optimize (default false) additionally folds constants and drops dead code, and is only worth setting when you asked for a rewrite anyway. options.transpile_to (e.g. 'javascript') returns a translation of the repaired source in transpiled, not of what you sent. fixed_code is null when nothing could be proven safe to change, so treat null as 'no fix', not as an error. options.timeout_s (seconds, default 5) is the wall clock for the run; the schema allows up to 60 but this deployment caps it at 30 and refuses a larger value with 400. options.expected_output compares stdout byte for byte and adds an 'expected-output' diagnostic (valid=false) when it differs, which is how you ask for 'it did the right thing' rather than 'it ran'. options.examples is the same question for code with no output: pass what you asked for as doctest lines ('>>> total([1, 2])' then '3') or assertions ('assert total([1, 2]) == 3'), and each is run against the code -- one that does not hold is a 'python:example-mismatch' error, and repair looks for a single-token change that makes them all pass. Send it whenever you know what you asked for: without it, code that runs but returns the wrong answer looks perfect from here. The program that runs is the repaired one, so read fixed_code before you trust runtime.stdout, and it runs exactly once however many rounds the repair took. Returns valid, score 0..1, diagnostics (rule, message, line, column), security findings, fixes, fixed_code and runtime; see outputSchema. The code and its verdict are retained to improve the service.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | The source to check, as a whole file where possible: diagnostics carry the line and column of the text you send, and a fragment hides the imports and definitions the type check needs. A deployment may accept fewer bytes than the 200000 here. | |
| options | No | Tuning knobs. Most of them only take effect in the mode that does the corresponding work; see each field. | |
| language | No | The language of the code. A service that does not handle it refuses the request rather than guessing; the enum is shared across services, so it lists more than any one of them accepts. | python |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | |
| fixes | No | |
| score | Yes | |
| valid | Yes | |
| runtime | No | |
| security | No | |
| fixed_code | No | |
| transpiled | No | |
| diagnostics | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
It adds critical context beyond the annotations: the code is actually executed, so malicious or unwanted code is a side effect; the container is no-network, read-only, and killed at timeout; the repaired code is what runs; and data is retained to improve the service. It also discloses auth and x402 payment behavior. No explicit contradiction with the annotations exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long, but it is structured and front-loaded: it starts with what the tool does, then covers side effects, alternatives, auth, parameters, and returned values. The length is justified by the complexity of a side-effecting, execution tool with payment requirements and repair semantics, though some parameter details are summarized the schema already contains.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description, together with the output schema, provides everything needed to choose and call this tool correctly: behavioral constraints, alternatives, auth flow, argument semantics, edge cases like null fixed_code, and return shape. The agent is not left to guess or infer critical behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Even though schema description coverage is 100%, the description explains practical operational semantics: code is measured in encoded UTF-8 bytes, language is restricted to Python despite the schema enum, the deployment caps timeout_s at 30, and expected_output/examples are the mechanism for proving correctness rather than just execution. This guidance is not inferable from the schema alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a concrete verb and resource: run the submitted code in a throwaway container and report exit code, stdout, and stderr. It also orients the agent by explaining that the tool does everything repair_python does and then executes the code, which clearly separates it from validate_python and repair_python.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It tells the agent exactly when to choose this tool: when proof of execution is needed, such as 'that it runs or that it does what it says'. It explicitly names the alternative tools, validate_python and repair_python, and notes neither runs anything, which prevents selection mistakes.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
repair_pythonRepair PythonARead-onlyIdempotentInspect
Everything validation does, plus deterministic fixes: the corrected source comes back in fixed_code, and the original is kept whenever the fix cannot be proven safe. The code is still never run. Use it when validation failed and you want the fix rather than the diagnosis. Alternatives: validate_python when the diagnosis is enough; execute_python when the fix has to be proven to run. Auth: a key is required. This call needs a paid key and answers HTTP 402 without one. Credits are bought without an account, 3 per call: GET /v1/pricing says where to send the xDAI. Or pay for this one call with no key at all: call it without one and the result carries x402 payment requirements ($0.03 in USD Coin on eip155:8453); sign them and repeat the call with the payment in _meta['x402/payment']. Arguments: code: the whole file, 1..200000 bytes of UTF-8 measured after encoding (empty is refused with 400, larger with 413); a fragment is fine, but line and column numbers in the answer count from 1 in what you sent. language: must be 'python'; anything else is 400, and the field may be omitted. options.max_iterations (1..10, default 3) caps the fix/verify rounds: raise it for a file with several independent faults, leave it for a snippet. options.optimize (default false) additionally folds constants and drops dead code, and is only worth setting when you asked for a rewrite anyway. options.transpile_to (e.g. 'javascript') returns a translation of the repaired source in transpiled, not of what you sent. fixed_code is null when nothing could be proven safe to change, so treat null as 'no fix', not as an error. options.timeout_s, options.examples and options.expected_output do nothing here: nothing is run, so there is no clock, no stdout, and no way to check an example. Returns valid, score 0..1, diagnostics (rule, message, line, column), security findings, fixes, fixed_code and runtime; see outputSchema. The code and its verdict are retained to improve the service.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | The source to check, as a whole file where possible: diagnostics carry the line and column of the text you send, and a fragment hides the imports and definitions the type check needs. A deployment may accept fewer bytes than the 200000 here. | |
| options | No | Tuning knobs. Most of them only take effect in the mode that does the corresponding work; see each field. | |
| language | No | The language of the code. A service that does not handle it refuses the request rather than guessing; the enum is shared across services, so it lists more than any one of them accepts. | python |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | |
| fixes | No | |
| score | Yes | |
| valid | Yes | |
| runtime | No | |
| security | No | |
| fixed_code | No | |
| transpiled | No | |
| diagnostics | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds critical behavior beyond annotations: code is never run, fixes are only returned when provably safe, fixed_code is null when no fix is possible, and authentication/payment requirements are disclosed. It also states which options are ignored because nothing executes. Annotations already indicate read-only and non-destructive, and the description does not contradict them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but logically organized by sections (behavior, use cases, auth, arguments, returns). It front-loads the core distinction from siblings and then systematically covers constraints. It is somewhat verbose, especially around payment details, but every section contributes decision-relevant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The output schema exists, and the description still explains the null fixed_code semantics, return fields, auth failure behavior, and constraint enforcement. Nothing an agent needs to call this tool correctly appears to be missing, including what happens with unsupported options.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the description enriches every parameter: it details byte limits for code, explains that fragments shift line/column numbers, states language must be 'python' and other values elicit 400, and clarifies that options like timeout_s, examples, and expected_output have no effect in this mode. This goes far beyond raw schema fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: repair Python code, returning deterministic fixes in fixed_code and preserving the original when safety cannot be proven. It also explicitly contrasts itself with the sibling tools validate_python and execute_python, so an agent can distinguish it without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit selection criteria: use when validation failed and you want a fix, not just a diagnosis. It also names the alternatives ('validate_python when the diagnosis is enough; execute_python when the fix has to be proven to run').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_pythonValidate PythonARead-onlyIdempotentInspect
Check Python source without running it: parse, lint (ruff), type-check (mypy), AST security policy, credential scan. Safe on code you do not trust. Use it on every Python file you generated or edited, before writing it to disk. Alternatives: repair_python to get the corrected source instead of the diagnosis; execute_python to prove the code runs. Auth: a key is required. A free key covers this call, 25 per day, then HTTP 429; get one with POST /v1/keys. Credits are bought without an account, 1 per call: GET /v1/pricing says where to send the xDAI. Or pay for this one call with no key at all: call it without one and the result carries x402 payment requirements ($0.01 in USD Coin on eip155:8453); sign them and repeat the call with the payment in _meta['x402/payment']. Arguments: code: the whole file, 1..200000 bytes of UTF-8 measured after encoding (empty is refused with 400, larger with 413); a fragment is fine, but line and column numbers in the answer count from 1 in what you sent. language: must be 'python'; anything else is 400, and the field may be omitted. Of options only transpile_to (e.g. 'javascript', which returns a translated copy in transpiled) acts here; timeout_s, max_iterations, optimize, examples and expected_output need a pass that rewrites or runs the code, so send code alone. Ignored options are not refused, so a call that sets them looks like it worked; and code that does not parse is answered rather than refused: valid=false with the syntax error located, which is the point. Returns valid, score 0..1, diagnostics (rule, message, line, column), security findings, fixes, fixed_code and runtime; see outputSchema. The code and its verdict are retained to improve the service.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | The source to check, as a whole file where possible: diagnostics carry the line and column of the text you send, and a fragment hides the imports and definitions the type check needs. A deployment may accept fewer bytes than the 200000 here. | |
| options | No | Tuning knobs. Most of them only take effect in the mode that does the corresponding work; see each field. | |
| language | No | The language of the code. A service that does not handle it refuses the request rather than guessing; the enum is shared across services, so it lists more than any one of them accepts. | python |
Output Schema
| Name | Required | Description |
|---|---|---|
| meta | Yes | |
| fixes | No | |
| score | Yes | |
| valid | Yes | |
| runtime | No | |
| security | No | |
| fixed_code | No | |
| transpiled | No | |
| diagnostics | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Even though annotations already mark readOnlyHint=true and destructiveHint=false, the description goes far beyond them: it promises safety on untrusted code ('Safe on code you do not trust'), discloses that it never runs code, and highlights silent no-op options ('Ignored options are not refused, so a call that sets them looks like it worked'). It also reveals rate limits and auth behavior (HTTP 429, key requirement, x402 payment flow) and the fact that submitted code is retained to improve the service. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every sentence earns its place. It is clearly structured with labeled sections (Auth, Arguments, Returns) and front-loaded with the core purpose before diving into details. No filler or redundant repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description does not need to enumerate return fields in depth; it still gives a high-level list. It covers input constraints, authentication requirements, call-limits, error behaviors, sibling tool relations, and retention. An agent has everything necessary to call the tool safely and correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Even though the schema already covers parameters 100%, the description adds critical meaning: it notes empty/large code fails with HTTP 400/413, line/column numbers count from the submitted fragment, the language must be exactly 'python' despite the broad schema enum, and that only transpile_to among options actual effects in this static tool. It explains that other options are ignored rather than rejected, which is not communicated by the schema alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb and resource: 'Check Python source without running it' followed by an explicit checklist (parse, lint/ruff, type-check/mypy, AST security policy, credential scan). It explicitly distinguishes the tool from its siblings: 'repair_python to get the corrected source instead of the diagnosis; execute_python to prove the code runs.' No ambiguity remains about what this tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states exactly when to use this tool ('Use it on every Python file you generated or edited, before writing it to disk') and clearly names alternatives and their purpose. The when-not-to-use is implicit but clear: if you need a corrected file, use repair_python; if you need runtime proof, use execute_python. This is explicit enough to route an agent correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
3 tool updates
v1.17.1- Changed
execute_python1 field changed- added
Input schema / $defs / Options / properties / examplesAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "What the code is supposed to do, as doctest lines ('>>> f(2)' on one line, '4' on the next) or as plain assertions ('assert f(2) == 4'). In execute mode they are run in the sandbox: an example that does not hold is a 'python:example-mismatch' error and makes the response invalid, and repair searches for a single-token change that makes every one of them pass. This is the only way the service can tell code that runs from code that is right, so send it whenever you know what you asked for. Examples already written in the code ('>>> ' in any string) are used the same way without this option. Ignored in the other modes, which run nothing.", + "title": "Examples" +}
- Changed
repair_python1 field changed- added
Input schema / $defs / Options / properties / examplesAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "What the code is supposed to do, as doctest lines ('>>> f(2)' on one line, '4' on the next) or as plain assertions ('assert f(2) == 4'). In execute mode they are run in the sandbox: an example that does not hold is a 'python:example-mismatch' error and makes the response invalid, and repair searches for a single-token change that makes every one of them pass. This is the only way the service can tell code that runs from code that is right, so send it whenever you know what you asked for. Examples already written in the code ('>>> ' in any string) are used the same way without this option. Ignored in the other modes, which run nothing.", + "title": "Examples" +}
- Changed
validate_python1 field changed- added
Input schema / $defs / Options / properties / examplesAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "What the code is supposed to do, as doctest lines ('>>> f(2)' on one line, '4' on the next) or as plain assertions ('assert f(2) == 4'). In execute mode they are run in the sandbox: an example that does not hold is a 'python:example-mismatch' error and makes the response invalid, and repair searches for a single-token change that makes every one of them pass. This is the only way the service can tell code that runs from code that is right, so send it whenever you know what you asked for. Examples already written in the code ('>>> ' in any string) are used the same way without this option. Ignored in the other modes, which run nothing.", + "title": "Examples" +}
4 tool updates
v1.6.4- Added
execute_python - Removed
python_code_validator - Added
repair_python - Added
validate_python
1 tool update
v1.1.1- Changed
python_code_validator5 fields changed- changed
Input schema / properties / code / descriptionPrevious value: -"The Python source to validate."New value: +"The Python source to validate. A whole module, not a fragment." - removed
Input schema / properties / filenameRemoved value: -{ - "description": "Name to report diagnostics against.", - "type": "string" -} - changed
Input schema / properties / mode / descriptionPrevious value: -"static analyses only; repair also returns fixed code; execute runs it in a sandbox. repair and execute need a paid key."New value: +"static analyses only and is free; repair also returns fixed code; execute runs it in a sandbox. repair and execute need a paid key." - added
Input schema / properties / optionsAdded value: +{ + "description": "Tuning knobs; timeout_s (1-60) bounds execute mode.", + "properties": { + "timeout_s": { + "maximum": 60, + "minimum": 1, + "type": "number" + } + }, + "type": "object" +} - changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "diagnostics": { + "description": "Correctness problems, each with rule, message, line and column.", + "items": { + "type": "object" + }, + "type": "array" + }, + "fixed_code": { + "description": "Repaired source, only in repair and execute mode.", + "type": [ + "string", + "null" + ] + }, + "fixes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "meta": { + "type": "object" + }, + "runtime": { + "description": "Sandbox result, only in execute mode.", + "type": "object" + }, + "score": { + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "security": { + "items": { + "type": "object" + }, + "type": "array" + }, + "valid": { + "description": "False when anything is an error.", + "type": "boolean" + } + }, + "required": [ + "valid", + "score", + "diagnostics", + "security", + "meta" + ], + "type": "object" +}
1 tool update
v1.0.0- First observed
python_code_validator
TDQS
Each tool is clearly distinct: validate_python diagnoses without running, repair_python additionally fixes, and execute_python additionally runs the code. The layering is explicit, and cross-references in the descriptions make the relationship unambiguous. No two tools appear to serve the same purpose.
All tool names follow the verb_python pattern exactly: validate_python, repair_python, execute_python. Naming is consistent, predictable, and clearly reflects each tool's function.
Three tools cover the full validation-to-execution pipeline without bloat. Each tool represents a distinct stage of the workflow, and the count is well-scoped for the server's stated purpose.
The tool set provides a complete lifecycle for Python code handling: diagnose (validate), fix (repair), and prove (execute). No obvious gaps exist; even transpile and security scanning are embedded in the pipeline. The options for examples and expected_output also address behavioral verification.
Maintenance
Related MCP Connectors
Deterministic validation for AI-generated artifacts: JSON Schema, OpenAPI response, SQL syntax.
Security + bug + perf + refactor audit for Python. Returns 0-10 score + MD report.
Pre-commit code quality guardian. Detects semantic drift in AI-generated code.
Deterministic AI code review, with an audit record. Governance inside the agent loop.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAutomatically detects security vulnerabilities in AI-generated code, scanning for hardcoded secrets, injection flaws, XSS, weak cryptography, authentication issues, path traversal, and vulnerable dependencies across JavaScript, Python, Java, and Go.102MIT
- FlicenseNot gradedqualityDmaintenanceProvides deterministic Python code quality analysis using flake8, mypy, McCabe, and vulture, enabling LLMs to access real linting and type checking results.1-
- AlicenseNot gradedqualityDmaintenanceDeterministic JSON validation and repair for AI agents. Validates, repairs, schema-checks, and diffs JSON so long-running agents don't corrupt their session state with malformed writes.MIT
- AlicenseNot gradedqualityDmaintenanceValidates AI-generated code against actual codebases to catch hallucinations, dead code, and API mismatches before runtime.241MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/jkanselaar/python-code-validator'
If you have feedback or need assistance with the MCP directory API, please join our Discord server