actions-check
Reviews GitHub Actions workflow files for outdated actions, deprecated runner labels, deprecated commands, and security risks like script injection and unsafe pull_request_target usage, providing line-level findings with fixes.
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., "@actions-checkFind outdated actions and security risks in my workflows"
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.
Actions Check
Coding agents write GitHub Actions workflows from memory, so they reach for actions/checkout@v3,
echo "::set-output ..." and runs-on: ubuntu-20.04 years after those stopped being current, and
they paste untrusted pull request titles into shell scripts. Actions Check reviews workflow files the
way a careful maintainer would, and says what to change:
Every action against its latest release, from the action's own git tags (no API limit): how far behind it is, the runtime it runs on (Node 16 actions are deprecated), and the exact line to pin it by commit SHA (
actions/checkout@<sha> # v7.0.1). A moving tag like@v3names the release it actually points at.Runners against GitHub's runner-images list, matrix values included: labels GitHub no longer provides (jobs wait and fail) and deprecated ones.
Security: untrusted event text (issue and pull request titles, bodies, branch names) expanded into
run:scripts,pull_request_targetworkflows that check out the pull request's code, third-party actions not pinned to a commit, missingpermissions.Deprecated commands:
set-output,save-state,set-env,add-path.
Every finding has the file, the line and a fix. No key needed.
Built and maintained by Arhan Canli.
Install
Needs Node.js 20 or newer. No account or key.
Claude Code
claude mcp add actions-check -- npx -y actions-check-mcpClaude Desktop: download actions-check-mcp-<version>.mcpb from the latest release and open it. The bundle is signed; verify it with gh attestation verify <file> --repo arhancanli/actions-check-mcp.
Any other client (Windsurf, Zed, Cline, Continue and others), in its MCP config file:
{
"mcpServers": {
"actions-check": {
"command": "npx",
"args": [
"-y",
"actions-check-mcp"
]
}
}
}Docker
docker build -t actions-check-mcp https://github.com/arhancanli/actions-check-mcp.git && docker run -i --rm actions-check-mcpHosted (Streamable HTTP): node src/server.mjs --http serves stateless MCP at POST /mcp (port from PORT, default 3000).
Related MCP server: TaskBounty Check
Example
An agent calls check_workflows with:
{
"files": [
{
"path": ".github/workflows/ci.yml",
"content": "name: CI\non:\n pull_request_target:\n push:\njobs:\n build:\n runs-on: ${{ matrix.os }}\n strategy:\n matrix:\n os: [ubuntu-20.04, ubuntu-latest, macos-14]\n steps:\n - uses: actions/checkout@v3\n with:\n ref: ${{ github.event.pull_request.head.sha }}\n - uses: actions/setup-node@v4.0.0\n - uses: peaceiris/actions-gh-pages@v3\n - uses: some-org/does-not-exist-xyz@v1\n - run: echo \"Title: ${{ github.event.pull_request.title }}\"\n - run: |\n echo \"::set-output name=x::1\"\n echo \"done\"\n"
}
]
}and gets back (recorded from the live server on 2026-09-26):
{
"actions": [
"actions/checkout@v3 -> v3.7.0, latest v7.0.1, node16",
"actions/setup-node@v4.0.0 -> v4.0.0, latest v7.0.0, node20",
"peaceiris/actions-gh-pages@v3 -> v3.9.3, latest v4.1.0, node16"
],
"counts": {
"error": 6,
"warning": 4,
"info": 2
},
"findings": [
{
"level": "error",
"file": ".github/workflows/ci.yml",
"line": 18,
"code": "- run: echo \"Title: ${{ github.event.pull_request.title }}\"",
"issue": "Script injection: ${{ github.event.pull_request.title }} is text an outside contributor controls, expanded into a shell script.",
"fix": "Pass it through an environment variable: env: VALUE: ${{ github.event.pull_request.title }} and use \"$VALUE\" in the script."
},
{
"level": "error",
"file": ".github/workflows/ci.yml",
"line": 14,
"code": "ref: ${{ github.event.pull_request.head.sha }}",
"issue": "pull_request_target workflow checks out the pull request's code: it runs untrusted code with the repository's secrets and a write token.",
"fix": "Use pull_request for building contributed code, or keep the checkout of the base branch and never run the PR's code in this workflow."
},
{
"level": "error",
"where": ".github/workflows/ci.yml:12",
"issue": "actions/checkout@v3 runs on Node 16, which GitHub has deprecated for actions.",
"fix": "Update to v7.0.1 (runs on Node 24): actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1"
},
{
"level": "error",
"where": ".github/workflows/ci.yml:16",
"issue": "peaceiris/actions-gh-pages@v3 runs on Node 16, which GitHub has deprecated for actions.",
"fix": "Update to v4.1.0 (runs on Node 24): peaceiris/actions-gh-pages@84c30a85c19949d7eee79c4ff27748b70285e453 # v4.1.0"
},
{
"level": "error",
"where": ".github/workflows/ci.yml:17",
"issue": "some-org/does-not-exist-xyz@v1: github.com/some-org/does-not-exist-xyz does not exist or is private."
},
{
"level": "error",
"file": ".github/workflows/ci.yml",
"line": 7,
"issue": "runs-on ubuntu-20.04 (matrix.os): GitHub no longer provides this runner; jobs wait and fail.",
"fix": "Use ubuntu-latest, or a current version from GitHub's runner-images list."
},
{
"level": "warning",
"file": ".github/workflows/ci.yml",
"line": 20,
"code": "echo \"::set-output name=x::1\"",
"issue": "Deprecated workflow command ::set-output.",
"fix": "write to $GITHUB_OUTPUT instead: echo \"name=value\" >> \"$GITHUB_OUTPUT\""
},
... (32 more lines)Tools
Tool | What it does |
| For up to 20 actions (owner/repo, or owner/repo@ref): latest release with its commit SHA and runtime, the newest release of each major version, and for a ref, the commit it points to and its runtime, with the line to pin (action@sha # tag). |
| Reviews up to 30 workflow files (path and content): outdated actions and the SHA to pin, actions on deprecated Node runtimes, runner labels GitHub no longer provides, deprecated commands (set-output), script injection and pull_request_target risks. Findings with file, line and fix. |
| Status of GitHub-hosted runner labels (ubuntu-22.04, macos-14, windows-2019...) from GitHub's runner-images list: available, beta, deprecated, or retired (no longer provided). Without labels, every label GitHub lists now. |
How it behaves
Read-only: no tool changes anything outside this process.
Network: HTTPS only, to the hosts listed in
package.jsonunderfactory.allowHosts, with a deadline, a size cap and bounded retries. Nothing else is contacted, and nothing is logged except unexpected failures (to stderr, without your inputs).Workflow files are read as text and never run. Tags come from git's own ref listing (
github.com/<action>.git/info/refs), runtimes from each action'saction.ymlat the commit used, runner labels fromactions/runner-images. Answers are cached for 30 minutes.Local actions (
./...) anddocker://images are not looked up.Results are compact JSON with a matching output schema, errors first.
Benchmark
Measured 2026-09-26 with gpt-5.4-mini, 9 fixed tasks graded by fixed checks (bench/tasks.json, raw results in bench/results/).
Server | Correct | Input tokens | Output tokens | Tool calls | Median time |
This server | 8/9 | 12672 | 677 | 9 | 2.1 s |
mcp-server-fetch reading GitHub (no workflow-checking server exists; this is what agents use today) | 6/9 | 109430 | 898 | 21 | 4.2 s |
Performance
Measured 2026-09-26 from Dubai, home connection against the live upstream, Node 24.19.0 (bench/perf.json, scripts/perf.mjs in the factory).
Call | First call | Repeat | Result size |
check_workflows: a workflow with 12 problems | 1028 ms | 1.1 ms | 3,383 chars |
check_workflows: a clean, pinned workflow | 648 ms | 0.6 ms | 117 chars |
action_versions: 3 actions, with and without refs | 1018 ms | 0.9 ms | 1,375 chars |
runner_labels: 4 labels | 251 ms | 0.3 ms | 293 chars |
First call: a fresh server process, including the TLS connection and the upstream's own time. Repeat: the same call again, answered from the in-process cache, so it shows this server's own overhead.
Tool definitions the model reads on every turn (name, description, input schema): 1,450 characters, against 1,105 for mcp-server-fetch reading GitHub (no workflow-checking server exists; this is what agents use today). The full tool list, with the output schemas and annotations clients use to validate results, is 2,689 characters (1,104 for the alternative).
More MCP servers by Arhan Canli
Cron Check: Explains cron expressions, lists next run times in any time zone, converts between cron dialects.
Domain Health: Email and domain checks: SPF lookup limits, DKIM keys, DMARC, DNS records, registration expiry.
End of Life: Is this version still supported? EOL dates, latest patch and upgrade target for 470+ products.
Internet Standards: RFC sections, status, obsoleted-by chains, errata and IANA registries for coding agents.
License Check: Open source license answers: SPDX ids, copyleft, and whether a dependency's license fits yours.
Package Truth: Checks packages exist before install: version, deprecation, vulnerabilities, licence. 7 ecosystems.
Release Notes: What changed between two versions of a package: breaking changes, deprecations, security fixes.
Citation Check: Verifies citations: finds fabricated or mismatched references and retractions, returns clean BibTeX.
The whole collection, 7 more
License
MIT, Copyright (c) 2026 Arhan Canli.
Available Tools
3 toolsaction_versionsVersions of an actionARead-onlyIdempotent
For up to 20 actions (owner/repo, or owner/repo@ref): latest release with its commit SHA and runtime, the newest release of each major version, and for a ref, the commit it points to and its runtime, with the line to pin (action@sha # tag).
| Name | Required | Description | Default |
|---|---|---|---|
| actions | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, openWorldHint=true, and destructiveHint=false, so the safety profile is fully covered. The description adds return-content detail but does not disclose rate limits, pagination, or error behavior. With strong annotation coverage, a 3 is appropriate.
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?
A single dense sentence that front-loads the input constraint and enumerates outputs efficiently. No wasted words, though the structure is packed and could benefit from a slight split for readability.
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-value explanation is unnecessary. Combined with safety annotations and the description's coverage of input format and output content, the definition is adequate for a read-only retrieval tool. Minor gaps (rate limits, response shape nuances) are acceptable given the annotations.
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 0%, so the description must compensate. It does by specifying the parameter format ('owner/repo, or owner/repo@ref') and the 20-item cap. This provides meaning the bare schema array lacks, though it could go further on delimiters or edge cases.
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 resource ('actions') and enumerates the exact deliverables: latest release with commit SHA and runtime, newest release per major version, and ref resolution with pin line. The resource and return scope are unambiguous and clearly distinct from siblings check_workflows and runner_labels, which concern workflows and runner metadata respectively.
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 its purpose (retrieving action version information) and is clearly distinct from the siblings by subject matter, but it does not explicitly state when to choose this over alternatives or provide exclusion conditions. The usage context is inferred rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_workflowsReview GitHub Actions workflowsARead-onlyIdempotent
Reviews up to 30 workflow files (path and content): outdated actions and the SHA to pin, actions on deprecated Node runtimes, runner labels GitHub no longer provides, deprecated commands (set-output), script injection and pull_request_target risks. Findings with file, line and fix.
| Name | Required | Description | Default |
|---|---|---|---|
| files | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| counts | Yes | |
| findings | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, openWorld, and non-destructive behavior, and the description is consistent with these. It adds useful behavioral detail by stating that the tool analyzes provided path/content pairs and returns findings with file, line, and fix.
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 that front-loads the resource and limit, then presents checks and output in a compact, scannable list. Every clause adds information and there is no repetition of schema or annotation details.
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 single-parameter tool with a rich output schema and comprehensive annotations, the description covers the input contract, the analysis categories, and the output shape. It lacks only explicit routing guidance relative to siblings, which was already penalized under usage guidelines.
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 does by explaining that 'files' are workflow files consisting of path and content, implicitly reinforcing the required structure and the 30-file limit. It could add more about content format, but the meaning is clear.
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 ('Reviews') with a clear resource ('up to 30 workflow files') and enumerates the exact checks performed. It is unambiguous about what the tool does and is easily distinguished from siblings by its review-oriented 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 the tool is for reviewing workflow files for security and maintenance issues, but it does not explicitly state when to prefer this over the sibling tools action_versions or runner_labels. Usage context is present only by inference from the listed checks.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
runner_labelsGitHub-hosted runner labelsARead-onlyIdempotent
Status of GitHub-hosted runner labels (ubuntu-22.04, macos-14, windows-2019...) from GitHub's runner-images list: available, beta, deprecated, or retired (no longer provided). Without labels, every label GitHub lists now.
| Name | Required | Description | Default |
|---|---|---|---|
| labels | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint=false. The description adds valuable context: the possible statuses (including 'retired' meaning no longer provided) and the default of returning all labels if none are specified. This goes beyond the annotations without contradicting them, enriching the agent's understanding of behavior.
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 two sentences, front-loaded with the core purpose, examples, and statuses, then the default behavior. Every sentence earns its place, with zero waste or redundancy.
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 tool is simple with one optional parameter, and an output schema exists (so return format is covered). The description covers purpose, default behavior, and statuses. Annotations cover safety (read-only, non-destructive). It lacks explicit prerequisites or error conditions, but for a read-only status tool, the description is sufficiently complete for 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?
Schema description coverage is 0%, so the description must compensate for the single optional 'labels' parameter. It does provide examples of label names and clarifies that omitting the parameter returns all labels, but it does not explicitly define the parameter's purpose (e.g., 'labels to check status for'). The description adds some meaning but not a direct parameter explanation.
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+resource (status of GitHub-hosted runner labels) and gives concrete examples (ubuntu-22.04, macos-14, windows-2019) and statuses (available, beta, deprecated, retired). It clearly differentiates from sibling tools (action_versions, check_workflows) by focusing on runner labels, so an agent can identify the right tool without opening schemas.
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 usage by topic (runner labels vs. action versions or workflows) and clarifies the default behavior when the optional 'labels' parameter is omitted ('Without labels, every label GitHub lists now'). However, it does not explicitly state when to use this tool over alternatives or any exclusions, leaving the agent to infer from context.
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.
3 tool updates
v0.1.0- First observed
action_versions - First observed
check_workflows - First observed
runner_labels
TDQS
Scored across 3 tools
Each tool targets a distinct concern: action_versions queries specific action metadata, check_workflows scans workflow files for issues, and runner_labels reports runner label availability. No two tools overlap in purpose or output, so an agent can select unambiguously.
All names are lowercase snake_case and composed of two clear tokens, but the pattern varies: action_versions and runner_labels are noun phrases, while check_workflows is a verb_noun. This is a minor deviation from a fully consistent verb-first convention, but the names are still predictable and readable.
Three tools is well-scoped for a focused actions-checking utility. Each tool covers a distinct and necessary capability (version lookup, workflow review, runner label status) without redundancy or bloat, and the count falls within the typical 3–15 range.
The set covers the core actions-checking needs: outdated action versions, deprecated runtimes, runner labels, deprecated commands, and security risks. A minor gap is that there is no tool to list workflows in a repository; the agent must supply workflow paths externally, but this is a workable limitation rather than a significant dead end.
Maintenance
Related MCP Connectors
GitHub Actions workflow security audit - 21 checks: pinning, permissions, secrets, injection.
Finds the GitHub Actions workflow eating your CI bill and suggests fix diffs, verified against runs.
Screens public GitHub repos and PRs to generate risk maps, findings, and merge-readiness signals.
Triage failing GitHub Actions jobs and see what self-heal repaired, in natural language.
Related MCP Servers
- AlicenseAqualityNot gradedmaintenanceConnects AI assistants to GitHub Actions workflows to monitor CI/CD pipelines, view run logs, diagnose failures, and optionally trigger or manage workflows with granular permission controls.101-
- AlicenseAqualityCmaintenanceLocal-only GitHub Actions and CI maintenance scanner for AI-built apps. Exposes scan, explanation, and fix-planning tools to MCP clients; modifies nothing and makes no outbound requests by default.351 npm2MIT
- AlicenseNot gradedqualityDmaintenanceAnalyzes GitHub Actions workflows and performance, helping identify bottlenecks, failures, and optimization opportunities in CI/CD pipelines.24 npmMIT
- FlicenseNot gradedqualityDmaintenanceAudits GitHub Actions workflow files for supply-chain risks like script injection, leaked tokens, unpinned actions, and broad permissions.-