# MCP Trust & Rug-Pull Monitor (`fascinating_lentil/mcp-trust-rug-pull-monitor`) Actor

Monitor authorized public MCP servers for tool, schema, permission, package, TLS, and behavioral drift. Detect suspicious changes, preserve trusted baselines, and quarantine risky updates for manual approval.

- **URL**: https://apify.com/fascinating\_lentil/mcp-trust-rug-pull-monitor.md
- **Developed by:** [Md Jakaria Mirza](https://apify.com/fascinating_lentil) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 server inspections

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/platform/actors/running/actors-in-store#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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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 Trust & Rug-Pull Monitor

A defensive Apify Actor that monitors **authorized** MCP server metadata for security-relevant drift. It retrieves only exposed discovery metadata, normalizes and redacts it, compares it with a trusted baseline when one exists, and produces structured reports for human review. It never invokes discovered tools (`tools/call`), executes local processes, uses stdio/process transport, guesses credentials, bypasses authentication, or sends destructive target requests.

> **Authorization and legal notice:** Set `authorizedUseConfirmed: true` only when every target intentionally exposes public metadata, belongs to you, or you have explicit permission to inspect it. You are responsible for applicable terms, law, and organizational policy. This Actor does not certify safety or detect every attack.

### Supported metadata transports and safety scope

- **Streamable HTTP:** bounded `initialize`, `tools/list`, `resources/list`, and `prompts/list` discovery only. Discovered tools are never called.
- **Static JSON:** bounded MCP manifests or exported discovery metadata.
- **Legacy HTTP/SSE:** recognized but returns `unsupported_transport` in this release because no bounded correlated streaming client is implemented.

The hosted Actor blocks localhost, loopback, RFC1918/private, link-local, cloud metadata, Unix socket, `file:`, and unsupported targets. HTTPS is required by default. Plain HTTP requires explicit `allowHttp: true`; private-network access remains unsupported. DNS and redirects are revalidated, cross-origin credential redirects are rejected, and response sizes, retries, request time, per-server wall time, and concurrency are bounded.

### Input and safe defaults

```json
{
  "authorizedUseConfirmed": true,
  "servers": [
    {
      "name": "production-mcp",
      "url": "https://mcp.example.com/mcp",
      "transport": "auto",
      "headers": { "Authorization": "Bearer <APIFY_SECRET_VALUE>" },
      "enabled": true,
      "tags": ["production", "customer-support"]
    }
  ],
  "baselineMode": "compare_only",
  "promoteCandidateBaseline": false,
  "minimumAlertSeverity": "medium",
  "checkVulnerabilities": true,
  "checkTls": true,
  "includeRawNormalizedSnapshot": false,
  "requestTimeoutSeconds": 20,
  "maxRetries": 2,
  "concurrency": 5,
  "dryRun": false,
  "allowHttp": false,
  "maxResponseBytes": 1048576
}
````

`compare_only` is the production and schema default: an omitted `baselineMode` never creates or updates a trusted baseline. For compatibility with the pinned schema validator, the input schema marks the complete `servers` JSON array as encrypted secret input, which covers every nested `headers` object and value. Put authorized credentials only in `headers`; never put real secrets in names, tags, target URLs, webhook URLs, examples, logs, or reports. Credential-shaped target query parameters and URL credentials are rejected. Metadata strings are redacted before logs, reports, webhooks, and baseline storage; inside JSON Schema `properties`/`patternProperties`, credential-shaped property names are preserved while value-bearing `default`, `const`, `examples`, and `enum` values are replaced before hashing, storage, Dataset output, evidence, or OSV processing.

Input limits match runtime validation:

- 1–25 server entries; enabled targets must have unique effective name/URL baseline keys.
- Server names: 1–128 characters. Tags: at most 20, each 1–128 characters.
- Header names: 1–128 valid header-token characters; values: 1–4096 characters without line breaks; combined names and values: at most 8192 bytes. Connection-routing and framing headers are rejected.
- Request timeout: 1–120 seconds; retries: 0–4; concurrency: 1–10.
- Metadata response limit: 16,384–5,242,880 bytes.
- Optional webhook: public HTTPS, at most 2048 characters, and no URL credentials.

#### Baseline and candidate modes

- `compare_only` (**safe default**): compare with a compatible trusted baseline when present; never write trusted or candidate state.
- `initialize_only`: initialize a trusted baseline when none exists; otherwise compare without updating it.
- `compare_and_update`: initialize or update trusted state only after a successful complete classified inspection. High/critical initialization or drift is retained as a separate candidate instead of being trusted automatically.
- `manual_approval`: write a separate candidate and never overwrite trusted state.
- `promoteCandidateBaseline: true`: promote only a compatible stored candidate whose endpoint identity, current snapshot hash, and recorded trusted-parent hash (or explicit no-parent state) exactly match current state. Any missing, incompatible, endpoint/hash/parent mismatch returns structured `promotion_mismatch`, preserves both records, and never substitutes a new candidate. A valid attempt durably marks its exact target before updating trusted state, so retry can safely finish candidate consumption if deletion was interrupted after the trusted write. Successful promotion consumes the candidate.
- `dryRun: true`: disable all trusted, candidate, and promotion writes regardless of mode.
- `baselineKeyValueStoreId` + `baselineRequestQueueId`: optional persistent stores selected through Apify resource pickers. Both are required for any non-dry-run initialization, update, candidate write, or promotion. Reuse the same two stores across task or scheduled runs.

Unreachable, malformed, timed-out, unauthenticated, empty, incomplete, incompatible, unclassified, or lease-conflicted inspections never replace trusted state.

### Reports, persistence, and alerting

Each enabled server produces one redacted Dataset `Report` containing status, reachability, concrete transport, baseline and snapshot hashes, severity, 0–100 risk score, classified changes, OSV outcomes, TLS metadata, recommendations, baseline/candidate flags, timestamps, bounded inspection metadata, and structured errors. `includeRawNormalizedSnapshot` adds the redacted canonical snapshot only when explicitly enabled.

The Actor persists the Dataset report first with `persistence.succeeded: true`. Only after that write succeeds can it deliver the optional webhook and attempt pay-per-event charges. Dataset, webhook, PPE, and finalizer waits are bounded by the same per-server deadline. If Dataset persistence fails or reaches that deadline, webhook delivery and PPE charging are suppressed for that report; the timed-out promise is rejection-safe but is not treated as durable success even if its provider later settles. Because webhook and PPE outcomes occur after the Dataset write, those late runtime fields are normally visible in logs rather than the already persisted item. Webhook or charging failure does not rewrite or invalidate a durable report.

Trusted and candidate snapshots are stored as versioned records in the default Key-Value Store only when the selected mode permits writes. Baseline mutation also uses the run's default Request Queue for atomic ownership. For scheduled or task-based monitoring, pin both the default Key-Value Store and default Request Queue across runs; otherwise each run receives fresh state and cannot compare with an earlier baseline. Candidates carry their exact trusted-parent hash (or explicit no-parent state), and successful promotion deletes the consumed candidate.

Every trusted/candidate set or delete requires verified ownership of an atomic lock in the run's authorized default Apify Request Queue. The queue temporarily contains one synthetic unique-key request per active baseline mutation with owner/expiry metadata; successful release removes that request, and the Actor never fetches its synthetic `.invalid` URL. Native lock expiry is longer than the maximum per-server mutation window, ownership is heartbeated while an overdue KVS mutation settles, and platform KVS mutation calls use a shorter non-retrying timeout. Expiry permits safe stale-owner takeover after a terminated run. If the queue API or ownership verification is unavailable, mutating modes fail closed; ordinary `compare_only` reads remain bounded, side-effect-free KVS reads. KVS records alone cannot provide cross-run atomicity, so deployments that cannot access the run's default Apify Request Queue cannot mutate baseline state.

A public HTTPS webhook is eligible only when the report meets `minimumAlertSeverity` and its status is alertable. Changed comparisons and relevant failures can alert; candidate initialization alerts only at high/critical severity, and trusted initialization alerts only at critical severity. Payloads are compact and redacted, delivery is bounded, and failures do not alter monitoring results.

### Vulnerability, TLS, and risk interpretation

When metadata explicitly contains an unambiguous package name, version, and ecosystem, the Actor can query the public OSV API. It does not infer package identity or treat a match as proof of exploitability. Unavailable lookups are represented as unavailable rather than fabricated findings. Optional TLS inspection reports certificate validity, hostname issues, expiry within 30 days, and protocol metadata.

Changes include a stable ID, category, entity, JSON path where applicable, redacted values, deterministic severity and score contribution, rule ID, explanation, evidence, confidence, and recommended action. The rule-based score is not an LLM judgment. This remains a change monitor with possible false positives and false negatives; review medium, high, and critical results before action.

### Cloud smoke input

[`input-smoke.json`](input-smoke.json) is a no-secret cloud smoke configuration for the public raw GitHub fixture URL `https://raw.githubusercontent.com/erenmyeager15/mcp-trust-rug-pull-monitor/master/src/__fixtures__/mcp-manifest.json`. The same safe fixture is used by the input-schema prefill for automated Store QA. It uses explicit `static_json`, `compare_only`, `dryRun`, no TLS/OSV/webhook, zero retries, one worker, a three-second request bound, and the minimum response limit. The fixture contains meaningful MCP server/tool/package metadata and no credentials or secret values. A successful inspection is expected to return non-green `baseline_missing` with `baselineUpdated: false` and `candidateBaselineStored: false`; it performs no KVS or Request Queue writes.

The local `npm run smoke` command is separate: it uses in-memory fixtures to exercise initialization, unchanged comparison, and a security-relevant change without network access.

### Development and release validation

Node.js 20 or newer is required. The scripts invoke TypeScript through Node directly, so this Windows path's `&` character is not interpreted through a `node_modules/.bin` shim.

```powershell
npm ci
npm run typecheck
npm run lint
npm run test:unit
npm run test:integration
npm test
npm run smoke
npm audit --omit=dev --audit-level=high
npx --yes apify-cli@1.7.1 validate-schema
```

The project is licensed under Apache-2.0; see [LICENSE](LICENSE). It uses no paid AI API and has no dashboard or separate SaaS component.

# Actor input Schema

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

One to 25 public MCP metadata endpoints that you own, are authorized to inspect, or that intentionally expose public metadata. Disabled entries count toward the 25-entry limit.

## `authorizedUseConfirmed` (type: `boolean`):

Required. Set true only when every target intentionally exposes public metadata, belongs to you, or you have explicit permission to inspect it. False is rejected by the Actor.

## `baselineKeyValueStoreId` (type: `string`):

Optional persistent Key-Value Store for trusted and candidate baselines. Required together with a baseline Request Queue for non-dry-run initialization, update, or promotion. Reuse the same selected stores across scheduled runs.

## `baselineRequestQueueId` (type: `string`):

Optional persistent Request Queue used only for atomic baseline mutation locks. Required together with the baseline Key-Value Store for non-dry-run initialization, update, or promotion.

## `baselineMode` (type: `string`):

Controls trusted baseline persistence. The safe default compare\_only never creates or updates a trusted baseline. Choose a mutating mode only after reviewing the endpoint and persistence behavior.

## `promoteCandidateBaseline` (type: `boolean`):

When true, promote and consume a compatible stored candidate only if its endpoint identity, current snapshot hash, and exact trusted-parent hash (or explicit no-parent state) match the current state. Any mismatch returns promotion\_mismatch and preserves both records.

## `minimumAlertSeverity` (type: `string`):

Lowest report severity eligible for the optional webhook. Status-specific alert rules still apply, and webhook delivery occurs only after Dataset persistence succeeds.

## `webhookUrl` (type: `string`):

Optional public HTTPS webhook URL without URL credentials. Do not include tokens or other secrets in the URL.

## `checkVulnerabilities` (type: `boolean`):

Query the public OSV API only for package identities and versions explicitly exposed by server metadata. Unavailable lookups are reported without fabricating matches.

## `checkTls` (type: `boolean`):

Inspect HTTPS certificate validity, hostname, expiry, and negotiated protocol metadata before the MCP metadata request.

## `includeRawNormalizedSnapshot` (type: `boolean`):

Include the redacted canonical metadata snapshot in each Dataset report. Leave disabled unless downstream review requires the larger payload.

## `requestTimeoutSeconds` (type: `integer`):

Timeout for each bounded network operation, from 1 to 120 seconds. A separate per-server wall-clock limit also applies.

## `maxRetries` (type: `integer`):

Maximum retry count for eligible metadata requests, from zero to four. Authentication and other terminal failures are not retried indefinitely.

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

Number of enabled servers inspected concurrently, from one to ten.

## `dryRun` (type: `boolean`):

Inspect and compare without creating, updating, promoting, or replacing trusted or candidate baseline records.

## `allowHttp` (type: `boolean`):

Explicitly opt in to public plain-HTTP targets. Disabled by default because HTTP provides no transport confidentiality or certificate validation.

## `allowPrivateNetwork` (type: `boolean`):

Reserved compatibility field that must remain false. Private, loopback, link-local, metadata-service, local-file, Unix-socket, and stdio targets are unsupported by this hosted Actor.

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

Maximum accepted metadata response body size, from 16 KiB to 5 MiB. Oversized or incomplete responses never update a trusted baseline.

## Actor input object example

```json
{
  "servers": [
    {
      "name": "public-mcp-fixture-smoke",
      "url": "https://raw.githubusercontent.com/erenmyeager15/mcp-trust-rug-pull-monitor/master/src/__fixtures__/mcp-manifest.json",
      "transport": "static_json",
      "enabled": true,
      "tags": [
        "public-demo"
      ]
    }
  ],
  "authorizedUseConfirmed": true,
  "baselineMode": "compare_only",
  "promoteCandidateBaseline": false,
  "minimumAlertSeverity": "critical",
  "checkVulnerabilities": true,
  "checkTls": true,
  "includeRawNormalizedSnapshot": false,
  "requestTimeoutSeconds": 3,
  "maxRetries": 2,
  "concurrency": 1,
  "dryRun": true,
  "allowHttp": false,
  "allowPrivateNetwork": false,
  "maxResponseBytes": 16384
}
```

# Actor output Schema

## `reports` (type: `string`):

One structured, redacted monitoring report per enabled server in the default Dataset.

## `trustedBaselines` (type: `string`):

Trusted normalized baseline records created only by an explicitly selected mutating mode or exact candidate promotion.

## `candidateBaselines` (type: `string`):

Candidate normalized baseline records retained for review until replaced by an ordinary candidate-writing run or consumed by a successful exact-lineage promotion.

# 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": [
        {
            "name": "public-mcp-fixture-smoke",
            "url": "https://raw.githubusercontent.com/erenmyeager15/mcp-trust-rug-pull-monitor/master/src/__fixtures__/mcp-manifest.json",
            "transport": "static_json",
            "enabled": true,
            "tags": [
                "public-demo"
            ]
        }
    ],
    "authorizedUseConfirmed": true,
    "baselineMode": "compare_only",
    "promoteCandidateBaseline": false,
    "minimumAlertSeverity": "critical",
    "checkVulnerabilities": false,
    "checkTls": false,
    "includeRawNormalizedSnapshot": false,
    "requestTimeoutSeconds": 3,
    "maxRetries": 0,
    "concurrency": 1,
    "dryRun": true,
    "allowHttp": false,
    "allowPrivateNetwork": false,
    "maxResponseBytes": 16384
};

// Run the Actor and wait for it to finish
const run = await client.actor("fascinating_lentil/mcp-trust-rug-pull-monitor").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": [{
            "name": "public-mcp-fixture-smoke",
            "url": "https://raw.githubusercontent.com/erenmyeager15/mcp-trust-rug-pull-monitor/master/src/__fixtures__/mcp-manifest.json",
            "transport": "static_json",
            "enabled": True,
            "tags": ["public-demo"],
        }],
    "authorizedUseConfirmed": True,
    "baselineMode": "compare_only",
    "promoteCandidateBaseline": False,
    "minimumAlertSeverity": "critical",
    "checkVulnerabilities": False,
    "checkTls": False,
    "includeRawNormalizedSnapshot": False,
    "requestTimeoutSeconds": 3,
    "maxRetries": 0,
    "concurrency": 1,
    "dryRun": True,
    "allowHttp": False,
    "allowPrivateNetwork": False,
    "maxResponseBytes": 16384,
}

# Run the Actor and wait for it to finish
run = client.actor("fascinating_lentil/mcp-trust-rug-pull-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    {
      "name": "public-mcp-fixture-smoke",
      "url": "https://raw.githubusercontent.com/erenmyeager15/mcp-trust-rug-pull-monitor/master/src/__fixtures__/mcp-manifest.json",
      "transport": "static_json",
      "enabled": true,
      "tags": [
        "public-demo"
      ]
    }
  ],
  "authorizedUseConfirmed": true,
  "baselineMode": "compare_only",
  "promoteCandidateBaseline": false,
  "minimumAlertSeverity": "critical",
  "checkVulnerabilities": false,
  "checkTls": false,
  "includeRawNormalizedSnapshot": false,
  "requestTimeoutSeconds": 3,
  "maxRetries": 0,
  "concurrency": 1,
  "dryRun": true,
  "allowHttp": false,
  "allowPrivateNetwork": false,
  "maxResponseBytes": 16384
}' |
apify call fascinating_lentil/mcp-trust-rug-pull-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=fascinating_lentil/mcp-trust-rug-pull-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "MCP Trust & Rug-Pull Monitor",
        "description": "Monitor authorized public MCP servers for tool, schema, permission, package, TLS, and behavioral drift. Detect suspicious changes, preserve trusted baselines, and quarantine risky updates for manual approval.",
        "version": "1.0",
        "x-build-id": "rj1uEHomoqahFvHvi"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/fascinating_lentil~mcp-trust-rug-pull-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-fascinating_lentil-mcp-trust-rug-pull-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/fascinating_lentil~mcp-trust-rug-pull-monitor/runs": {
            "post": {
                "operationId": "runs-sync-fascinating_lentil-mcp-trust-rug-pull-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/fascinating_lentil~mcp-trust-rug-pull-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-fascinating_lentil-mcp-trust-rug-pull-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "servers",
                    "authorizedUseConfirmed"
                ],
                "properties": {
                    "servers": {
                        "title": "Authorized MCP servers",
                        "minItems": 1,
                        "maxItems": 25,
                        "type": "array",
                        "description": "One to 25 public MCP metadata endpoints that you own, are authorized to inspect, or that intentionally expose public metadata. Disabled entries count toward the 25-entry limit.",
                        "items": {
                            "type": "object",
                            "additionalProperties": false,
                            "properties": {
                                "name": {
                                    "title": "Server name",
                                    "type": "string",
                                    "description": "Stable human-readable server name used with the endpoint URL to derive baseline keys.",
                                    "editor": "textfield",
                                    "minLength": 1,
                                    "maxLength": 128,
                                    "pattern": ".*\\S.*"
                                },
                                "url": {
                                    "title": "Metadata endpoint URL",
                                    "type": "string",
                                    "description": "Absolute HTTP(S) MCP metadata URL without URL credentials, fragments, or credential-shaped query parameters. HTTPS is required unless allowHttp is explicitly enabled.",
                                    "editor": "textfield",
                                    "minLength": 8,
                                    "maxLength": 10000,
                                    "pattern": "^https?:\\/\\/[^\\s]+$"
                                },
                                "transport": {
                                    "title": "Transport",
                                    "type": "string",
                                    "description": "Metadata discovery transport. auto tries bounded hosted transports; http_sse is recognized but intentionally returns unsupported_transport in this release.",
                                    "editor": "select",
                                    "default": "auto",
                                    "enum": [
                                        "auto",
                                        "streamable_http",
                                        "http_sse",
                                        "static_json"
                                    ],
                                    "enumTitles": [
                                        "Auto detect",
                                        "Streamable HTTP",
                                        "Legacy HTTP/SSE (unsupported)",
                                        "Static JSON manifest"
                                    ]
                                },
                                "enabled": {
                                    "title": "Enabled",
                                    "type": "boolean",
                                    "description": "When false, keep this configured server in the input without inspecting it during this run.",
                                    "default": true
                                },
                                "tags": {
                                    "title": "Tags",
                                    "type": "array",
                                    "description": "Optional labels for organizing this server. Up to 20 non-empty labels of at most 128 characters each are accepted.",
                                    "editor": "stringList",
                                    "maxItems": 20,
                                    "items": {
                                        "type": "string",
                                        "minLength": 1,
                                        "maxLength": 128,
                                        "pattern": ".*\\S.*"
                                    }
                                },
                                "headers": {
                                    "title": "Secret request headers",
                                    "type": "object",
                                    "description": "Optional authorized request headers. The containing servers array is encrypted as secret Actor input, covering this entire object. Values must be non-empty, contain no line breaks, and be at most 4096 characters; total header names and values are limited to 8192 bytes at runtime. Host, connection, length, transfer, upgrade, proxy, TE, and trailer headers are rejected. Never put secrets in URLs, tags, or names.",
                                    "editor": "json",
                                    "maxProperties": 64,
                                    "patternKey": "^[!#$%&'*+.^_`|~0-9A-Za-z-]{1,128}$",
                                    "patternValue": "^[^\\r\\n]{1,4096}$",
                                    "additionalProperties": true
                                }
                            },
                            "required": [
                                "name",
                                "url"
                            ]
                        }
                    },
                    "authorizedUseConfirmed": {
                        "title": "Authorization attestation",
                        "type": "boolean",
                        "description": "Required. Set true only when every target intentionally exposes public metadata, belongs to you, or you have explicit permission to inspect it. False is rejected by the Actor.",
                        "default": false
                    },
                    "baselineKeyValueStoreId": {
                        "title": "Persistent baseline key-value store",
                        "type": "string",
                        "description": "Optional persistent Key-Value Store for trusted and candidate baselines. Required together with a baseline Request Queue for non-dry-run initialization, update, or promotion. Reuse the same selected stores across scheduled runs."
                    },
                    "baselineRequestQueueId": {
                        "title": "Persistent baseline lock queue",
                        "type": "string",
                        "description": "Optional persistent Request Queue used only for atomic baseline mutation locks. Required together with the baseline Key-Value Store for non-dry-run initialization, update, or promotion."
                    },
                    "baselineMode": {
                        "title": "Baseline mode",
                        "enum": [
                            "initialize_only",
                            "compare_only",
                            "compare_and_update",
                            "manual_approval"
                        ],
                        "type": "string",
                        "description": "Controls trusted baseline persistence. The safe default compare_only never creates or updates a trusted baseline. Choose a mutating mode only after reviewing the endpoint and persistence behavior.",
                        "default": "compare_only"
                    },
                    "promoteCandidateBaseline": {
                        "title": "Promote matching candidate",
                        "type": "boolean",
                        "description": "When true, promote and consume a compatible stored candidate only if its endpoint identity, current snapshot hash, and exact trusted-parent hash (or explicit no-parent state) match the current state. Any mismatch returns promotion_mismatch and preserves both records.",
                        "default": false
                    },
                    "minimumAlertSeverity": {
                        "title": "Minimum webhook severity",
                        "enum": [
                            "informational",
                            "low",
                            "medium",
                            "high",
                            "critical"
                        ],
                        "type": "string",
                        "description": "Lowest report severity eligible for the optional webhook. Status-specific alert rules still apply, and webhook delivery occurs only after Dataset persistence succeeds.",
                        "default": "medium"
                    },
                    "webhookUrl": {
                        "title": "Alert webhook URL",
                        "pattern": "^https:\\/\\/[^\\s]+$",
                        "minLength": 9,
                        "maxLength": 2048,
                        "type": "string",
                        "description": "Optional public HTTPS webhook URL without URL credentials. Do not include tokens or other secrets in the URL."
                    },
                    "checkVulnerabilities": {
                        "title": "Check OSV vulnerabilities",
                        "type": "boolean",
                        "description": "Query the public OSV API only for package identities and versions explicitly exposed by server metadata. Unavailable lookups are reported without fabricating matches.",
                        "default": true
                    },
                    "checkTls": {
                        "title": "Inspect TLS metadata",
                        "type": "boolean",
                        "description": "Inspect HTTPS certificate validity, hostname, expiry, and negotiated protocol metadata before the MCP metadata request.",
                        "default": true
                    },
                    "includeRawNormalizedSnapshot": {
                        "title": "Include normalized snapshot",
                        "type": "boolean",
                        "description": "Include the redacted canonical metadata snapshot in each Dataset report. Leave disabled unless downstream review requires the larger payload.",
                        "default": false
                    },
                    "requestTimeoutSeconds": {
                        "title": "Request timeout",
                        "minimum": 1,
                        "maximum": 120,
                        "type": "integer",
                        "description": "Timeout for each bounded network operation, from 1 to 120 seconds. A separate per-server wall-clock limit also applies.",
                        "default": 20
                    },
                    "maxRetries": {
                        "title": "Maximum retries",
                        "minimum": 0,
                        "maximum": 4,
                        "type": "integer",
                        "description": "Maximum retry count for eligible metadata requests, from zero to four. Authentication and other terminal failures are not retried indefinitely.",
                        "default": 2
                    },
                    "concurrency": {
                        "title": "Server concurrency",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Number of enabled servers inspected concurrently, from one to ten.",
                        "default": 5
                    },
                    "dryRun": {
                        "title": "Dry run",
                        "type": "boolean",
                        "description": "Inspect and compare without creating, updating, promoting, or replacing trusted or candidate baseline records.",
                        "default": false
                    },
                    "allowHttp": {
                        "title": "Allow plain HTTP",
                        "type": "boolean",
                        "description": "Explicitly opt in to public plain-HTTP targets. Disabled by default because HTTP provides no transport confidentiality or certificate validation.",
                        "default": false
                    },
                    "allowPrivateNetwork": {
                        "title": "Allow private networks",
                        "type": "boolean",
                        "description": "Reserved compatibility field that must remain false. Private, loopback, link-local, metadata-service, local-file, Unix-socket, and stdio targets are unsupported by this hosted Actor.",
                        "default": false
                    },
                    "maxResponseBytes": {
                        "title": "Maximum metadata response size",
                        "minimum": 16384,
                        "maximum": 5242880,
                        "type": "integer",
                        "description": "Maximum accepted metadata response body size, from 16 KiB to 5 MiB. Oversized or incomplete responses never update a trusted baseline.",
                        "default": 1048576
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
