Skip to content

AR-ACT-04: where is a server card resolved from when the MCP endpoint is at a sub-path? #7

Description

@ernanibmurtinho

Summary

AR-ACT-04 says a server card MAY be shipped for pre-connection discovery, and notes the path is still moving. It does not say what the card is resolved relative to.

For a host that serves one MCP endpoint at the origin this never comes up. For a host that mounts several surfaces at sub-paths — /{surface}/mcp — there are two defensible readings, and they disagree. We hit the disagreement on a conformant deployment: a complete card at the origin was reported absent when the evaluated URL was the sub-path endpoint.

We think the spec should say which reading is normative. RFC 8615 already implies the answer, and making it explicit costs one sentence.

Evidence

Reproducible as of 2026-09-04.

The card is served at the origin, and it carries every field AR-ACT-04 asks for:

curl -s https://mcp.geckovision.tech/.well-known/mcp/server-card.json
→ 200 application/json
  name, title, description, version, protocolVersion,
  serverUrl, authentication, tools[], icon, iconUrl, websiteUrl, remotes[]

Resolved relative to the MCP endpoint path instead, nothing is there — correctly, because nothing should be:

curl -s -o /dev/null -w '%{http_code}\n' \
  https://mcp.geckovision.tech/orquestra/mcp/.well-known/mcp/server-card.json
→ 404

curl -s -o /dev/null -w '%{http_code}\n' \
  https://mcp.geckovision.tech/orquestra/.well-known/mcp/server-card.json
→ 404

An AgentReady evaluation of https://mcp.geckovision.tech/orquestra/mcp reported
No MCP server card found at /.well-known/mcp/server-card.json, and separately
No registry branding (name, icon, description) found — while the card above carries
title, description, icon and iconUrl.

Why we think origin is the right reading

RFC 8615 defines /.well-known/ as a path
prefix at the root of an origin. A .well-known segment nested under an arbitrary
path is not a well-known URI in the RFC's sense. So an evaluator that probes
<endpoint-path>/.well-known/... is looking somewhere the standard it cites does not
place the resource, and a publisher who put the file there would be non-conformant.

This matters more as multi-surface hosts become common: one host, many MCP endpoints,
one card describing the host with a remotes[] array naming each. That shape is
already how several gateways and proxies serve MCP, and under an endpoint-relative
reading every one of them reads as "no card".

Proposed change

A normative note under AR-ACT-04, roughly:

A server card is a well-known resource and MUST be resolved at the origin of the
MCP endpoint (https://host/.well-known/mcp/server-card.json), per RFC 8615, not
relative to the endpoint's path. A host serving several MCP endpoints SHOULD
publish one card at the origin and enumerate its endpoints, rather than one card per
path. Evaluators MUST probe the origin.

Happy to open a PR with the wording if the direction is right.

A related question, if it is in scope

Three other properties of the same endpoint were reported absent where they are present.
All 16 tools carry behavioural annotations:

submit_transaction   readOnlyHint: false, destructiveHint: true   ← the only destructive tool
try_purchase         readOnlyHint: false, destructiveHint: false  ← signs only on a local fork
(14 others)          readOnlyHint: true,  destructiveHint: false

and an invalid tool call already returns a structured error:

{"code": -32602, "message": "Unknown tool: '…'. This surface serves: <all 16 names>"}

We are not raising these as evaluator bugs here — that is the wrong venue, and the
resolution question above may explain some of them. The spec-level question they raise
is different, and we think it is worth asking directly:

Should the spec place any requirement on evaluation itself — specifically, that an
evaluator distinguish "the property is absent" from "the property was not measured"?

Today the spec defines what a product must publish, and the dataset makes the
measurements reproducible, which is more rigour than most standards carry. But nothing
in the conformance section constrains what a score may claim when a probe fails to reach
the thing it is scoring. A report that says "absent" when it means "not reached" is
indistinguishable, to a reader, from a real finding.

We have hit this from the implementer side repeatedly and think it generalises. Three
recent cases from our own checker, all fixed:

  • a single-page app answering 200 + index.html for every path was credited with an
    llms.txt and an llms-full.txt it did not have — a fabricated pass;
  • a spec behind an API key returned 401 and was scored as a malformed spec — a
    fabricated fail, on exactly the paywalled APIs the agentic web most needs graded;
  • a marketing site with no docs routes was graded against a documentation rubric and
    scored as though its documentation were poor, when its documentation is on another host.

In each the number was arithmetically consistent and describing nothing. The cheap
general form of the fix is that a check which could not be evaluated is reported as
not_evaluated and excluded from the denominator, so a score always carries how much of
it was actually measured.

If that is out of scope for this document we will drop it and keep this issue to the
resolution question.

Context

We build an API/MCP comprehension layer and run our own agent-readiness checks, so we
come to this as implementers of the same ideas rather than as a neutral party — worth
stating plainly. The AgentReady datasets are the main reason we are engaging: publishing
the traces so anyone can reproduce or challenge them is the right way to do this, and the
find/read/act split has held up well against what we see.

Where we think we can contribute measurements rather than opinions is the act stage on
non-website surfaces — OpenAPI and MCP endpoints specifically, where our own probing is
concentrated. Happy to write that up separately if there is appetite.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions