Skip to content
AutomotiveMCP
Spec§11DraftRFC / v0.1

Federation

How one request reaches several independent servers and locations, and comes back with every item attributable, every failure visible, and no token used where it was not issued. Draft, and deliberately domain-neutral.


Draft. This section is a working draft, published for comment. Its MUST and SHOULD language states what the working group intends, but it is not yet a conformance requirement, and it may change incompatibly before it is. Do not claim conformance with it. If you build against it, tell the working group what broke: that is the evidence that moves a draft.

This section is written in domain-neutral terms. It describes parties, locations and servers rather than dealer groups, rooftops and DMS platforms, because the problem is not specific to retail automotive. Automotive appears only in the examples.

It profiles the 2026-07-28 revision of the Model Context Protocol and adds nothing to the base protocol. Every mechanism below is either a constraint on something MCP already defines (request metadata headers, x-mcp-header, the token pass-through prohibition) or a field carried inside a tool result. It is published as the candidate extension io.automotivemcp/federation.

11.1 The problem

One request often has to reach more than one system. An agent asked to find a vehicle "near me" reads inventory at several businesses. A group that operates several locations runs them on several servers, sometimes from different vendors. A single platform hosts many unrelated tenants behind one endpoint.

Each of those is easy on its own. What is not specified anywhere is what the combined answer looks like: how a location is named so that two servers mean the same one, where each item came from, what the caller is told when one of five systems does not answer, and how the system doing the fanning out gets permission to call the others without reusing a token that was never meant for them.

Without those rules every aggregator invents its own, and the caller cannot tell a complete answer from a partial one, or a figure from the business that owns it from one an intermediary rewrote.

11.2 Terms

TermMeaning
LocationOne operating unit that holds its own data and makes its own commitments: a store, a branch, a clinic. In retail automotive, a rooftop. It is the tenant of §3.2.
GroupA set of locations under common control. A group is a label, never a tenant (§11.3.3).
Member serverAn MCP server that is authoritative for the data of one or more locations.
Federating serverAn MCP server that answers a request by calling one or more member servers and combining their results. It is a member server's client.
SourceThe member server that produced a given item, named by its canonical server URI (§11.6).

A server can be a member for its own locations and a federating server for others at the same time. The rules below apply per request, by role.

11.3 Location identity

11.3.1 The identifier

Every location MUST have a location identifier, location_id, with these properties:

  • It MUST be an absolute https URI. Its origin is the authority: the party that assigned the identifier and answers for it.
  • It MUST be stable. A location keeps its identifier when it is renamed, changes systems, or changes ownership. An authority MUST NOT reassign a retired identifier to a different location.
  • It MUST NOT contain personal data, and SHOULD NOT contain anything a reader would take as a commercial secret (internal account numbers, contract identifiers).
  • Two identifiers are equal only when they are identical strings. Implementations MUST NOT normalize, case-fold or resolve them before comparing.
https://locations.example-platform.com/l/4f1c9a
https://group.example-motors.com/locations/north-austin

The dealership_id of §3.2 is a deprecated alias of location_id. For this version (v0.1), a server MUST accept either name wherever a location is required, MUST treat them as the same identifier, and MUST reject a call that supplies both with different values. Clients SHOULD send location_id. The alias is scheduled for removal in the next MINOR version (v0.2). A member server MAY keep using its own internal identifier inside its own system, but anything that crosses a server boundary, and every provenance record (§11.6), MUST use the location_id.

11.3.2 Same location, several authorities

A location will often be known to several systems, each of which assigned its own identifier. An authority MAY publish that two identifiers denote the same location through an alias_of link on its location record. A federating server MAY use an alias to route, but MUST report the identifier the source used in provenance, and MUST NOT treat an alias asserted by one authority as binding on another.

Resolving which identifier is canonical when authorities disagree is not specified (§11.11).

11.3.3 Groups are labels, not tenants

A group MAY have a group_id with the same properties as a location_id. A group identifier MUST NOT be accepted where a location is required. A token, a scope or a tool call that names a group MUST be expanded to an explicit set of locations, each authorized separately, before any data is read. This restates §3.2 for the federated case: a group is never a blended tenant.

11.4 Addressing a location on the wire

A tool that operates on a location's data MUST take the location as an argument named location_id, at the top level of its inputSchema, and SHOULD annotate it with "x-mcp-header": "Location".

{
  "name": "inventory.search_vehicles",
  "inputSchema": {
    "type": "object",
    "properties": {
      "location_id": {
        "type": "string",
        "format": "uri",
        "x-mcp-header": "Location"
      },
      "body_style": { "type": "string" }
    },
    "required": ["location_id"]
  }
}

Under the Streamable HTTP transport the client then mirrors the value into an Mcp-Param-Location header alongside the Mcp-Method and Mcp-Name headers MCP already requires. That lets a gateway in front of a multi-tenant server route and rate-limit by location without parsing the body, which is the purpose MCP gives those headers.

Because a gateway may now act on that header, the MCP rules about it are load-bearing here and are restated:

  • The location_id property MUST be reachable from the schema root through properties keys only. MCP invalidates an x-mcp-header annotation under items, oneOf, anyOf, allOf, not, a conditional, or a $ref, and a client will drop the tool.
  • A server that processes the body MUST reject a request whose Mcp-Param-Location does not match the body value with 400 Bad Request and JSON-RPC error -32020 (HeaderMismatch).
  • An intermediary that routes or authorizes by Mcp-Param-Location SHOULD reject a request whose MCP-Protocol-Version predates header and body validation, rather than trust an unvalidated header.
  • Authorization MUST be decided on the location in the body, after validation, and never on the header alone.

A single tool call MUST name exactly one location. A request that needs several locations is several calls, which a federating server issues on the caller's behalf (§11.7).

11.5 Namespacing

Federation does not change tool names. A federating server MUST expose tools under the same domain.verb_object names as §5, and MUST NOT prefix or suffix a tool name with a server, vendor or location to tell members apart. The member is chosen by the location_id argument, not by the name. This keeps Mcp-Name meaningful to every gateway on the path and keeps the catalog at /tools.json the only enumeration of tools.

Identifiers inside results are another matter. A resource id is unique only within its source and location (§3.3). A federating server combining results from several sources:

  • MUST NOT present two items with the same id from different sources as the same item.
  • MUST NOT rewrite a member's id without recording the original in provenance (§11.6).
  • SHOULD let the caller refer back to an item by the pair of its source and its source id, and MUST accept that pair wherever it accepts its own identifier for the item.

Extension data that a member adds beyond the published schemas MUST sit under that member's own reverse-DNS namespace, so that two members' extensions cannot collide in a combined result.

11.6 Provenance

Every item a federating server returns that it did not itself produce MUST carry a provenance object:

FieldRequiredMeaning
sourceMUSTCanonical URI of the member server that produced the item, in the form MCP uses for a server's resource indicator (RFC 8707).
location_idMUSTThe location the item belongs to (§11.3).
source_idMUSTThe item's id as the source issued it.
retrieved_atMUSTWhen the federating server received it, RFC 3339 with an explicit offset.
transformedMUSTtrue if the federating server changed any field other than adding provenance.
viaMAYThe chain of federating servers the item passed through, nearest first, when federation is nested.
{
  "id": "veh_8812",
  "vin": "1HGCV1F3XRA012345",
  "price": { "amount": 3149900, "currency": "USD" },
  "provenance": {
    "source": "https://mcp.example-dms.com",
    "location_id": "https://group.example-motors.com/locations/north-austin",
    "source_id": "veh_8812",
    "retrieved_at": "2026-10-08T14:02:11-05:00",
    "transformed": false
  }
}

The rules that give provenance its value:

  • A federating server MUST NOT present an item as its own when it came from a member.
  • A federating server MUST NOT alter a figure the source committed to (a price, a payment, an availability flag) while leaving transformed false. Where it computes a figure itself, it MUST mark the item transformed, and SHOULD say which fields it computed.
  • An item derived from several sources (a de-duplicated listing, a merged record) MUST carry the provenance of every source it was derived from, as a derived_from array of provenance objects, and MUST be marked transformed.
  • Provenance is not a signature. It records a claim by the federating server. Whether a caller can verify a figure end to end, without trusting the intermediary, is the subject of substantiation (§13) and is not solved here.

11.7 Fan-out and partial failure

11.7.1 Reads

A federating server that answers one call by calling several members MUST return, alongside the items, a federation object describing the outcome at each member:

{
  "items": [],
  "federation": {
    "status": "partial",
    "members": [
      { "source": "https://mcp.example-dms.com",
        "location_id": "https://group.example-motors.com/locations/north-austin",
        "status": "ok", "item_count": 14 },
      { "source": "https://mcp.other-dms.example",
        "location_id": "https://group.example-motors.com/locations/round-rock",
        "status": "timeout", "retryable": true, "retry_after": 30 }
    ]
  }
}
  • status at the top level MUST be complete only when every member the request needed returned ok. It MUST be partial when at least one did and at least one did not, and failed when none did.
  • Each member entry has a status of ok, error, timeout, unauthorized or skipped. skipped means the federating server chose not to call it (a circuit breaker, a policy decision), and MUST be reported, not hidden.
  • A federating server MUST NOT omit a member it was asked to reach, and MUST NOT report ok for a member that returned an error.
  • An empty result and a failed result MUST be distinguishable. ok with an item_count of 0 means the member answered and had nothing.
  • A member's error detail MUST NOT be relayed if it contains personal data (§6.3). A federating server SHOULD map member errors to the structured codes of §6 and the retryable and retry_after fields, and drop the rest.
  • A partial result is a successful MCP response. It MUST NOT be returned as a JSON-RPC error, and a caller MUST NOT treat it as complete.

A federating server SHOULD apply a per-member deadline and return what it has rather than let the slowest member decide the latency of the whole answer. Pagination across members MUST be carried in the single opaque cursor of §3.4, so that the caller never handles a member's cursor directly.

11.7.2 Writes

A tool call that changes state MUST be addressed to exactly one location and MUST be executed by exactly one member. A federating server MUST NOT fan a mutating call out to several members, and MUST NOT emulate a multi-member transaction. There is no partial success for a write in this profile: a write either happened at its one location or it did not.

Where a task genuinely needs changes at several locations (holding a vehicle at one store while booking an appointment at another), the caller issues separate calls and owns the sequence. Compensation across members is not specified. For this version the prohibition is a decision, not an open question: relaxing it later would need a compensation model.

11.8 Calling a member: token exchange

11.8.1 No pass-through

MCP 2026-07-28 is explicit: a server MUST only accept tokens that are valid for use with its own resources and MUST NOT accept or transit any other tokens, and a server that calls an upstream API MUST NOT pass through the token it received from the MCP client. A federating server is exactly that kind of server. It therefore:

  • MUST NOT forward the caller's access token to a member, in any header or argument.
  • MUST NOT call a member on a user's behalf with a standing credential of its own whose authority is broader than the user's. That is the confused deputy MCP warns about, and it is the most likely shortcut a federating implementation will take.
  • MUST obtain, for each member, a separate token whose audience is that member.

11.8.2 The exchange

A federating server obtains a member token with OAuth 2.0 Token Exchange (RFC 8693) at the member's authorization server:

ParameterValue
grant_typeurn:ietf:params:oauth:grant-type:token-exchange
subject_tokenThe access token the federating server received from its caller.
subject_token_typeurn:ietf:params:oauth:token-type:access_token
actor_tokenA credential identifying the federating server itself.
resourceThe member's canonical server URI (RFC 8707).
scopeThe scopes of §6.2 the member call needs, and no more.

The issued token, and the member's validation of it, MUST satisfy all of these:

  • Audience. Its audience is the member, and the member MUST reject it otherwise, exactly as it would any other token.
  • No escalation. Its scopes MUST be a subset of the subject token's, and its locations a subset of the locations the subject token was authorized for. An exchange can only narrow.
  • No outliving. It MUST expire no later than the subject token.
  • Accountability. It MUST carry an act claim (RFC 8693 §4.1) naming the federating server, so the member can record who called on whose behalf. Nested federation produces nested act claims; a member MAY refuse a chain deeper than it is willing to audit.

This requires the member's authorization server to accept subject tokens issued by the caller's authorization server. That trust is configured between the parties and is not specified here. It is the same shape MCP's Enterprise-Managed Authorization extension uses (a token exchange followed by a JWT grant), applied between servers instead of between an enterprise identity provider and a server.

A request that is not on any user's behalf (a public inventory read, a nightly sync) MAY use the federating server's own client credentials at the member, provided the member scopes that credential to what it would show an anonymous or service caller.

11.9 Declaring federation

A server that supports this section declares the extension in its discovery response:

{
  "extensions": {
    "io.automotivemcp/federation": {
      "version": "0.1-draft",
      "roles": ["federating", "member"],
      "max_fan_out": 25,
      "token_exchange": true
    }
  }
}

Where a conformant server publishes this, and how a caller finds the member servers for a set of locations in the first place, is discovery (§10) and is not yet written.

11.10 Security and privacy considerations

  • Isolation survives aggregation. Each location's data is authorized separately, by the member that holds it, on a token issued for that member. A federating server that caches results MUST key the cache by location and by the authorization the result was fetched under.
  • Amplification. One call can become many. A federating server MUST rate-limit by the cost of the fan-out, not by the count of inbound calls, and MUST honor each member's rate_limited signals (§6.4) without converting them into retries against the same member.
  • Errors leak. A member's error relayed verbatim can disclose another tenant's data or the existence of a record. See §11.7.1.
  • Headers are untrusted until validated. See §11.4.

11.11 Open questions

  • Canonical identity across authorities. When two authorities both claim to name a location, who wins? A registry is the obvious answer and the expensive one.
  • Should provenance be signed? A signed provenance record would let a caller verify a figure without trusting the federating server. It overlaps substantially with substantiation (§13).
  • Cross-authorization-server trust for token exchange is assumed, not specified. Without it §11.8 cannot be implemented between unrelated businesses, only within one platform or group. This is open for a decision by the project owner and working group.
  • Should the location header be required rather than recommended, so that every gateway can depend on it?
Something wrong, missing, or impossible to implement in §11?Propose a change →Opens an email with this section and version already filled in. No account needed, and you keep your copyright.