pyxel-mcp
pyxel-mcp lets AI agents drive Pyxel games headlessly and inspect the results with screenshots, pixel grids, state, audio, and diffs.
Run a Pyxel script headlessly for a frame budget, with scheduled button/axis/mouse inputs, random seeding, a stop condition (
until), and timeouts/stall detection.Capture snapshots at specific frames or at the end: game state attributes, screen images (PNG, optionally inline as image content), pixel grids, and video (GIF/MP4).
Validate Pyxel scripts for syntax and recognizable Pyxel patterns without executing them.
Get environment info: installed versions, paths, bundled examples, and Pyxel resource URIs.
Read palette colors and which palette indices are used by image banks.
Read image-bank regions as pixel arrays and optionally render them to PNG inline.
Read tilemaps: tile coordinates, usage counts, bounds, source bank, and optional rendered output.
Render sound or music slots to WAV and get measurable audio data like duration, sample rate, peak amplitude, and notes.
Compare two PNG frames pixel by pixel to report changed region, changed pixel count, ratio, and whether they are identical.
Enables AI to autonomously run, verify, and iterate on retro game programs created with the Pyxel engine, providing tools for Python script validation, state inspection, and visual/audio analysis.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pyxel-mcpRun main.py and capture a screenshot to verify the game visuals"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
pyxel-mcp
Let AI agents play, watch, and measure Pyxel games. pyxel-mcp is an MCP server that runs a Pyxel script headlessly, feeds it scheduled input, stops when a condition holds, and hands back the facts: screenshots, pixel grids, game state, assets, audio, and frame diffs.
Why
An agent can write a Pyxel game in seconds, but it cannot open a window, press the arrow keys, or look at the screen. Editor-bound engines solve this with MCP servers that live inside the editor. Pyxel has no editor process to attach to, so pyxel-mcp drives the game itself:
Headless execution. Every call runs the script in a fresh subprocess with SDL dummy drivers and a frame budget. Set
random_seedto seed Python'srandommodule and Pyxel's random generator. Other randomness, timing, and external state can still affect the frames.Input as data. Buttons, axes, and mouse position are scheduled per frame, so a playtest is a JSON document the agent can rerun and extend.
Stop on the event, not the clock.
until="score >= 1"ends the run at the first frame where a game attribute holds, and"frame": "end"snapshots capture that moment.Facts, not scores. Tools report pixels, values, and measurements. Deciding whether the game is good stays with the agent and the person asking for it.
See the frame in the result.
inline: truereturns a PNG as MCP image content, so the model looks at the screen without a second file read.
Related MCP server: Aseprite MCP
Install
Register the stdio server with your client:
claude mcp add --scope user pyxel -- uvx pyxel-mcpcodex mcp add pyxel -- uvx pyxel-mcpgemini mcp add pyxel uvx pyxel-mcpFor Cursor (~/.cursor/mcp.json), a project-scoped Claude Code .mcp.json, or any other client that reads the common JSON format, add:
{
"mcpServers": {
"pyxel": {
"command": "uvx",
"args": ["pyxel-mcp"]
}
}
}VS Code uses .vscode/mcp.json with a top-level servers key and "type": "stdio"; Codex CLI can also be configured in ~/.codex/config.toml as [mcp_servers.pyxel]. Run uvx pyxel-mcp install to print every variant.
Claude Code users can instead install the pyxel-skill plugin, which registers this server together with the skill that teaches agents how to use it:
claude plugin marketplace add kitao/pyxel-skill && claude plugin install pyxel@pyxel-skillRestart the client after changing its configuration. The server writes this diagnostic to stderr:
[pyxel-mcp] starting - 8 toolsPython 3.11+ is required, and Pyxel >= 2.9.6 is installed as a dependency. Script tools execute local Python in subprocesses to isolate Pyxel state, but they do not sandbox untrusted code. See SECURITY.md.
How an agent uses it
flowchart LR
W["Write or edit<br>game.py"] --> V["validate"]
V --> R["run<br>inputs · until · snapshots"]
R --> O{"Inspect facts<br>state · pixels · log"}
O -- "defect" --> W
O -- "looks right" --> A["read_image · read_tilemap<br>read_audio · diff_frames"]
A --> D["Report evidence"]The loop is deliberately small. The separate pyxel-skill project teaches agents when to use each tool and what counts as enough evidence; this package only supplies the observations.
Tools
Every script argument is a file path, not Python source. Relative asset paths inside the script resolve from the script's directory, as when running python game.py from that directory.
Tool | Returns |
| Syntax errors and recognizable Pyxel code patterns, without executing. |
| Headless frames, scheduled input, logs, and |
| Installed versions, paths, bundled examples, and resource URIs. |
| Palette colors and image-bank indices in use. |
| Image-bank pixels and an optional PNG render. |
| Tile coordinates, source bank, usage counts, bounds, and an optional render. |
| A rendered sound or music WAV plus measurable audio data. |
| Pixel differences between two PNG files. |
All tools declare input and output schemas. Every result includes ok and errors.
Script tools observe the first pyxel.run() call while its enclosing resources
remain active. run drives the callbacks there; the asset readers inspect the
pre-loop state. pyxel.quit() ends a run normally and preserves completed
frames. Statements after pyxel.run() are not executed. Enclosing cleanup runs
after observation, and cleanup failures are reported with phase: "script_exit".
Stopping uses internal BaseException signals. Scripts or context-manager
cleanup that suppress these signals are unsupported and may execute post-run code.
Captured PNGs can travel inside the result: set inline: true on a screen_image snapshot, or inline=true on read_image and read_tilemap, and the PNG is returned as MCP image content next to the structured data. A single inline frame may omit its output path; the file is then written under the system temp directory and its path is still reported, so diff_frames and later comparisons keep working. At most 12 images are embedded per call.
Example
Hold right, jump at frame 25, stop as soon as the score changes, and look at that frame:
{
"script": "/absolute/path/game.py",
"frames": 600,
"random_seed": 7,
"inputs": [
{"frame": 0, "buttons": ["KEY_RIGHT"]},
{"frame": 25, "buttons": ["KEY_RIGHT", "KEY_SPACE"]},
{"frame": 26, "buttons": ["KEY_RIGHT"]}
],
"until": "score >= 1",
"snapshots": [
{"kind": "state", "frame": "end", "attrs": ["score", "player.x"]},
{"kind": "screen_image", "frame": "end", "scale": 3, "inline": true}
]
}The result reports until_met, the reached frame_count, the requested state values, the PNG path, and the PNG itself as image content. Artifact paths you choose must be absolute. Read log even when ok is true, and inspect captured images directly when appearance matters.
Resources
pyxel://run-snapshots-schema— completerun.snapshotsgrammar, including"end", ranges, andinline.pyxel://validation-patterns— categories reported byvalidate.pyxel://palette/default— default palette table.pyxel://examples/{name}— source for an example bundled with the installed Pyxel package; discover names withpyxel_info.
Update
uvx caches packages. Force a refresh with:
uvx --refresh-package pyxel-mcp pyxel-mcp installTroubleshooting
If tools do not appear, look for the
starting - 8 toolsdiagnostic and restart the client.If
runfails, inspecterrors,exit_status, andlog.If a script cannot find an asset, check the path relative to the script file, not to the client's working directory.
If a validation category is unfamiliar, read
pyxel://validation-patterns.
Related
Pyxel — the retro game engine this server observes.
pyxel-skill — the Agent Skill that turns these tools into a build-and-verify workflow.
CHANGELOG.md — what changed in each release.
MCP Registry
mcp-name: io.github.kitao/pyxel-mcp
License
MIT — see LICENSE.
Available Tools
8 toolsdiff_framesARead-onlyIdempotent
Compare two PNG frames pixel by pixel and return their changed region and ratio.
| Name | Required | Description | Default |
|---|---|---|---|
| frame_a | Yes | ||
| frame_b | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| ratio | No | |
| errors | Yes | |
| region | No | |
| size_a | No | |
| size_b | No | |
| warnings | No | |
| identical | No | |
| size_match | No | |
| total_pixels | No | |
| changed_pixels | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds behavioral detail: pixel-by-pixel comparison and the output of a changed region plus a ratio. This goes beyond the annotations without contradicting 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 a single, efficient sentence with no filler. It front-loads the core operation and the output, making it easy to scan and understand quickly.
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?
An output schema exists, so return values do not need to be described. However, the missing input format details and lack of guidance on edge cases like mismatched image sizes make the description incomplete for confident invocation. It is adequate but has a clear gap.
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?
The schema only defines two required strings with no format, and schema description coverage is 0%. The description identifies the parameters as 'PNG frames', which adds some meaning, but it does not clarify whether frame_a and frame_b are file paths, data URIs, raw byte strings, or something else. This leaves a critical ambiguity for the agent.
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 uses a specific verb ('Compare'), identifies the resource ('two PNG frames'), and states the result ('changed region and ratio'). This clearly distinguishes it from sibling tools like read_image or run, which perform different operations.
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?
The purpose implies when it should be used: whenever two PNG frames need to be compared. However, there is no explicit guidance about when to use this tool instead of alternatives, no exclusions, and no mention of prerequisites such as matching dimensions or format.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pyxel_infoARead-onlyIdempotent
Report installed versions, paths, examples, and Pyxel resource URIs.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| errors | Yes | |
| examples | No | |
| resources | No | |
| stubs_path | No | |
| pyxel_version | No | |
| python_version | No | |
| pyxel_mcp_version | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is fully covered. The description adds useful behavioral detail by specifying exactly what the tool reports, which is beyond what the empty input schema and annotations reveal.
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 a single sentence with the verb and key output categories front-loaded. Every word contributes meaning, and there is no redundancy or filler.
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?
For a zero-parameter, read-only, non-destructive tool with an output schema and strong annotations, the description is sufficient for an agent to select and invoke it correctly. The only minor gap is the lack of explicit guidance about when to prefer it over sibling tools, but this does not hinder correct invocation.
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?
The tool has zero parameters, so the baseline of 4 applies. There is nothing for the description to explain about parameters, and the description correctly focuses on the tool's output rather than input semantics.
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 uses a specific verb ('Report') and names an exact set of outputs: installed versions, paths, examples, and Pyxel resource URIs. This clearly distinguishes it from sibling read_* tools that target game assets such as palettes, images, tilemaps, and audio.
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?
There is no explicit when-to-use or when-not-to-use guidance or mention of alternatives. However, the tool's purpose is strongly implied by its name and content: use it to introspect the Pyxel environment rather than to execute or validate game resources. The guidance is implicit, not explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_audioA
Render one Pyxel sound or music slot to WAV and return measurable audio data. Notes describe tracker fields, not an MML or PCM transcription.
| Name | Required | Description | Default |
|---|---|---|---|
| script | Yes | ||
| target | Yes | ||
| output_path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| path | No | |
| notes | No | |
| errors | Yes | |
| channels | No | |
| warnings | No | |
| sample_rate | No | |
| peak_amplitude | No | |
| duration_seconds | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations provide only basic safety flags (readOnlyHint=false, destructiveHint=false), so the description carries the behavioral burden. It adds useful context about the output being WAV and measurable audio data, and clarifies that notes are tracker fields, but it does not disclose side effects such as whether output_path is overwritten or whether the operation has any state impact beyond file creation.
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?
Two front-loaded sentences with no filler. The first sentence states the core action and deliverable, and the second clears up a key interpretative trap without clutter.
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 three required parameters, zero schema descriptions, and minimal annotations, the description leaves critical invocation details unexplained, particularly the meaning of 'script' and 'output_path'. Even though an output schema exists, the input side is too under-specified for an agent to call this tool correctly without additional context.
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 description coverage is 0%, so the description must compensate, but it only hints at the target parameter via 'one Pyxel sound or music slot'. It gives no explanation for the required 'script' or 'output_path' parameters, leaving their roles and formats ambiguous.
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 names a specific verb and resource ('Render one Pyxel sound or music slot to WAV') and a clear deliverable ('return measurable audio data'), which distinguishes this audio-focused tool from siblings like read_image and read_tilemap. The clarifying clause about tracker fields further pins down its exact role.
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?
Usage is implied by the audio-specific resource, but the description never states when to choose this tool over alternatives, nor does it name any sibling or exclusion. It lacks explicit 'use when' guidance, so an agent must infer applicability from the tool name and purpose.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_imageA
Read palette-index pixels from a Pyxel image-bank region and optionally render it to PNG; inline=true returns the render as image content and makes render_path optional.
| Name | Required | Description | Default |
|---|---|---|---|
| h | No | ||
| w | No | ||
| x | No | ||
| y | No | ||
| image | Yes | ||
| inline | No | ||
| script | Yes | ||
| render_path | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| errors | Yes | |
| pixels | No | |
| region | No | |
| rendered | No | |
| bank_size | No | |
| color_count | No | |
| image_index | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses a non-read-only side effect (optional PNG rendering) and explains that inline=true returns image content, going beyond the sparse annotations. This is consistent with readOnlyHint=false because rendering is a write-capable path.
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?
One compact, front-loaded sentence that puts the core read action first and then adds the conditional rendering behavior. No filler or redundant restatement of the tool name.
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?
Covers the primary read/render flow and the inline behavior, and the output schema can handle return-value details. However, it does not explain the required script parameter or the coordinate-region semantics, so an agent must infer important calling details.
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?
Adds meaningful semantics for inline and render_path by explaining their relationship, but leaves the required script parameter and the coordinate parameters x/y/w/h unexplained. With 0% schema description coverage, this is a substantial gap.
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?
States a specific action: read palette-index pixels from a Pyxel image-bank region and optionally render to PNG. The resource ('image-bank region') and pixel-mode clearly distinguish it from sibling read tools like read_palette and read_tilemap.
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?
Provides a clear condition for inline mode and render_path optionality, but gives no guidance on when to choose read_image over alternatives such as read_palette or read_tilemap. Tool-selection context is only implied by the purpose rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_paletteC
Read the active Pyxel palette and the palette indices used by image banks.
| Name | Required | Description | Default |
|---|---|---|---|
| script | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| colors | No | |
| errors | Yes | |
| palette_size | No | |
| used_indices | No | |
| extended_palette | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description frames the operation as a read ('Read the active Pyxel palette'), but the annotations set readOnlyHint to false, which contradicts the clear read-only semantics of the description. It also sets idempotentHint to false for an operation that should be idempotent. This is an annotation contradiction, and the description adds no further behavioral context.
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 a single front-loaded sentence with no filler words; it names the action and the resource in the order an agent needs. It is concise without sacrificing the core object.
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?
Although the tool is simple and an output schema exists, the description omits the meaning of the required 'script' parameter and does not clarify the exact relationship between the active palette and image-bank indices. Combined with the misleading annotations, the description is incomplete for reliable invocation.
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?
The single required parameter 'script' has 0% schema description coverage, and the description does not mention or explain how 'script' relates to reading the palette. With no parameter details in the schema, the description fails to compensate.
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?
States a specific action ('Read') on a specific resource ('active Pyxel palette and the palette indices used by image banks'). This distinguishes it from sibling tools like read_image, read_tilemap, and read_audio, so an agent can identify the tool's scope.
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?
The description implies this tool is for retrieving palette data, but it does not explicitly state when to choose read_palette over read_image, read_tilemap, or read_audio, nor does it list exclusions or prerequisites such as needing a script.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_tilemapA
Read Pyxel tile coordinates, usage, bounds, source bank, and optional rendered output; inline=true returns the render as image content and makes render_path optional.
| Name | Required | Description | Default |
|---|---|---|---|
| inline | No | ||
| script | Yes | ||
| tilemap | Yes | ||
| render_path | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| size | No | |
| tiles | No | |
| usage | No | |
| errors | Yes | |
| imgsrc | No | |
| region | No | |
| rendered | No | |
| tilemap_index | No | |
| zero_tile_used | No | |
| zero_tile_nonempty | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With all annotations false, the description carries the burden of behavioral disclosure. It explains the inline rendering behavior and the optional render_path, but does not clarify potential file-writing side effects when render_path is used, nor the meaning of 'source bank'. It adds some behavioral context but leaves important details implied.
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 a single dense sentence with no filler, front-loading the main action and then adding the conditional inline behavior. It is concise, though the semicolon-heavy structure and slight repetition of 'optional rendered output' vs 'inline=true' could be streamlined.
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?
Given the output schema existshare, return-value documentation is not needed, and the description covers the tool's core purpose and inline mode. However, the required `script` parameter is unexplainedeing, and the behavior of render_path when inline=false is ambiguous. This is adequate but not complete for a 4-parameter tool with no annotation support.
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 description coverage is 0%, so the description must compensate. It explicitly explains the inline and render_path relationshipbell, and 'tilemap' is contextually clear. However, the required `script` parameter is not described at all, and the exact roles of `script` and `tilemap` as inputs are left to inference.
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 clearly identifies the resource (Pyxel tilemap) and lists specific data it reads: tile coordinates, usage, bounds, source bank, and optional rendered output. This is more specific than sibling read_* tools and leaves little ambiguity about the tool's function.
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?
The description gives a concrete usage condition: inline=true returns render as image content and makes render_path optional, which helps the agent decide between inline and path-based output. It does not explicitly name sibling alternatives or exclusions, but the context of reading tilemaps is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
runA
Run a Pyxel script headlessly for a frame budget or until a condition holds, with scheduled input and state, screen, or video capture. screen_image snapshots with inline=true also return the PNG as image content, and a single inline frame may omit its output path.
| Name | Required | Description | Default |
|---|---|---|---|
| until | No | ||
| frames | Yes | ||
| inputs | No | ||
| script | Yes | ||
| timeout | No | ||
| snapshots | No | ||
| random_seed | No | ||
| stall_window_frames | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| log | Yes | |
| errors | Yes | |
| seeded | Yes | |
| snapshots | Yes | |
| until_met | No | True once `until` held, False when it was evaluated without ever holding, None when it was never evaluated. |
| exit_status | Yes | ok includes reaching the frame budget, matching until, or an explicit pyxel.quit(). Cleanup failures are reported as crashed. |
| frame_count | Yes | Number of completed update/draw pairs; excludes a partial quit frame. |
| elapsed_seconds | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate it is not read-only, not idempotent, and not destructive. The description adds useful details like the inline image behavior and headless execution, but it does not disclose the risk of executing arbitrary user code or potential side effects. The description partially adds behavioral context beyond annotations but misses key aspects.
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 concise (two sentences) and front-loaded with the core purpose. The second sentence adds a specific, non-obvious detail about inline images. It is efficient, though it could be slightly better organized with explicit sections for parameters and usage.
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?
Given the high complexity (8 parameters, nested snapshot objects, discriminator), the description is far too brief. It does not explain the differences between snapshot types, the format of 'until' conditions, or the meaning of stall_window_frames. An agent would need to rely heavily on the schema and would likely struggle to construct valid requests.
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 description coverage is 0%, so the description must compensate. It only offers a high-level overview (frame budget, condition, scheduled input, capture) but does not explain individual parameters like timeout, stall_window_frames, random_seed, or the snapshot request variants. This is insufficient for a complex tool with 8 parameters.
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 clearly states the verb (run), resource (Pyxel script), and context (headlessly, with frame budget or condition). It also mentions capture capabilities, which distinguishes it from the read/info sibling tools. This is specific and unambiguous.
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?
The description provides clear context on the tool's purpose (running scripts headlessly with capture) but does not explicitly mention alternatives or when not to use it. Given the sibling set (all read/info tools), the intended usage is fairly obvious, so this is a 4 rather than a 3.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validateARead-onlyIdempotent
Check Python syntax and report recognizable Pyxel code patterns.
| Name | Required | Description | Default |
|---|---|---|---|
| script | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| errors | Yes | |
| issues | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering the safety profile. The description adds valuable behavioral context by specifying that the tool performs syntax checking and pattern recognition, which implies a non-executing, analysis-only behavior. This goes beyond what annotations state, though it stops short of detailing exactly what patterns are recognized or how results are reported.
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 a single, front-loaded sentence with zero filler. It wastes no words and communicates the core action and focus immediately, making it easy for an agent to parse and act on quickly.
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?
Given the tool has a single parameter and an output schema (which presumably documents the return structure), the description covers the essentials: what the tool does and on what input. It does not explain potential edge cases (e.g., handling of invalid syntax) but those are likely covered by the output schema. The description is sufficiently complete for a straightforward validation tool.
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?
The input schema has zero description coverage for its single parameter, so the description must convey parameter meaning. It does so by implication: the tool validates Python syntax, so 'script' is the Python code to be checked. However, it does not explicitly state that the parameter contains the source code, and gives no hints about expected encoding, length limits, or file references. This is adequate for a single simple parameter but not fully explicit.
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 ('Check') and a clear resource ('Python syntax' and 'Pyxel code patterns'), which precisely distinguishes it from sibling tools like 'run', 'read_palette', and 'read_tilemap' that perform execution or read operations. An agent can immediately understand this is a validation tool, not a runtime or read tool.
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?
The description gives no explicit guidance on when to use this tool versus alternatives. It does not mention typical workflows (e.g., 'use before run'), nor does it reference any sibling tools, leaving the agent to infer usage context from the tool's name and purpose alone.
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.
1 tool update
v1.3.1- Changed
run2 fields changed- added
Output schema / properties / exit_status / descriptionAdded value: +"ok includes reaching the frame budget, matching until, or an explicit pyxel.quit(). Cleanup failures are reported as crashed." - added
Output schema / properties / frame_count / descriptionAdded value: +"Number of completed update/draw pairs; excludes a partial quit frame."
21 tool updates
v1.3.0- Removed
capture_frames - Removed
compare_frames - Added
diff_frames - Removed
inspect_bank - Removed
inspect_layout - Removed
inspect_palette - Removed
inspect_screen - Removed
inspect_sprite - Removed
inspect_state - Removed
inspect_tilemap - Removed
play_and_capture - Changed
pyxel_info13 fields changed- added
Output schema / $defsAdded value: +{ + "ExampleInfo": { + "additionalProperties": false, + "properties": { + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Description" + }, + "name": { + "title": "Name", + "type": "string" + }, + "path": { + "title": "Path", + "type": "string" + } + }, + "required": [ + "name", + "path" + ], + "title": "ExampleInfo", + "type": "object" + }, + "ToolErrorRecord": { + "additionalProperties": false, + "properties": { + "frame": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Frame" + }, + "message": { + "title": "Message", + "type": "string" + }, + "path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Path" + }, + "phase": { + "title": "Phase", + "type": "string" + }, + "traceback": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Traceback" + } + }, + "required": [ + "phase", + "message" + ], + "title": "ToolErrorRecord", + "type": "object" + } +} - added
Output schema / additionalPropertiesAdded value: +false - added
Output schema / properties / errorsAdded value: +{ + "items": { + "$ref": "#/$defs/ToolErrorRecord" + }, + "title": "Errors", + "type": "array" +} - added
Output schema / properties / examplesAdded value: +{ + "items": { + "$ref": "#/$defs/ExampleInfo" + }, + "title": "Examples", + "type": "array" +} - added
Output schema / properties / okAdded value: +{ + "title": "Ok", + "type": "boolean" +} - added
Output schema / properties / python_versionAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Python Version" +} - added
Output schema / properties / pyxel_mcp_versionAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Pyxel Mcp Version" +} - added
Output schema / properties / pyxel_versionAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Pyxel Version" +} - added
Output schema / properties / resourcesAdded value: +{ + "additionalProperties": { + "type": "string" + }, + "title": "Resources", + "type": "object" +} - removed
Output schema / properties / resultRemoved value: -{ - "title": "Result", - "type": "string" -} - added
Output schema / properties / stubs_pathAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Stubs Path" +} - changed
Output schema / requiredPrevious value: -[ - "result" -]New value: +[ + "ok", + "errors" +] - changed
Output schema / titlePrevious value: -"pyxel_infoOutput"New value: +"PyxelInfoResult"
- Added
read_audio - Added
read_image - Added
read_palette - Added
read_tilemap - Removed
render_audio - Added
run - Removed
run_and_capture - Added
validate - Removed
validate_script
14 tool updates
v0.8.0- First observed
capture_frames - First observed
compare_frames - First observed
inspect_bank - First observed
inspect_layout - First observed
inspect_palette - First observed
inspect_screen - First observed
inspect_sprite - First observed
inspect_state - First observed
inspect_tilemap - First observed
play_and_capture - First observed
pyxel_info - First observed
render_audio - First observed
run_and_capture - First observed
validate_script
TDQS
Scored across 8 tools
Each tool maps to a distinct concern: environment info, script execution, audio rendering, frame comparison, and specific resource readers for images, palettes, and tilemaps. Even the read_* tools are cleanly separated by resource type, so there is no meaningful overlap between them.
Most tools follow a clear action_resource pattern, especially read_image, read_palette, read_tilemap, and read_audio. The deviations are minor: pyxel_info is noun-ish and run is a bare verb, but both are still understandable and do not undermine the overall scheme.
With 8 tools, the surface is tightly scoped to running Pyxel scripts and inspecting Pyxel resources and output. No tool feels redundant or out of place, and the count is well within the ideal range.
The server covers a coherent inspect-and-run workflow: validate scripts, execute them, capture frames, diff frames, and read images, palettes, tilemaps, and audio. The main gap is the lack of tools for creating or modifying Pyxel resources, which is a workaround if the server is intended as a read-only/testing interface.
Maintenance
Related MCP Connectors
Generate authentic pixel art - sprites, animations, and tilesets - from any MCP client
MCP server for building and testing AI agents with multi-model experimentation and insights.
Generate game-ready 3D models, textures, and audio from natural language, over MCP.
Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceMCP server for programmatically creating and editing Aseprite sprites, enabling AI agents to draw, manage layers and frames, and iterate until the desired result is achieved.MIT
- AlicenseBqualityAmaintenanceAn MCP server that lets AI agents create and edit Aseprite sprites headlessly, enabling pixel art, animation, and export via 98 tools.15613MIT
- FlicenseAqualityDmaintenanceAn MCP server that enables AI coding agents to create pixel art programmatically by providing canvas manipulation tools and PNG export.1035 npm6-
- AlicenseNot gradedqualityAmaintenanceAn AI-native game engine MCP server that enables AI agents to create, modify, and run games using 53 tools for scene creation, physics, audio, 3D rendering, and AI-generated images and music.1MIT