MCP Release validates MCP servers. It verifies the protocol handshake, discovers tools, validates their schemas, and checks for stdio protocol violations. Supports both HTTP/SSE remote servers and local stdio servers (spawned processes). It does not execute tools or accept credentials.
Web app: https://mcprelease.dev Demo endpoint: https://mcp-release-fixture.vercel.app/mcp Repository: https://github.com/daranium2020/mcp-release
The web checker at https://mcprelease.dev supports public HTTPS endpoints only. It does not accept credentials and cannot reach private networks or localhost.
- Open https://mcprelease.dev
- Enter a public HTTPS MCP endpoint URL and click Run Release Check
- Review the report. Download it as JSON or Markdown if needed.
To try without a real server, paste https://mcp-release-fixture.vercel.app/mcp directly.
The CLI runs on your machine and supports public, private, localhost, and authenticated MCP endpoints. Credentials stay in your environment and are never stored.
The web checker at https://mcprelease.dev only accepts public HTTPS endpoints without credentials. Use the CLI or GitHub Action for private networks, localhost, staging servers, or any endpoint that requires authentication.
# Install globally
npm install -g @mcp-release/cli
# Or run directly without installing
npx -y @mcp-release/cli check https://your-mcp-server.example.com/mcpHTTP/SSE endpoints:
# Public endpoint
mcp-release check https://your-mcp-server.example.com/mcp
# JSON output
mcp-release check https://example.com/mcp --json
# Markdown output
mcp-release check https://example.com/mcp --markdown
# Write report to file
mcp-release check https://example.com/mcp --json --out report.json
# Bearer token from environment variable (recommended for secrets)
MCP_TOKEN=your-token mcp-release check https://staging.example.com/mcp --bearer-token-env MCP_TOKEN
# Literal header (for non-secret values only)
mcp-release check https://staging.example.com/mcp --header "X-Tenant-Id: acme"
# Header value from environment variable
MY_KEY=secret mcp-release check https://staging.example.com/mcp --header-env "X-API-Key=MY_KEY"
# Localhost or private network endpoint
mcp-release check http://localhost:4000/mcp --allow-http
# Exit 4 on WARNING (e.g., AUTH_REQUIRED)
MCP_TOKEN=your-token mcp-release check https://staging.example.com/mcp \
--bearer-token-env MCP_TOKEN --fail-on-warningLocal stdio servers (new in v0.2.0):
# Spawn a local server by command string; validate over stdin/stdout
mcp-release check --stdio --command "npx -y my-mcp-server"
# With a working directory
mcp-release check --stdio --command "node dist/server.js" --cwd /path/to/project
# JSON output
mcp-release check --stdio --command "node dist/server.js" --json
# Write report to file
mcp-release check --stdio --command "npx -y my-mcp-server" --json --out report.jsonStdio validation runs entirely locally. No data is sent to the web app or any remote service.
From this repo (without installing):
pnpm build
node packages/cli/dist/index.js check https://mcp-release-fixture.vercel.app/mcpCLI exit codes:
| Code | Meaning |
|---|---|
0 |
PASS |
1 |
FAIL (validation found a blocking issue) |
2 |
Invalid CLI usage (bad arguments, missing env var) |
3 |
Transport error, timeout, or unexpected runtime error |
4 |
WARNING and --fail-on-warning was set |
All CLI options for check:
| Option | Description |
|---|---|
--stdio |
Validate a local stdio server (spawned process). Requires --command. |
--command <cmd> |
Command string to spawn the stdio server (e.g. "npx -y my-mcp-server"). |
--cwd <dir> |
Working directory for the spawned process (stdio mode only). |
--header "Name: value" |
Add a request header (HTTP mode). Repeatable. |
--header-env "Name=VAR" |
Read a header value from an env var (HTTP mode). Repeatable. |
--bearer-token-env VAR |
Read a bearer token from an env var; sends Authorization: Bearer <token> (HTTP mode). |
--timeout-ms <ms> |
Request/startup timeout in milliseconds (default: 10000). |
--max-redirects <n> |
Maximum redirects to follow (HTTP mode, default: 3). |
--allow-http |
Allow HTTP connections for localhost/development (HTTP mode). |
--json |
Print JSON report to stdout. |
--markdown |
Print Markdown report to stdout. |
--out <path> |
Write report to file (JSON by default; Markdown if --markdown). |
--fail-on-warning |
Exit 4 when overall status is WARNING. |
The GitHub Action supports public, staging, and authenticated MCP endpoints. Secrets stay in GitHub Actions secrets and are masked in logs.
Reference by a tagged release or by commit SHA for pinned usage:
HTTP/SSE endpoint:
- name: Validate MCP server
uses: daranium2020/mcp-release@v0.2.1
with:
endpoint: https://staging.example.com/mcp
bearer-token-env: MCP_TOKEN # reads token from env; never put secrets inline
fail-on: fail # optional: fail (default) | warning
timeout-ms: 10000 # optional
format: markdown # optional: json | markdown | both
env:
MCP_TOKEN: ${{ secrets.MCP_TOKEN }}Local stdio server (new in v0.2.0):
- name: Validate local MCP server
uses: daranium2020/mcp-release@v0.2.1
with:
transport: stdio
command: npx -y my-mcp-server
working-directory: ./packages/my-server # optional
fail-on: fail
format: markdownPass all secrets through the env block using GitHub Actions secrets (${{ secrets.YOUR_SECRET }}). Never put secret values directly in with: inputs or workflow YAML.
All inputs:
| Input | Description |
|---|---|
transport |
http (default) or stdio. |
endpoint |
MCP endpoint URL (required when transport: http). |
command |
Command to spawn the stdio server (required when transport: stdio). |
working-directory |
Working directory for the spawned process (stdio mode). |
bearer-token-env |
Name of an env var containing a bearer token. Sends Authorization: Bearer <token> (HTTP mode). |
header |
Newline-separated Name: value pairs added to every request (HTTP mode). |
header-env |
Newline-separated Name=ENV_VAR pairs. Values read from environment (HTTP mode). |
fail-on |
fail (default) or warning. |
timeout-ms |
Request/startup timeout in milliseconds. |
format |
json, markdown, or both. |
Outputs: status, failures, warnings, tools, report-path, pass-count, warning-count, fail-count, report-json, report-markdown
The action annotates the workflow job with findings and writes a summary to the GitHub Actions job summary.
| Area | Details |
|---|---|
| Protocol | MCP initialization handshake, protocol version negotiation, transport response codes |
| Tool schemas | Tool names (non-empty, valid characters), descriptions, inputSchema (valid JSON Schema, Ajv-compilable), outputSchema (if present), duplicate names |
| Network safety (HTTP) | SSRF protection, DNS pinning, redirect chain validation (up to 3 hops), HTTPS enforcement across all redirects |
| Stdio transport (stdio) | Non-JSON lines on stdout (STDIO_UNEXPECTED_OUTPUT), malformed MCP messages (STDIO_FRAMING_ERROR), response size limit (STDIO_RESPONSE_SIZE_EXCEEDED), unclean shutdown (STDIO_SHUTDOWN_TIMEOUT) |
| Reports | Findings exportable as JSON or Markdown |
What is not checked: tools are never invoked, authenticated endpoints are not validated, runtime correctness of tool responses is not assessed.
| Result | Meaning |
|---|---|
| PASS | All checks completed without a blocking or incomplete condition. A PASS does not guarantee universal security or correctness. It reflects the checks MCP Release ran. |
| WARNING | One or more checks could not complete or found a non-blocking issue. If the server returns 401, MCP Release records AUTH_REQUIRED as a WARNING and stops. No credentials are accepted or stored. |
| FAIL | One or more checks found a blocking condition. Review the server before shipping. |
- Tools are discovered via
tools/listbut never invoked. No arguments are constructed or sent. - Only public HTTPS endpoints are accepted. HTTP is rejected before any connection.
- Private, loopback, link-local (
169.254.0.0/16), and cloud-metadata (169.254.169.254) destinations are blocked at the DNS level. - DNS pinning closes the TOCTOU gap. The resolved IP is pinned at connection time.
- Redirects are re-validated at each hop. HTTPS applies across all redirects.
- Remote response bodies are never included in findings.
- No credentials are accepted, forwarded, or stored.
- TLS verification is enforced (
rejectUnauthorized: true). - Error messages are redacted. Token patterns and embedded URL credentials are stripped before being returned.
Human-readable summary suitable for pull request descriptions and release notes. Generated by packages/reporter.
After a check completes, the results area displays overall status, findings grouped by severity, discovered tools, and export buttons (Copy JSON, Download JSON, Download Markdown).
| Package / App | Purpose |
|---|---|
packages/core |
Validation engine: SSRF guard, DNS pinning, transport adapter, MCP validator, report model |
packages/cli |
Command-line interface |
packages/reporter |
JSON, Markdown, and terminal report formatters |
packages/github-action |
GitHub Action (action.yml) wrapping the core validator |
apps/web |
Next.js 15 web interface (https://mcprelease.dev) |
apps/public-mcp-fixture |
Public MCP fixture server (https://mcp-release-fixture.vercel.app/mcp) |
fixtures/servers |
Localhost fixture MCP servers used in tests |
Two independent Vercel projects:
| Project | Root directory | URL |
|---|---|---|
mcp-release |
apps/web |
https://mcprelease.dev |
mcp-release-fixture |
apps/public-mcp-fixture |
https://mcp-release-fixture.vercel.app |
apps/web (mcprelease.dev) deploys automatically on every push to main. apps/public-mcp-fixture has automatic deployments disabled and is deployed manually.
apps/web depends on packages/core and packages/reporter. Its build command builds those packages first:
pnpm --filter @mcp-release/core build && pnpm --filter @mcp-release/reporter build && pnpm --filter @mcp-release/web build
apps/public-mcp-fixture has no sibling package dependencies and builds with next build directly.
Requirements: Node.js ≥ 22.13.0, pnpm ≥ 10.28.0
pnpm install # install all workspace dependencies
pnpm typecheck # TypeScript type check (all packages + apps)
pnpm lint # ESLint across the workspace
pnpm build # build all packages and apps
pnpm test # run all tests (500+ automated tests)pnpm --filter @mcp-release/web dev
# → http://localhost:3000The development server shows fixture buttons (PASS / WARNING / FAIL) that load sample reports without making network requests. These buttons are removed in production builds.
apps/web/src/
├── app/
│ ├── layout.tsx HTML shell, metadata, OG tags
│ ├── page.tsx Landing page
│ ├── docs/
│ │ └── page.tsx Documentation page
│ └── api/check/
│ ├── handler.ts Testable request handler
│ └── route.ts Next.js route entry point
├── components/
│ ├── Header.tsx / .module.css
│ ├── Footer.tsx / .module.css
│ ├── CheckClient.tsx / .module.css Client component (form, state)
│ └── Results.tsx / .module.css Report display
└── lib/
├── constants.ts SITE_URL, GITHUB_URL, DEMO_ENDPOINT, timeout bounds
├── rate-limit.ts In-memory sliding-window rate limiter
└── concurrency.ts In-memory concurrency guard
POST /api/check accepts application/json:
{ "endpoint": "https://example.com/mcp", "timeoutMs": 10000 }endpoint: required, HTTPS only, no embedded credentialstimeoutMs: optional, 1000-30000 ms (default 10000)- Unexpected fields are rejected with
400 UNEXPECTED_FIELD
Returns 200 { "report": CheckReport } or a JSON error body with error and message.
- Rate limit: 10 requests per IP per minute (sliding window)
- Concurrency: max 5 simultaneous outbound checks
Both controls are per-process. See Known Limitations below.
- Public HTTPS endpoints only. HTTP and private network endpoints are rejected.
- No credential input. Authenticated checks are not performed. Servers requiring authorization return
AUTH_REQUIRED(WARNING). - Tools are not invoked. Runtime correctness of tool responses is not validated.
- A PASS is not a security guarantee. It reflects the checks MCP Release ran. Runtime behavior may differ in other environments.
- In-memory rate limiting. Per-process only, not shared across horizontally-scaled instances.
- Reports are not stored server-side. Export before closing the tab.
- x-forwarded-for is used for rate limiting. Accurate behind a trusted proxy, not verified otherwise.
pnpm install
pnpm typecheck && pnpm lint && pnpm testAll PRs run the full suite via .github/workflows/ci.yml. The workflow uses SHA-pinned actions and pnpm 10.28.0.
Core validation behavior (transport, SSRF, DNS pinning, error classification, report format) is covered by tests in packages/core/tests/. Web UI behavior is covered by tests in apps/web/tests/.