modelcontextprotocol / modelcontextprotocol/ext-apps

SEP: Duplicate placement of `McpUiResourceMeta` in the resource metadata and the resource read value leads to confusion.

Open
#269 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
2.9k
Forks
387
Avg merge
3h 21m
Merged PRs (30d)
6

Description

Issue

Currently the spec requires you to place the CSP, permissions, etc information in two separate places:

  1. The resource metadata _meta.ui?.
  2. The contents of the resource.

Example: I have to add the _meta.ui info here:

registerAppResource(server,
    resourceUri,
    resourceUri,
    {
      mimeType: RESOURCE_MIME_TYPE,
      _meta: {
        ui: {
          csp: {
            connectDomains: ["https://xxx"],
            resourceDomains: [
              "https://xxx",
              "https://fonts.googleapis.com",
              "https://fonts.gstatic.com",
            ],
          },
        },
      },
    },
    async (): Promise<ReadResourceResult> => {
      const html = await fs.readFile(path.join(DIST_DIR, "cocktail-recipe-widget.html"), "utf-8");
      return {
        contents: [{ uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html }],
      };
    },
  );

and here:

// resources/read response for UI resource
{
  contents: [{
    uri: string;                  // Matching UI resource URI
    mimeType: "text/html;profile=mcp-app";  // MUST be "text/html;profile=mcp-app"
    text?: string;                // HTML content as string
    blob?: string;                // OR base64-encoded HTML
    _meta?: {
      ui?: {
        csp?: {
          connectDomains?: string[]; // Origins for network requests (fetch/XHR/WebSocket).
          resourceDomains?: string[]; // Origins for static resources (scripts, images, styles, fonts).
          frameDomains?: string[]; // Origins for nested iframes (frame-src directive).
          baseUriDomains?: string[]; // Allowed base URIs for the document (base-uri directive).
        };
        permissions?: {
          camera?: boolean;           // Request camera access
          microphone?: boolean;       // Request microphone access
          geolocation?: boolean;      // Request geolocation access
          clipboardWrite?: boolean;   // Request clipboard write access
        };
        domain?: string;
        prefersBorder?: boolean;
      };
    };
  }];
}

Why it's a problem

There is redundancy in having to add the same exact information in two separate places. As a client implementor, I don't know which one to check. Do I check the resource meta? Do I check the resource result? I don't know.

As a server implementor, it was difficult for me to realize that I had to add it in two separate places. I was confused why my CSP wasn't getting used even though I put it in the resource meta, only to realize the client I'm using is checking it in the resource content.

Solution

Ideally, we have a single source of truth for where to put the meta. I think we should standardize it to be read in the resource read content. That's where most clients today have it implemented.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by comparing the resource metadata _meta.ui with the _meta.ui object in the resources/read response, including the McpUiResourceMeta placement described in the issue. Trace which location clients and servers currently use, then define and document one authoritative location and update the protocol examples so the two sides agree.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, documentation
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.