Skip to content

Conversation

@evalstate
Copy link
Member

This change updates the guidance on the use of EmbeddedResources within CallToolResults to clarify the use of custom URI Schemes, and add guidance that Servers using EmbeddedResources SHOULD implement the resources capability.

Motivation and Context

The documentation for Resources makes it clear that MCP Servers are:

implementations are always free to use additional, custom URI schemes.

And references RFC 3986 in the opening paragraph.

The existing wording for CallToolResult is worded in a way which makes it sound like there are guarantees for later availability:

Resources MAY be embedded, to provide additional context or data, behind a URI that can be subscribed to or fetched again by the client later:

Whereas a custom URI scheme within RFC3986 (7.1 Reliability and Consistency) states:

There is no guarantee that once a URI has been used to retrieve information, the same information will be retrievable by that URI in the future. Nor is there any guarantee that the information retrievable via that URI in the future will be observably similar to that retrieved in the past.

The update to the wording is intended to make it clearer that MCP Server implementors are able to define and use their own scheme.

How Has This Been Tested?

Local document serving.

Breaking Changes

No breaking changes.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

A number of discussions threads, for example:
https://github.com/orgs/modelcontextprotocol/discussions/287#discussioncomment-12944736

@evalstate evalstate requested a review from jspahrsummers April 25, 2025 10:38
@tadasant
Copy link
Member

Thanks for opening this, I think it is sorely needed. Coming from this discussion, there has been repeated misalignment across potentially a half dozen individuals with respect to the idea of using EmbeddedResource as a way to return shapes like JSON or HTML from a tools/call. This change would make it clear that is the intent.

A thought: would it make sense to make uri an optional parameter on ResourceContents? Besides the verbiage that this PR is proposing changing, I think the mere presence of the required URI parameter, plus the traditional notion of a "resource" in REST, is still liable to cause confusion and discourage the used of EmbeddedResource where it might actually be a good fit. If we continue to say uri is required, but Resources are allowed to be ephemeral, it feels like people will feel forced to create some contrived throwaway URI even if mimeType is sufficient context to pass back to the client.

For example, take the following scenario:

  • As a client, I am capable of rendering the text/html mimeType in my "Tool Call Result" window
  • As a server, I want to reply back to a tools/call with a structured <table> HTML element to make it easy for the end-user to visualize a complex dataset. That UI is only relevant for that single tool call and is not a Resource that gets stored otherwise.

Would we expect the server to come up with some custom URI scheme for this, even though the URI and associated scheme are entirely ignored by both sides? Seems like it would be better to just make it optional.

If there's an argument to keep it required, though, I could be convinced that this scenario is too contrived and the reality is that we want to push implementers to invest in defining and documenting thoughtful custom URI's instead of skipping that step entirely.

@evalstate
Copy link
Member Author

evalstate commented Apr 27, 2025

Great question - I'd propose it remain mandatory for the following reasons:

  • The type used in CallToolResult and PromptMessage inherits from ResourceContents which is also used for ReadResourceResult which returns based on the uri. We definitely want to keep the semantics that that the uri "identifies an abstract or physical resource".
  • While it might be convenient for MCP Server developers to not specify a uri (or even have one generated), I think it's a net benefit for the developer to consider Resource semantics when using them.

I think the need here is to make it clearer what RFC3986 means in practice for integrators, and some use-cases to show how uris and associated schemes could be useful. A couple of examples:

  • An enterprise application Client/Server pair returning a Customer Record as an EmbeddedResource within a well-known uri scheme. This would allow the integrator to: subscribe to CRUD updates to that record via ResourceUpdateNotifications, or retrieve associated sales information by adapting the uri given the customer identifier.
  • A consumer application doing AI Video generation returning the first frame of video as an EmbeddedResource within the first few seconds to improve UX, with the uri being later able to return the result after completion.
  • Prompts for IDE/API Servers for application building including https:// resources (e.g. llms.txt) to be resolved by the Host for inclusion in context during code generation.

And also the really important fact that RFC3986 doesn't make guarantees of permanence - meaning integrators are free to use EmbeddedResources from tools for ephemeral or visible-once data. We've seen a number of PRs recently that seem predicated on the idea that Resources are something to be somehow avoided - which is really unfortunate.

There's a lot of value to be unlocked here. For example:

  • Commonly agreed URI scheme for Home Automation sensors and controls would allow integrators to use standardised libraries to build all kinds of embedded agent based systems with low effort.
  • UX generation patterns (such as Claude Artifacts) delivered by commonly agreed schemes would allow rich clients (Claude Desktop, Sage, 5ire and others) to use standard SDKs to show rich User Interfaces from MCP Servers that supported the scheme.

MCP Tool Calls have been a delighting feature as it has allowed developers to quickly and easily integrate their code with a huge number of Hosts. I personally think the next wave of value is unlocked by integrators producing libraries and schemes that enable much richer integrations. Because MCP can be used in so many different environments, it doesn't necessarily make sense to e.g. include UX primitives in the core - but to enable Host application writers to combine the libraries and schemes that make sense to them.

@cmsparks
Copy link

cmsparks commented Apr 28, 2025

I am a big fan of increasing clarity on embedded resources and encouraging this use case. It took me and some others a while to understand that using embedded resources in this way is possible. It also feels like it supplants the need for adding tool result schemas to the spec, which to me feels substantially more complex and less ergonomic.

If we continue to say uri is required, but Resources are allowed to be ephemeral, it feels like people will feel forced to create some contrived throwaway URI even if mimeType is sufficient context to pass back to the client.

I wonder if we could add some annotation to EmbeddedResource or recommend server developers use a scheme like ephemeral: or volatile: here. Then we'd get the benefit of:

  1. Server developers are forced to consider resource semantics, and can make an explicit decision as to whether their resource is ephemeral
  2. The ephemerality of the resource is hinted to the client. This tells the client whether the resource can be read or subscribed to in the future.

Not sure if something like this feels right, but here's example I've mocked up in the context of the servers I've been developing (Cloudflare's official MCP servers):

this.server.tool(
  "create_bucket",
  `Creates a R2 bucket for object storage. An example workflow:
  - User: "Create a bucket for me to store image"
  - Call tool create_bucket, returns
  - Call a file write tool to some valid wrangler.json, which contains the result of create_database
  `,
  async () => {
    const bucketName = "bucket123"
    return {
      content: [
        {
          type: "resource",
          resource: {
            /**
             * The "ephemeral" uri scheme implies that this embedded resource 
             * only exists for this tool call and can't be subscribed to or 
             * fetched later
             */
            uri: "ephemeral:/wrangler.json",
            mimeType: "application/json",
            text: JSON.stringify({ 
              r2_buckets: [{ binding: "MY_BUCKET", bucket_name: bucketName }]
            }),
          },
        },
        {
          type: "text",
          text: "Here is a JSON config snippet, which can be added to a valid wrangler.json",
        },
      ],
    };
  }
);

@patwhite
Copy link
Contributor

GREAT change @evalstate!!

  • The type used in CallToolResult and PromptMessage inherits from ResourceContents which is also used for ReadResourceResult which returns based on the uri. We definitely want to keep the semantics that that the uri "identifies an abstract or physical resource".

For what it's worth, I feel like this is actually the crux of the problem. Because embedded resources are so tightly tied to normal resources, when I first read the spec I absolutely felt like I couldn't return an embedded resource unless I also server it up as a resource. Maybe I misread something, but I read it as you could optionally take a resource that your server hosts and serve it to he client as the response to this call. That's very different than the use case you've outlined here!

It might be that read the spec linearally and read the resource section before the tools section, so when I got to the tools section I was all primed for resources to be pervasive.

  • While it might be convenient for MCP Server developers to not specify a uri (or even have one generated), I think it's a net benefit for the developer to consider Resource semantics when using them.

Your examples here are great, though I'm not sure the examples change much if the URI is optional? If it's there you have these semantics, if not, no big deal?

We've seen a number of PRs recently that seem predicated on the idea that Resources are something to be somehow avoided - which is really unfortunate.

I'll admit I fall into this camp - I'm not entirely sure when to use them. For instance, in the hosting working group, we're discussing multi-tenancy. If you're an agent and you have access to two tenants, should that be a resource? Should it be multiple resources?? I know that's a silly one example, but I've been genuinely struggling with it. I don't know if the answer is documentation related or what, but not being sure how exactly to use resources then immediately wrapped around to, when I read the tool call details, because I felt I didn't understand resources very well, I didn't really give embedded resources a lot of thought, I figured they were solving a different problem than json delivery.

Hope this perspective helps!

@evalstate
Copy link
Member Author

It does thanks @patwhite

I think the danger is in overthinking them. A Resource is simply some text or binary data, an identifier (uri) and a mimeType - no more, no less. They can be delivered with Tool Results, Prompts and directly as Resources.

If you want - and the server and uri scheme support it - you can subscribe for live updates to them, specify a templating scheme and use completions for discovery - but these things are all optional if you need them. I'd encourage people to use those capabilities, and think it good practice to have an integrated scheme, but it's flexible. I do also think that commonly accepted uri schemes for MCP would be really helpful for the wider community.

RFC3986 gives us the rules about using them (e.g. how to use , or ; etc.). I think another problem (I'll update the PR) is that the current site style sheet doesn't make the link to the RFC clear.

@evalstate
Copy link
Member Author

Update 28/04/2025 - I have also updated the server/Resources page to include a sub-section on Custom URI schemes, primarily as the link in the opening paragraph is not obvious.

@bhosmer-ant
Copy link
Contributor

bhosmer-ant commented Apr 28, 2025

@evalstate first of all, thanks for your patience with the sprawly discourse on #356 :) A few general questions/observations here, and then I'll follow up on #356 with some questions related specifically to schematized tool results. Apologies for the split commentary but I figure that's the best way to keep the schematized tool results discussion in one place.

  • I totally get the pitch - if we decouple permanence from the notion of EmbeddedResource, we unlock a bunch of utility and expressive, and RFC 3986 lets us do this. Very appealing.
  • The trickiest consequence at the level of MCP nomenclature is that we're introducing a consequential difference between the mental model of "Resource" and "EmbeddedResource" (the optional ephemerality of the latter but not the former). I think we'd need to prominently call out this difference in the spec language to avoid confusion (the presence of URIs in both would make this especially important).
  • Per @cmsparks it's critical that an EmbeddedResource would include information about whether it's ephemeral or not, right? it seems infeasible to leave it up to clients to figure this out from context, trial and error, etc.

@evalstate
Copy link
Member Author

I totally get the pitch - if we decouple permanence from the notion of EmbeddedResource, we unlock a bunch of utility and expressive, and RFC 3986 lets us do this. Very appealing.

Embedded simply means a Resource contained within a CallToolResult or PromptMessage. It doesn't have special meaning beyond that.

The trickiest consequence at the level of MCP nomenclature is that we're introducing a consequential difference between the mental model of "Resource" and "EmbeddedResource" (the optional ephemerality of the latter but not the former). I think we'd need to prominently call out this difference in the spec language to avoid confusion (the presence of URIs in both would make this especially important).

We only need a mental model of Resource. They arrive either embedded within CallToolResults and PromptMessages, or as a result of a ReadResourceResult.

I'm not particularly comfortable with the idea of promoting "optional ephemerality". The behaviour of the Resource uri scheme is defined by the Server author. They may choose to publish a well known scheme such as home-widgets://sensors/{location}/ or their own scheme such as temp://just-need-to-return-some-json. We need to make the option plain for MCP Server authors and Host/Client SDK producers who may want to build value-add products based on well-known schemes. There may be parts of RFC3986 we want to highlight for convenience.

Per @cmsparks it's critical that an EmbeddedResource would include information about whether it's ephemeral or not, right? it seems infeasible to leave it up to clients to figure this out from context, trial and error, etc.

I'm sorry, I've read this multiple times and I'm afraid I don't understand this point at all.

@bhosmer-ant
Copy link
Contributor

...

Embedded simply means a Resource contained within a CallToolResult or PromptMessage. It doesn't have special meaning beyond that.

...

We only need a mental model of Resource. They arrive either embedded within CallToolResults and PromptMessages, or as a result of a ReadResourceResult.

The problem is that irrespective of RFC 3986, MCP broadly assumes/relies on the persistence of Resources (e.g. the resources/list -> resources/read flow). So while it's true that EmbeddedResources in particular will still work fine if the current language around persistence is relaxed ("behind a URI that can be subscribed to or fetched again by the client later"), that's not the case for Resources as used elsewhere in the protocol.

So it would be actively confusing to use Section 7.1 RFC 3986 as a basis for explicitly defining all Resources as being "optionally persistent" without further qualification, since Resources as commonly used do in fact need to be persistent. If we add guidance about using ephemeral EmbeddedResources, we'll need to be very clear about this distinction. (Regardless of whether we use EmbeddedResources to return structured tool results.)

I'm not particularly comfortable with the idea of promoting "optional ephemerality". The behaviour of the Resource uri scheme is defined by the Server author. They may choose to publish a well known scheme such as home-widgets://sensors/{location}/ or their own scheme such as temp://just-need-to-return-some-json. We need to make the option plain for MCP Server authors and Host/Client SDK producers who may want to build value-add products based on well-known schemes. There may be parts of RFC3986 we want to highlight for convenience.

Yeah, I see why adding an ephemerality bit would be redundant, given that this information should be derivable from the URI (given sufficient information from the server). I think this moves EmbeddedResource further away from being a reasonably lightweight solution for tools that simply want to return ephemeral structured results though.

Per @cmsparks it's critical that an EmbeddedResource would include information about whether it's ephemeral or not, right? it seems infeasible to leave it up to clients to figure this out from context, trial and error, etc.

I'm sorry, I've read this multiple times and I'm afraid I don't understand this point at all.

My point was just, "a client needs a way to find out if a Resource is ephemeral", which I think you answered above with "a server should either use a well-known URI scheme or publish + document one of its own, and the client should use this information to derive this information from the URI "

@patwhite
Copy link
Contributor

patwhite commented Apr 30, 2025

This whole conversation got me really interested in what a resource is, I ended up going down a rat hole here, because what I've thought of as a resource for the last 10 years is very different than how we're using resource here. This isn't authoritative, ietf has like 6 different specs that go into the details of resources, but better or worse, here's what gemini thinks:

image

So, this isn't to say that we can't use resources as ephemeral - but as with any good protocol discussion, a lot of this discussion is all coming back to readability of the spec, and I'm not sure most people read resources (in the REST world we live in) as ephemeral, which then just leads to the knock on effect of all this confusion about what's the right type to use for a return for people reading the spec for the first time

@evalstate
Copy link
Member Author

evalstate commented Apr 30, 2025

The problem is that irrespective of RFC 3986, MCP broadly assumes/relies on the persistence of Resources (e.g. the resources/list -> resources/read flow).

There's a chance we're overthinking this. The fact I do a directory listing doesn't mean the filesystem guarantees the later availability of a file.

hat's not the case for Resources as used elsewhere in the protocol.

Would you mind being specific, as I'm not inferring that from either https://modelcontextprotocol.io/docs/concepts/resources or https://modelcontextprotocol.io/specification/2025-03-26/server/resources.

@tadasant
Copy link
Member

tadasant commented May 3, 2025

A potential slippery slope to be aware of:

  • Let's say we don't take this PR, and peg Resources & EmbeddedResources as persistent, non-ephemeral
  • So, it becomes natural to introduce DataContent for the output schema conversation
  • But then, are we opening the floodgates to all sorts of new shapes, like HtmlContent, which would probably become the right way to answer the discussion on UI?

Beyond application/json and text/html, I could see the discussion happening again for MIME types like text/csv or application/javascript. It seems to me like EmbeddedResource would nicely handle all of these ephemeral opportunities in a flexible way at the specification level, and leave handling the long tail of types (including structured JSON, HTML, and more) to Resource's mimeType field and the ecosystem's conventions that emerge around it.

good catch :)

Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com>
@evalstate evalstate requested review from dsp-ant and pcarleton May 9, 2025 08:18
@dsp-ant dsp-ant moved this to Consulting in Standards Track Jun 6, 2025
@dsp-ant dsp-ant modified the milestone: DRAFT 2025-06-XX Jun 6, 2025
@dsp-ant dsp-ant added this to the DRAFT 2025-06-XX milestone Jun 6, 2025
Copy link
Member

@dsp-ant dsp-ant left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am okay for this to be accepted, but please make teh changes only to DRAFT.


### Custom URI Schemes

Custom URI schemes SHOULD be in accordance with [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Custom URI schemes SHOULD be in accordance with [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986),
Custom URI schemes MUST be in accordance with [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986),

In the schema we say format: uri, which according to JSON-Spec referes to RFC3986, see https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.7.3.5

@dsp-ant dsp-ant moved this from Consulting to In Review in Standards Track Jun 10, 2025
@bhosmer-ant
Copy link
Contributor

@evalstate thanks for the quick turnaround! If you could fix merge conflicts then it's button-pushing time

@bhosmer-ant bhosmer-ant enabled auto-merge June 10, 2025 22:19
Copy link
Contributor

@bhosmer-ant bhosmer-ant left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@bhosmer-ant bhosmer-ant merged commit 80d942f into modelcontextprotocol:main Jun 10, 2025
2 checks passed
@github-project-automation github-project-automation bot moved this from In Review to Approved in Standards Track Jun 10, 2025
@evalstate
Copy link
Member Author

Thanks @bhosmer-ant -- should be good, tripped over the lastModified merge. Should be mergeable

@bhosmer-ant
Copy link
Contributor

Done! ! Yeah I don't think that lastModified thing was due to your merge tbh 😁

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

Labels

None yet

Projects

No open projects
Status: Approved

Development

Successfully merging this pull request may close these issues.

7 participants