Feranor

Consulting

Feranor Resilience MCP

An MCP server that runs a resilience check on any public domain and returns a scored report: TLS certificate, security headers, DNS redundancy, and response time, with every individual finding it was able to measure.

Built for agents that check domains repeatedly and unattended, not for a single manual look. For one manual check, use the free web version at feranor.com/check.

At a glance

  • Endpoint

    https://www.feranor.com/mcp

  • Transport

    Streamable HTTP

  • Price

    Free triage, $0.01 per full report, from $0.005 per domain in batch

  • Payment

    x402, USDC on Base (eip155:8453)

  • Signup

    None. No account, no API key, no dashboard.

  • Free

    initialize, tools/list, domain_check_score_v1, and domain_check_score_batch_v1.

You do not create anything to use this server. You point a client at the URL, and the first paid call returns a payment challenge your x402-capable client settles automatically. If your client cannot pay, everything except the paid tools still works.

Try it without paying

tools/list is free and needs no client setup. This is the fastest way to confirm the server is reachable and see the current catalogue:

curl -sS https://www.feranor.com/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Each tool carries its price in two places: in plain text at the end of its description, and machine-readable under _meta["x-x402"]. You can therefore budget a task before committing to any call.

Add it to your client

Claude Code
claude mcp add --transport http feranor https://www.feranor.com/mcp

Scoped to the current project by default. For every project:

claude mcp add --transport http --scope user feranor https://www.feranor.com/mcp

Confirm with claude mcp list, then /mcp inside a session.

Cursor

~/.cursor/mcp.json for all projects, or .cursor/mcp.json in a repository:

{
  "mcpServers": {
    "feranor": {
      "url": "https://www.feranor.com/mcp"
    }
  }
}
VS Code

.vscode/mcp.json in the workspace root. Note the root key is servers, not mcpServers, and type must be present:

{
  "servers": {
    "feranor": {
      "type": "http",
      "url": "https://www.feranor.com/mcp"
    }
  }
}

MCP tools are only available in Copilot Chat agent mode.

Shared with your team

.mcp.json at the repository root, committed to git:

{
  "mcpServers": {
    "feranor": {
      "type": "http",
      "url": "https://www.feranor.com/mcp"
    }
  }
}
Any other client

Point it at https://www.feranor.com/mcp over streamable HTTP. There is no authentication step, no OAuth flow, and no token to provision.

The tools

text_scan_v1

Price free.

Scans a text string for invisible Unicode characters, homoglyphs, and normalization issues. Returns a risk score, a list of flagged characters, and detected homoglyphs. Never modifies the input text.

{ "text": "Hello​World" }

Detects zero-width characters, BOM, variation selectors, tag characters, bidi controls, and Cyrillic/Greek homoglyphs. Also checks whether the text is in NFC normalization form. The intended path: run text_scan_v1 first to see what is wrong, then call text_purge_v1 to fix it.

text_purge_v1

Price $0.01 per call.

{ "text": "Hello​World" }

Strips zero-width characters, variation selectors, tag characters, and bidi controls. Replaces Cyrillic and Greek homoglyphs with their Latin equivalent. Normalizes the output to NFC.

domain_check_score_v1

Price free.

Overall score, per-category scores, and how many findings each category raised.

Use it to triage: rank a list of domains, confirm one is healthy, or decide whether the full report is worth pulling. It tells you which categories are weak and how many issues they hold, but not what the issues are.

Input

{ "domain": "example.com" }

Output

{
  "domain": "example.com",
  "score": 52,
  "measuredCategories": 5,
  "evaluatedAt": "2026-08-01T00:00:00Z",
  "detailsAvailableVia": "domain_check_v1",
  "categories": [
    { "name": "Transport",        "score": 40,  "findingCount": 2 },
    { "name": "Performance",      "score": 67,  "findingCount": 1 },
    { "name": "Security headers", "score": 0,   "findingCount": 4 },
    { "name": "Infrastructure",   "score": 100, "findingCount": 0 },
    { "name": "Hygiene",          "score": 100, "findingCount": 0 }
  ]
}
domain_check_score_batch_v1

Price free.

The same triage scores for up to 100 domains in a single call. One score summary per distinct domain: overall score, per-category scores, and how many findings each category raised. Never the findings themselves.

Input

{ "domains": ["example.com", "example.org", "www.example.net"] }

Between 1 and 100 entries. Duplicates are removed. A domain that cannot be reached is returned with its own error rather than failing the batch.

Output

{
  "requested": 3,
  "evaluated": 2,
  "succeeded": 2,
  "evaluatedAt": "2026-08-10T09:14:22Z",
  "results": [
    {
      "domain": "example.com",
      "summary": {
        "domain": "example.com",
        "score": 52,
        "measuredCategories": 5,
        "evaluatedAt": "2026-08-10T09:14:22Z",
        "detailsAvailableVia": "domain_check_batch_v1",
        "categories": [
          { "name": "Transport",        "score": 40,  "findingCount": 2 },
          { "name": "Performance",      "score": 67,  "findingCount": 1 },
          { "name": "Security headers", "score": 0,   "findingCount": 4 },
          { "name": "Infrastructure",   "score": 100, "findingCount": 0 },
          { "name": "Hygiene",          "score": 100, "findingCount": 0 }
        ]
      }
    },
    {
      "domain": "example.org",
      "summary": {
        "domain": "example.org",
        "score": 91,
        "measuredCategories": 5,
        "evaluatedAt": "2026-08-10T09:14:22Z",
        "detailsAvailableVia": "domain_check_batch_v1",
        "categories": [
          { "name": "Transport",        "score": 100, "findingCount": 0 },
          { "name": "Performance",      "score": 100, "findingCount": 0 },
          { "name": "Security headers", "score": 70,  "findingCount": 1 },
          { "name": "Infrastructure",   "score": 100, "findingCount": 0 },
          { "name": "Hygiene",          "score": 80,  "findingCount": 1 }
        ]
      }
    },
    {
      "domain": "unreachable.invalid",
      "error": "Host could not be resolved."
    }
  ]
}

The intended path: rank a portfolio here for free, then pull `domain_check_batch_v1` on the domains that need attention.

domain_check_v1

Price $0.01 per call.

The full report for one domain: the same score plus every individual finding, grouped by category, with a prioritised remediation order.

Input

{ "domain": "example.com" }

A bare domain. Scheme and path are ignored if present.

Output

{
  "domain": "example.com",
  "requestedDomain": "example.com",
  "score": 52,
  "evaluatedAt": "2026-08-01T00:00:00Z",
  "checks": [
    {
      "id": "tls.certificate",
      "category": "Transport",
      "label": "TLS Certificate",
      "weight": 12,
      "earned": 12,
      "status": "Ok",
      "message": "Certificate valid for another 84 days, protocol negotiated Tls13."
    },
    {
      "id": "headers.hsts",
      "category": "Transport",
      "label": "HSTS",
      "weight": 10,
      "earned": 0,
      "status": "Critical",
      "message": "No Strict-Transport-Security: the initial visit remains interceptable."
    },
    {
      "id": "perf.response-time",
      "category": "Performance",
      "label": "Response time",
      "weight": 10,
      "earned": 10,
      "status": "Ok",
      "message": "Root reached in 159 ms."
    },
    {
      "id": "headers.nosniff",
      "category": "Security headers",
      "label": "X-Content-Type-Options",
      "weight": 5,
      "earned": 0,
      "status": "Warning",
      "message": "Missing X-Content-Type-Options."
    },
    {
      "id": "infra.cdn",
      "category": "Infrastructure",
      "label": "Front-end CDN",
      "weight": 6,
      "earned": 6,
      "status": "Ok",
      "message": "CDN detected (hint: cf-ray)."
    },
    {
      "id": "hygiene.directory-listing",
      "category": "Hygiene",
      "label": "Directory listing",
      "weight": 5,
      "earned": 0,
      "status": "Unknown",
      "message": "No folder derivable from the root: not evaluated."
    }
  ]
}
domain_check_batch_v1

Price from $0.005 per domain.

The same full report for up to 100 domains in a single call, with one payment for the whole batch instead of one per domain. Both cheaper per domain and much faster than calling domain_check_v1 in a loop.

Volume tiers

Domains Price per domain Example total
1 $0.010 $0.010
2 to 9 $0.008 5 domains: $0.040
10 to 49 $0.007 10 domains: $0.070
50 to 99 $0.006 50 domains: $0.300
100 $0.005 100 domains: $0.500

The unit price is the lowest tier the quantity qualifies for. Duplicates are removed before billing. For a single domain, domain_check_v1 costs the same and is simpler.

Input

{ "domains": ["example.com", "example.org", "www.example.net"] }

Between 1 and 100 entries. A request above 100 is rejected rather than truncated, so you never receive a partial report without knowing it.

Output

One entry per distinct domain. A domain that cannot be reached is returned with its own error rather than failing the batch, and it is still billed, because the crawl was attempted. This is deliberate and differs from the single-domain tool, where a failed check is not charged.

{
  "requested": 3,
  "evaluated": 3,
  "succeeded": 2,
  "evaluatedAt": "2026-08-01T00:00:00Z",
  "results": [
    {
      "domain": "example.com",
      "report": {
        "domain": "example.com",
        "score": 52,
        "checks": [
          {
            "id": "tls.certificate",
            "category": "Transport",
            "label": "TLS Certificate",
            "weight": 12,
            "earned": 12,
            "status": "Ok",
            "message": "Certificate valid for another 84 days, protocol negotiated Tls13."
          }
        ]
      }
    },
    {
      "domain": "example.org",
      "report": {
        "domain": "example.org",
        "score": 91,
        "checks": []
      }
    },
    {
      "domain": "unreachable.invalid",
      "error": "Host could not be resolved."
    }
  ]
}
How the score works

The score is measured only on what could actually be read from outside. A category that could not be observed is excluded from the denominator rather than counted as a failure, so a domain behind a WAF that blocks the probe gets a partial score over fewer categories, not a bad score. Compare two domains only when the number of measured categories matches.

Everything is read from the public internet. Nothing is authenticated, no ports are scanned, and no credentials are needed. The crawler identifies itself as FeranorBot and honours robots.txt. See the FeranorBot page to identify or block it.

Paying

The server uses x402: payment happens in the HTTP exchange itself, with no account in between.

The sequence, which an x402-capable client performs on its own:

1. Your client calls the tool with no payment attached.

2. The server answers 402 with the exact amount, asset, network, and recipient. For a batch, the amount reflects the number of distinct domains and the tier applied.

3. Your client signs a USDC transfer authorization and repeats the call.

4. The server verifies, runs the check, settles, and returns the report.

Header conventions. Both are accepted on the way in, PAYMENT-SIGNATURE and X-PAYMENT, and both are emitted on the way out. If your x402 client library predates the v2 transport naming, it will still work.

Receipt. The settlement receipt comes back two ways: base64 in the PAYMENT-RESPONSE header for x402 clients, and in decoded short form under the result's _meta["x-x402-receipt"] for MCP clients that never see response headers. It carries the transaction hash, so you can reconcile spend on-chain.

What you are charged for. Only successful checks, with one deliberate exception: in a batch, a domain that could not be reached is still billed, because the crawl was attempted. If the tool itself fails, or if settlement does not complete, nothing is charged and no report is returned. Retrying a call with the same payment returns the report you already paid for rather than charging twice.

Batch amounts are recomputed identically. The challenge and the paid retry carry the same arguments, so the total is the same. If you clean your list of duplicates between the two, the amount still matches, because duplicates were never billed.

Errors

The status code tells you whose problem it is.

Status Meaning What to do
402 Payment missing, malformed, or not matching the offer Read the error field. It names the exact mismatch.
405 Method not allowed, use POST only Nothing was charged. Fix and retry shortly.
406 Not acceptable, body may be unreadable Nothing was charged. Fix and retry shortly.
429 Rate limit Back off for the delay in Retry-After.
502 Our payment infrastructure is unavailable Nothing was charged. Retry shortly.

A request that is invalid rather than unpaid, such as an empty list or more than 100 domains, comes back as a tool error, not a 402. Paying would not fix it.

Common causes of a repeated 402:

  • Wrong network.

    The offer is Base mainnet, eip155:8453. A payload signed for another chain, including Base Sepolia eip155:84532, is rejected.

  • Amount below the offer.

    A signature over a smaller amount is a valid signature over the wrong amount. The error field states the expected atomic value.

  • Wrong asset or recipient.

    Both are published in the challenge and in the server card.

  • Authorization window expired.

    Sign a fresh one.

If you loop on 402 without a useful error, that is a bug on our side, please tell us.

Discovery

For registries, crawlers, and agents that resolve servers from a domain:

  • Server card: https://www.feranor.com/.well-known/mcp.json
  • Enumeration: https://www.feranor.com/.well-known/mcp
  • Site catalogue: https://www.feranor.com/llms.txt
  • MCP Registry: com.feranor/resilience

Contact

Questions, bug reports, or a check you wish existed: contact us.

Feranor is a distributed systems architecture and governance practice based in Lyon, France. About the practice.