ax-check rule

AXC-F002: Claimed URL could not be verified

A URL returned an access-denied, rate-limit or server error, or timed out, so it could not be verified.

ax-check is a checker being prepared for release. This page documents the rule ahead of that release; see all 50 rules.

Severityinfo
KindObserved. Depends on the program and environment at run time.
Modeax-check drift
Applies toInstruction files and manifests
Pattern tagsdrift, docs-for-agents
Fix in one lineCheck the URL by hand; if agents are blocked there, link a page they can read.

A URL in the file answered with an access-denied response, a rate-limit response or a server error, or it timed out. ax-check could not tell whether the page is fine, so it reports the URL as inconclusive. This is not a defect finding.

What it checks

For each URL, ax-check looks at the HTTP status code that comes back. This rule fires on:

  • any status other than success, redirect, 404 or 410, such as 401 or 403 (access denied), 429 (too many requests) or a 5xx (server error),
  • an answer of 405 (method not allowed) to GET. The message reads “endpoint rejects GET; this is normal for Streamable HTTP MCP servers”. A server that only accepts POST is not broken, so this is never reported as AXC-F001,
  • a timeout, or any other failure to fetch that is not a DNS failure,
  • a URL that was skipped because the cap on URLs was reached (raise it with --max-urls),
  • an npm or PyPI lookup that failed with anything other than “not found” (for example a 5xx or a network error). The package could not be checked, so it is not reported as missing.

An MCP endpoint is the exception that passes. For a URL whose path ends in /mcp (this also covers /api/mcp), or that is the --mcp target, ax-check sends one POST initialize request when GET is rejected with 405. If the server answers it with a JSON-RPC result, the URL counts as verified and nothing is reported. If it does not, the finding is this rule, and the message adds that the POST initialize did not succeed and why. ax-check sends no other request, and never calls a tool.

A 404, a 410 or a failed DNS lookup is a different case and belongs to AXC-F001.

Why it matters

These responses say very little about the page. A 403 may mean the page needs a login, or that the site blocks automated clients. A 429 means the checker asked too often. A 5xx or a timeout may last only a few minutes. In none of these cases can anyone say the link is wrong.

Reporting them as errors would produce false alarms. ax-check follows the same convention as the agentexperience.tech audit_agent_path diagnostic: a failure to fetch is reported as inconclusive, not as a defect. The finding is still worth reading, because a page that blocks automated clients is also a page an agent cannot read. If the file tells agents to use it, they will hit the same wall.

How to fix

  • Open the URL by hand and check that it works.
  • If the page is public but blocks automated clients, change the site’s rules, or link to a page that agents can read.
  • If the page needs a login on purpose, say so in the file, and do not rely on it as the only source of the information.
  • If the server was only briefly down, run the check again later.

Example

Find it:

ax-check drift --online AGENTS.md

Before

## Where to look

- Style rules: https://wiki.invoicekit.dev/style (members only)
- API reference: https://docs.invoicekit.dev/api

The wiki page answers 403 to anyone who is not signed in. ax-check reports it as inconclusive.

After

## Where to look

- Style rules: see `docs/style.md` in this repository
- API reference: https://docs.invoicekit.dev/api

How ax-check detects it

The rule uses the same request as AXC-F001: HEAD first, then GET before judging if HEAD returned 403, 404, 405, 501 or a 5xx, one request at a time per host, a 500 millisecond gap, a 10 second timeout (--timeout) and a cap of 200 URLs (--max-urls). If the final answer is neither success, 404 nor 410, or the request timed out or failed for a reason other than DNS, this rule fires with severity info. A registry lookup for AXC-F003 or AXC-F004 that fails with anything but 404 is reported here too.

For a 405 the final answer after HEAD and GET decides. The message is the same for every URL, because a 405 says only that the method is not accepted: “endpoint rejects GET; this is normal for Streamable HTTP MCP servers (HTTP 405), so it could not be verified”. An endpoint that looks like MCP and fails the POST initialize gets a longer message that includes the reason.

The rule never says the link is broken. It says ax-check could not find out.

Known limits:

  • A site that rate-limits after a few requests may return 429 for some URLs and 200 for others in the same run.
  • Only URLs that look like MCP endpoints get the POST initialize probe. An MCP server at another path passes only when it is the --mcp target; otherwise it is reported here as inconclusive.
  • The --header values are sent only to the --mcp target, never to other URLs.
  • A site that serves a bot-check page with status 200 is not detected.

Without --online this rule does not run. To silence it, use ax-check drift --online --disable AXC-F002 AGENTS.md, for example when you know a link is private by design.

Sources

Records in the AX evidence register that share a pattern tag with this rule. A shared tag means the record is about the same pattern, not that it tests this rule. Read the evidence class before the number.