Skip to content

Support lossless MCP embedded resources and resource links in AHP tool results #504

Closed as not planned

Description

Summary

Agent Host Protocol tool results can carry binary embedded data or a reference to externally stored content, but the current shapes cannot losslessly represent MCP embedded text resources and resource_link content blocks.

This becomes visible when an MCP client hosted behind an Agent Host needs to preserve a tool result such as:

{
  "content": [
    {
      "type": "text",
      "text": "Generated the requested artifact."
    },
    {
      "type": "resource",
      "resource": {
        "uri": "file:///generated/main.bicep",
        "mimeType": "text/plain",
        "text": "targetScope = 'subscription'\n"
      },
      "annotations": {
        "audience": ["user", "assistant"],
        "priority": 1
      }
    },
    {
      "type": "resource_link",
      "uri": "file:///generated/main.bicep",
      "name": "main.bicep",
      "title": "Generated Bicep template",
      "description": "Generated infrastructure template",
      "mimeType": "text/plain"
    }
  ],
  "isError": false
}

The artifact text may remain available to the model, but a host cannot map the complete result into current AHP tool-result content without discarding information or moving the text behind a newly created host resource.

Current AHP shapes

ToolResultEmbeddedResourceContent carries Base64 binary data and a content type:

export interface ToolResultEmbeddedResourceContent {
  type: ToolResultContentType.EmbeddedResource;
  data: string;
  contentType: string;
}

ToolResultResourceContent extends ContentRef:

export interface ContentRef {
  uri: URI;
  sizeHint?: number;
  contentType?: string;
  nonce?: string;
}

Sources:

These types support useful basic mappings, but do not directly preserve:

  • An inline textual resource together with its original URI.
  • MCP resource name, title, and description.
  • Audience and priority annotations.
  • Resource-level metadata.
  • The distinction between embedded resource content and an MCP resource_link.

Minimum mapping versus lossless mapping

A host could implement a minimum mapping without changing AHP:

  1. Store embedded text in a host-readable resource.
  2. Assign it an AHP content URI.
  3. Emit ToolResultResourceContent with URI, content type, and size.

That may be sufficient for a basic resource tile, but it changes the representation and cannot retain all MCP metadata.

This issue asks for a documented, interoperable answer to one of the following:

  1. Define the normative mapping from MCP embedded resources and resource links to existing AHP types, including where inline text is stored and how clients retrieve it; or
  2. Extend the AHP tool-result content model so hosts can preserve the complete MCP semantics.

Possible protocol approaches include:

  • A text-capable embedded-resource shape with URI and metadata.
  • Richer resource-reference fields for name, title, description, annotations, and metadata.
  • Dedicated MCP resource and resource-link result types.
  • A generic per-content metadata mechanism with well-defined client behavior.

Expected outcome

An Agent Host should be able to translate an ordered MCP result containing ordinary text, an embedded text resource, and a resource link such that:

  1. The client can distinguish all three blocks.
  2. Inline resource text or blob data remains retrievable.
  3. Original URI and MIME type are retained.
  4. Resource-link descriptive fields are retained.
  5. Annotations and resource metadata are not silently discarded.
  6. Minimal clients can safely ignore the richer fields.

Related work

Issue #473 documents broader interoperability differences, but does not define a lossless mapping for these MCP content blocks.

Activity

  1. psaswata commented on Oct 7, 2026

    @psaswata
    MemberAuthor

    The corresponding VS Code Agent Host mapping and rendering issue is now open: microsoft/vscode#340232

  2. connor4312 commented on Oct 7, 2026

    @connor4312
    Member

    when an MCP client hosted behind an Agent Host needs to preserve a tool result

    Can you describe the case(s) where you're needing to do this?

    AHP is a display protocol, losslessly translating the MCP tool results is not necessarily a requirement.

  3. psaswata commented on Oct 8, 2026

    @psaswata
    MemberAuthor

    Thanks. The concrete case is an MCP tool that generates one or more user-facing files.

    Our Azure MCP tool returns:

    • A normal textual summary.
    • Separate embedded text resources containing generated artifacts such as Bicep files.
    • Corresponding resource_link blocks carrying the artifact URI and display information.

    In VS Code's direct/Local MCP path, these are presented as separate resource outputs beneath the tool call. Through the Copilot Agent Host path, the resource text remains available to the model, but it is flattened into ordinary text—sometimes through a temporary tool-output file. The user therefore loses the distinction between the conversational response and the generated artifacts, as well as the ability to identify or open each artifact as a resource.

    The requirement is not necessarily to reproduce every MCP field losslessly. The display requirement is that the Agent Host client receives enough information to:

    1. Distinguish generated artifacts from ordinary tool-result text.
    2. Present each artifact separately with an appropriate filename or title and content type.
    3. Retrieve or open the artifact content.
    4. Preserve an actionable resource link where the MCP result provides one.

    If the intended AHP mapping is for the Agent Host to store inline text in its content/resource channel and emit an existing ToolResultResourceContent/ContentRef, that may cover most of the requirement. The open question is how the client receives display information such as the MCP resource-link name or title, because ContentRef currently contains only uri, sizeHint, contentType, and nonce.

    Fields such as MCP audience annotations, priority, or arbitrary _meta do not need to cross AHP unless they affect presentation. We are mainly looking for the recommended AHP representation for this generated-artifact experience and whether the existing Resource type is considered sufficient.

    Related implementation tracking:

  4. connor4312 commented on Oct 13, 2026

    @connor4312
    Member

    Connor's agent writing:

    Thanks for the detailed write-up! We looked into this and don't think AHP needs new types here. The gaps are in how the Copilot agent host maps MCP results into the existing ones.

    AHP is a display protocol, so the bar is "the client can show and open each artifact", not round-tripping MCP losslessly. We also want to keep chat state small, so payloads shouldn't be inlined into it. The existing types cover your four requirements:

    1. Telling artifacts apart from text: MCP text maps to a text block. MCP resource and resource_link both map to a resource block, which is a reference with a uri, contentType, and sizeHint.
    2. Filename and content type: clients label the artifact with the basename of the reference URI. The host controls that URI, so it can end in the MCP resource's basename or the resource_link name. This matches how VS Code's local MCP client labels resources today; it doesn't use title or description either.
    3. Retrieving content: clients fetch content lazily through AHP's resourceRead. For embedded resources, the host stores the text or blob in its session storage and returns a URI pointing at it. For resource_link, the host proxies the read to the MCP server's resources/read.
    4. An actionable link: same as (3). The client doesn't need to know whether something was embedded or linked; it just reads the URI.

    Audience annotations are the only other field that affects display. Hosts can apply them by leaving out resources meant only for the assistant. Priority and _meta don't change rendering, so they don't need to cross AHP.

    The real gaps were:

    Closing this since no protocol change is needed. If the URI basename turns out to be a poor label in practice (e.g. opaque URIs like demo://resource/dynamic/text/1), we can consider adding an optional display label to resource blocks.

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