Skip to content

Standardize provenance for app-initiated server tool calls #738

Description

@krubenok

Problem / motivation

For a server tool whose _meta.ui.visibility includes both "model" and "app", the server can receive tools/call requests initiated by either the model/agent or an embedded MCP App. Today those requests are indistinguishable at the server boundary.

A standardized, per-invocation provenance signal would help with observability, UX analytics, debugging, rate limiting, and policy decisions. It should be treated as provenance asserted by the MCP client/host, not as an authentication or authorization primitive.

Current spec behavior

The stable MCP Apps specification allows a View to send the core tools/call request to its Host, which may proxy that request to the MCP server.

Existing mechanisms answer related but different questions:

  • _meta.ui.visibility controls whether a tool may be called by the model and/or App; it does not identify who initiated a particular call to a dual-visible tool.
  • MCP 2026-07-28 per-request io.modelcontextprotocol/clientInfo identifies the MCP client/Host; it does not distinguish whether that Host's model/agent or embedded App initiated the request.
  • Apps ui/initialize appInfo identifies the View to the Host, but it is not propagated to the MCP server on each tools/call.
  • A custom App-supplied _meta marker is non-interoperable, may be dropped by Hosts or gateways, can collide with other conventions, and should not be considered authoritative.

As a result, proxying preserves the call parameters but carries no normative per-call origin signal.

Concrete example

Both paths collapse to the same server request:

Agent -> Host -> Server
App   -> Host -> Server
{
  "method": "tools/call",
  "params": {
    "name": "refresh_dashboard",
    "arguments": { "accountId": "123" }
  }
}

The server cannot tell whether the Host emitted this request because the agent selected the tool or because a user clicked a control in the embedded App.

Proposal: host-attested metadata

Define an official Apps-owned request _meta entry, for example:

{
  "_meta": {
    "io.modelcontextprotocol/ui": {
      "initiator": "app"
    }
  }
}

Normative behavior could be:

  • The Host MUST add or overwrite this value when proxying a View-originated tools/call.
  • The Host MUST NOT set initiator: "app" for model/agent-originated calls.
  • Downstream proxies and gateways SHOULD preserve the standardized entry.
  • Absence means unknown, not implicitly "model".
  • The View should not be responsible for self-declaring this marker.

The smallest interoperable shape may only need an App-origin boolean/enum. Optional appInfo and/or resourceUri could be considered separately if their interoperability value outweighs privacy and cardinality concerns.

Alternatives considered

  • clientInfo / appInfo: clientInfo identifies the Host, while appInfo identifies the View only within the Apps initialization boundary. Neither currently expresses per-invocation origin to the server.
  • Separate connections: A Host could use a distinct MCP connection for App traffic, but that complicates session/state sharing and still lacks a portable semantic signal across gateways.
  • OpenTelemetry baggage: Useful inside a deployment, but it is not an interoperable MCP protocol contract and may not survive all transports or proxies.
  • Custom vendor _meta: Feasible for closed ecosystems, but merely relocates the custom semantics. Hosts may drop it, namespaces may diverge, and App-authored values are not authoritative.

Security and trust considerations

“Host-attested” means asserted by the MCP client/Host; it is not cryptographically verified. A server must not use this field for authorization unless it separately trusts and authenticates the Host making the assertion.

Hosts should overwrite any spoofed App-provided value when proxying the request. Provenance should remain low-cardinality. If identity-bearing fields such as appInfo or resourceUri are included, the specification should give explicit privacy, disclosure, and logging guidance.

Open questions

  • What namespace and shape best fit current Apps and core _meta conventions?
  • Is an App-only boolean sufficient, or should the field be a broader enum such as app, model, user, host, or unknown?
  • Should appInfo and/or resourceUri be included, optional, or intentionally excluded?
  • What preservation requirements should apply through gateways and nested proxies?
  • How should provenance relate to _meta.ui.visibility enforcement without conflating the two?
  • Should the design align only with modern per-request metadata conventions, or also define legacy compatibility behavior?

The goal is to standardize the smallest interoperable shape; the options above are intended to invite maintainers to choose the least disruptive protocol contract.

Related specifications and issues

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