# MCP Server Validator & Security Audit 2026 (`craigtechservicesllc/mcp-server-validator-security-audit`) Actor

Validate remote MCP servers for current protocol compatibility, OAuth, headers, schemas, capabilities, tools/resources inventories, and production security without invoking tools.

- **URL**: https://apify.com/craigtechservicesllc/mcp-server-validator-security-audit.md
- **Developed by:** [Daniel Craig](https://apify.com/craigtechservicesllc) (community)
- **Categories:** Developer tools, MCP servers, AI
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $50.00 / 1,000 mcp server audits

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## MCP Server Validator & Security Audit 2026

A non-destructive Apify Actor for validating remote Model Context Protocol (MCP) servers against the **final MCP 2026-07-28 protocol** and producing deterministic deployment-readiness reports.

The defining safety rule is simple: **the Actor never sends `tools/call` and never executes a discovered MCP tool.** It performs discovery/list operations and narrow protocol, transport, Origin, OAuth, and schema probes only.

### Why developers use it

A server can be reachable and still fail when a modern MCP client, gateway, load balancer, or OAuth flow depends on it. The July 28, 2026 protocol introduced major changes including a stateless core, `server/discover`, header-based routing, cacheable list results, and authorization hardening.

Use this Actor for:

- pre-production MCP validation;
- CI/CD regression checks after deployments or SDK upgrades;
- migration checks from 2025-era MCP servers;
- gateway/reverse-proxy header validation;
- OAuth discovery troubleshooting;
- safe capability inventory without tool execution;
- recurring deployment-readiness checks.

### What it checks

#### MCP 2026 protocol and transport

- `server/discover` and advertised protocol versions;
- modern per-request `_meta` protocol version;
- modern `resultType` values;
- final `HeaderMismatch` behavior: HTTP 400 + JSON-RPC **`-32020`**;
- `MCP-Protocol-Version` required/mismatch behavior;
- `Mcp-Method` required/mismatch behavior;
- response `_meta` server identity;
- list-result cache hints such as `ttlMs` and `cacheScope`;
- deterministic first-page `tools/list` ordering;
- JSON-RPC envelope validity;
- JSON and Streamable HTTP SSE parsing;
- legacy 2025 `initialize` detection;
- unexpected legacy `Mcp-Session-Id` use on 2026 responses;
- Content-Type, HSTS, server/cookie disclosure, TLS, and certificate observations.

#### OAuth and authorization readiness

For protected endpoints, passive checks include:

- Bearer `WWW-Authenticate` challenge presence;
- one unique high-entropy invalid-token `server/discover` probe that verifies invalid credentials are rejected with HTTP 401;
- passive HTTP 403 validation for a Bearer `insufficient_scope` challenge and minimum-scope signal;
- challenge scope signals and obvious over-broad scopes;
- RFC 9728 Protected Resource Metadata discovery;
- required `resource` and exact resource matching;
- non-empty `authorization_servers`;
- safe public HTTPS authorization-server URLs;
- RFC 8414 / OpenID Connect authorization-server metadata discovery;
- exact issuer consistency;
- authorization, token, JWKS, and registration endpoint URL safety;
- PKCE `S256` support;
- authorization-code response/grant signals;
- implicit-flow warnings;
- RFC 9207 authorization-response issuer support signal;
- Client ID Metadata Document (`client_id_metadata_document_supported`) readiness and DCR-deprecation guidance;
- optional protected-resource cross-checks;
- `offline_access` and broad-scope warnings.

The Actor **does not log in, register an OAuth client, redeem an authorization code, request a token, or execute a protected tool**.

#### Capability/schema inventory

The Actor can safely list and summarize:

- tools;
- resources;
- resource templates;
- prompts.

It checks duplicate identifiers, tool schema shape, `x-mcp-header` mappings, recommended tool-name form, and MCP tool risk annotations (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`). Missing hints use conservative defaults in the report. Contradictory hints are flagged.

Tool-description security flags are deliberately heuristic and are never presented as proof of malicious behavior.

### Safety and security model

#### No tool execution

Production source contains no `tools/call` invocation. The test suite includes a **500-full-audit stress test** that verifies zero tool calls.

#### SSRF and network protections

- HTTPS required by default.
- Private/internal/local hostnames blocked.
- Loopback, RFC1918, link-local, CGNAT, documentation, multicast, reserved IPv4, unique-local/link-local/multicast/reserved IPv6, and mapped-private targets blocked.
- DNS checked before a request and rechecked by the lookup used by the actual HTTP/TLS socket, reducing DNS-rebinding/TOCTOU risk.
- Redirect targets revalidated.
- Cross-origin redirects blocked by default.
- HTTPS-to-HTTP downgrade redirects blocked.
- URL usernames/passwords, fragments, credential-like query parameters, oversized URLs, and common sensitive/non-HTTP infrastructure ports blocked.
- OAuth metadata URLs use the same safe URL validation.

#### Credential protections

`bearerToken` is an Apify `isSecret: true` input.

- Token syntax is validated before use.
- Only the token value is accepted, not a `Bearer ` prefix.
- Authenticated multi-endpoint runs must stay on one origin.
- Authorization/cookie/proxy-authorization headers are never transmitted over plaintext HTTP in production.
- Cross-origin redirects do not receive credentials.
- Exact supplied secrets, concrete Authorization Bearer header values, JWT-looking values, and common credential assignments are redacted before persistence without rewriting safe protocol prose.
- Reflected-token leakage from a hostile/broken server is covered by automated tests.
- Resource/resource-template URIs are reduced before persistence: embedded userinfo, sensitive query values, and fragments are redacted.
- Untrusted output is bounded and copied into null-prototype objects to prevent prototype-pollution keys from mutating sanitized output.

#### Resource and abuse controls

- maximum 25 endpoints per run;
- maximum concurrency 5;
- bounded request deadlines with both inactivity and absolute wall-clock limits;
- bounded response bytes and response-header count;
- response compression requested as `identity`;
- bounded redirects, pagination, cursor size, and inventory size;
- repeated pagination cursors terminate the list walk;
- no browser, shell, arbitrary proxy, external LLM, analytics service, or third-party validation API.

See `SECURITY.md` for the complete threat model and limitations.

### Why direct secret input is used instead of an MCP Connector

Apify MCP Connectors are valuable when an Actor needs to *use* another MCP service while keeping its credential behind Apify's MCP Proxy. This Actor needs to measure the target server's **own** HTTP status codes, redirects, Origin behavior, MCP headers, and OAuth metadata. Routing the core audit through a proxy would cause some checks to measure the proxy rather than the upstream server.

For audit fidelity, authenticated checks therefore use an optional Apify secret Bearer input with the protections above. The Actor still never executes tools.

### Input

Safe no-secret example:

```json
{
  "servers": [
    {
      "url": "https://mcp.apify.com",
      "name": "Apify hosted MCP"
    }
  ]
}
```

Authenticated example:

```json
{
  "servers": [
    { "url": "https://YOUR-MCP-HOST.example/mcp" }
  ],
  "bearerToken": "<TOKEN>",
  "includeInventory": true
}
```

Important inputs:

| Input | Default | Purpose |
|---|---:|---|
| `servers` | required | 1-25 public remote MCP HTTP(S) endpoints |
| `bearerToken` | empty | Optional Apify secret Bearer token |
| `protocolVersion` | `2026-07-28` | Target modern revision |
| `compatibilityProbe` | `true` | Detect responding 2025-era servers |
| `originSecurityProbe` | `true` | Test rejection of an unrelated Origin |
| `headerComplianceProbe` | `true` | Test required/matching MCP routing headers |
| `validateAuthorizationDiscovery` | `true` | Passive RFC 9728 + RFC 8414/OIDC checks |
| `includeInventory` | `true` | Include bounded capability summaries |
| `timeoutSecs` | `15` | Per-request inactivity and absolute deadline |
| `maxResponseBytes` | `1000000` | Per-response byte cap |
| `maxListPages` | `5` | Pagination cap |
| `maxItemsPerCapability` | `500` | Inventory cap |
| `concurrency` | `3` | Endpoint concurrency, hard-capped at 5 |
| `allowInsecureHttp` | `false` | Public development HTTP only; credentials/private targets remain blocked |

### Output

Each endpoint produces one dataset item with:

- server and detected protocol era;
- supported protocol versions;
- server identity/capabilities when present;
- authorization discovery results;
- inventory counts and optional bounded inventory;
- safe request observations;
- stable findings with status, severity, evidence, and remediation;
- deterministic overall/protocol/security scores and letter grade.

A compact run summary is also stored under the default key-value-store `OUTPUT` key.

Example finding:

```json
{
  "id": "MCP_PROTOCOL_HEADER_MISMATCH_ACCEPTED",
  "category": "protocol",
  "status": "fail",
  "severity": "high",
  "title": "Protocol-version header/body mismatch was not rejected",
  "detail": "Expected HTTP 400 and JSON-RPC -32020; observed HTTP 200.",
  "remediation": "Validate MCP-Protocol-Version against io.modelcontextprotocol/protocolVersion in request _meta."
}
```

### CI usage

Start the Actor through the normal Apify Actor API and fail a deployment when, for example:

- `summary.fail > 0`;
- `detectedEra != "modern-2026"`;
- `summary.protocolScore < 90`;
- a specific stable finding ID is present.

### Accuracy boundary

This is a **remote, non-destructive deployment-readiness audit**, not a penetration test or certification. It cannot prove server-side token audience validation, prove absence of token passthrough, inspect source code, verify OAuth state/redirect internals, or test tool-handler authorization without invoking tools.

A passing result means the observable checks performed by this Actor passed. It does **not** mean the deployment is guaranteed secure.

Use only on endpoints you own or are authorized to assess.

# Actor input Schema

## `servers` (type: `array`):

Remote Streamable HTTP MCP endpoint URLs to audit. Up to 25 per run.

## `bearerToken` (type: `string`):

Apify secret input. Used only as an Authorization header to same-origin HTTPS MCP endpoints, exact secret values are redacted from persisted reports, and plaintext HTTP credential transmission is blocked.

## `protocolVersion` (type: `string`):

The launch version focuses on the current MCP revision.

## `compatibilityProbe` (type: `boolean`):

Checks whether the endpoint also responds like a legacy 2025 MCP server so migration issues can be identified.

## `originSecurityProbe` (type: `boolean`):

Sends one safe discovery request with an unrelated Origin header. No tool is invoked.

## `headerComplianceProbe` (type: `boolean`):

Sends safe discovery requests with missing/mismatched Mcp-Method and MCP-Protocol-Version headers to verify final 2026-07-28 enforcement.

## `validateAuthorizationDiscovery` (type: `boolean`):

For protected endpoints, validates RFC 9728 Protected Resource Metadata plus RFC 8414/OIDC authorization-server discovery, issuer consistency, PKCE S256, Client ID Metadata Document readiness, endpoint URL safety, scope signals, and safe 401/403 invalid-token semantics without starting an OAuth login.

## `includeInventory` (type: `boolean`):

Includes bounded tool names/schema/risk-hint flags, resource URIs, templates, and prompt names. Full tool descriptions and tokens are not emitted.

## `timeoutSecs` (type: `integer`):

Maximum wall-clock time allowed for each individual HTTP request before the audit cancels it.

## `maxResponseBytes` (type: `integer`):

Safety cap for each HTTP response.

## `maxListPages` (type: `integer`):

Maximum number of pagination pages requested from each MCP list method to bound audit work and avoid cursor loops.

## `maxItemsPerCapability` (type: `integer`):

Maximum number of discovered tools, resources, resource templates, or prompts retained per capability.

## `concurrency` (type: `integer`):

Maximum number of MCP endpoints audited at the same time. The runtime also enforces a hard safety cap of 5.

## `allowInsecureHttp` (type: `boolean`):

Off by default. Only unauthenticated public HTTP endpoints can be audited; private/local/reserved targets and credential transmission over HTTP remain blocked in production.

## Actor input object example

```json
{
  "servers": [
    {
      "url": "https://mcp.apify.com",
      "name": "Apify hosted MCP (OAuth discovery)"
    }
  ],
  "protocolVersion": "2026-07-28",
  "compatibilityProbe": true,
  "originSecurityProbe": true,
  "headerComplianceProbe": true,
  "validateAuthorizationDiscovery": true,
  "includeInventory": true,
  "timeoutSecs": 15,
  "maxResponseBytes": 1000000,
  "maxListPages": 5,
  "maxItemsPerCapability": 500,
  "concurrency": 3,
  "allowInsecureHttp": false
}
```

# Actor output Schema

## `results` (type: `string`):

One structured report per audited MCP endpoint.

## `summary` (type: `string`):

Compact aggregate output written under OUTPUT.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "servers": [
        {
            "url": "https://mcp.apify.com",
            "name": "Apify hosted MCP (OAuth discovery)"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("craigtechservicesllc/mcp-server-validator-security-audit").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "servers": [{
            "url": "https://mcp.apify.com",
            "name": "Apify hosted MCP (OAuth discovery)",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("craigtechservicesllc/mcp-server-validator-security-audit").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "servers": [
    {
      "url": "https://mcp.apify.com",
      "name": "Apify hosted MCP (OAuth discovery)"
    }
  ]
}' |
apify call craigtechservicesllc/mcp-server-validator-security-audit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,craigtechservicesllc/mcp-server-validator-security-audit"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/F91HN792aLMktmAFU/builds/Rhumxo5SlYkgMLHd9/openapi.json
