You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Packaging, automation and deployment (ex: pypi, docker, quay.io, kubernetes, terraform)
Other (please describe below)
🧭 Epic
Title: Deliver MCP Apps through a minimal extension substrate
Goal: Ship MCP Apps support in ContextForge while establishing the first extension-shaped foundation that future generic extension framework work can replace or expand without rewriting MCP Apps as a one-off feature.
Why now: MCP Apps support is needed as a concrete product capability, and it should be delivered using the same extension-oriented boundaries described in #2527 and #4957. This keeps MCP Apps aligned with capabilities.extensions["io.modelcontextprotocol/ui"] and avoids embedding MCP Apps-specific behavior directly into the core MCP dispatcher.
🧑🏻💻 User Story 1
As a: MCP client or host I want: ContextForge to advertise MCP Apps through capabilities.extensions So that: clients can negotiate MCP Apps using the official extension capability model.
✅ Acceptance Criteria
Scenario: MCP Apps extension is advertised during initializeGiven MCP Apps support is enabled
And the caller is authorized to use the target server or gateway scope
When an MCP client calls initialize with compatible client capabilities
Then the initialize response includes capabilities.extensions["io.modelcontextprotocol/ui"]
And existing prompts/resources/tools/logging/completions capabilities are preserved
And capabilities.experimental is not used as the canonical MCP Apps signal
Scenario: MCP Apps extension is not advertised to unauthorized callersGiven MCP Apps support is enabled
And the caller is not authorized for the target server or gateway scope
When the caller invokes initialize
Then capabilities.extensions["io.modelcontextprotocol/ui"] is omitted
And no private or team-only extension availability is leaked
🧑🏻💻 User Story 2
As a: platform maintainer I want: a minimal built-in extension substrate for MCP Apps So that: MCP Apps is implemented as an extension handler rather than as scattered dispatcher-specific logic.
✅ Acceptance Criteria
Scenario: MCP Apps is registered as a built-in extension handlerGiven the gateway starts with MCP Apps enabled
When extension handlers are initialized
Then io.modelcontextprotocol/ui is registered as a built-in extension
And the handler can contribute initialize capabilities
And the handler can process MCP Apps-specific resource/session behavior
Scenario: Core MCP methods still take precedenceGiven an MCP request uses a core method such as tools/list or resources/read
When the request is dispatched
Then the existing core MCP path handles the request
And the extension handler is invoked only for MCP Apps-specific behavior or metadata processing
Scenario: Unknown extension methods remain default-denyGiven no built-in extension handler owns method unknown/hello
When a client calls unknown/hello
Then ContextForge returns JSON-RPC method not found
And no upstream call is made
🧑🏻💻 User Story 3
As a: server administrator I want: to register and serve MCP Apps UI resources So that: tools can return interactive UI metadata backed by ui:// resources.
✅ Acceptance Criteria
Scenario: Register UI resourceGiven an administrator has UI content for a dashboard
When they register a UI resource with a ui:// URI, MIME type, CSP config, and visibility metadata
Then the resource is stored with audit metadata
And the resource is associated with the configured owner/team visibility
Scenario: Read UI resource through MCP resource flowGiven ui://dashboard exists
And the caller is authorized to read it
When the caller invokes resources/read for ui://dashboard
Then the response returns the UI content in MCP resource content format
And the response includes the metadata needed by an MCP Apps host
Scenario: Deny unauthorized UI resource readGiven ui://dashboard is private or team-scoped
And the caller lacks access to that scope
When the caller invokes resources/read for ui://dashboard
Then the request is denied
And an audit event records the denied access
🧑🏻💻 User Story 4
As a: tool author I want: tools to declare associated UI resources and app/model visibility So that: MCP Apps can show interactive views without exposing app-only helper tools to the model.
✅ Acceptance Criteria
Scenario: Tool declares UI resource metadataGiven tool create_dashboard exists
And ui://dashboard exists
When the tool metadata is updated with _meta.ui.resourceUri="ui://dashboard"Then tools/list returns the UI metadata to authorized model-facing clients
And tools/call can return UI-capable results for compatible hosts
Scenario: App-only tools are hidden from model-facing listGiven helper tool get_dashboard_data is app-visible only
When a model-facing client invokes tools/list
Then get_dashboard_data is omitted
And model-visible tools remain listed normally
Scenario: App session can call app-visible helper toolGiven an active MCP Apps session is bound to the same server as get_dashboard_data
And the caller has permission to execute the tool
When the app invokes tools/call for get_dashboard_data
Then the call succeeds
And the result is returned to the app bridge
🧑🏻💻 User Story 5
As a: security administrator I want: MCP Apps sessions, AppBridge calls, CSP, and sandbox policy to be enforced So that: interactive UI content cannot cross server, team, or origin boundaries.
✅ Acceptance Criteria
Scenario: AppBridge enforces same-server boundaryGiven an app session is bound to server-a
When the app attempts to call a tool from server-b
Then the call is denied
And an audit event records a cross-server app call denial
Scenario: Expired or missing app session is deniedGiven no active app session exists for the provided session id
When an app-originated JSON-RPC call is received
Then the call is denied
And no tool or resource operation is executed
Scenario: CSP and sandbox policy are validatedGiven an administrator registers a UI resource
When the CSP, sandbox, or permissions policy is unsafe
Then the resource is rejected or requires an explicit approved override
And the policy decision is recorded
Change adheres to current MCP extension negotiation using capabilities.extensions
MCP Apps uses the official io.modelcontextprotocol/ui extension identifier
UI resources are represented as ui:// resources and served through MCP resource flows
No breaking changes to existing MCP-compliant integrations
If deviations exist, please describe them below:
No intentional deviations. Legacy capabilities.experimental may be preserved as compatibility metadata, but it is not the canonical MCP Apps signal.
🔄 Alternatives Considered
Implement MCP Apps directly in the core dispatcher. Rejected because it would make MCP Apps a one-off feature and create avoidable migration work when the broader extension framework lands.
Wait for the full generic extension framework before implementing MCP Apps. Rejected because MCP Apps can be delivered through a minimal built-in extension substrate while still preserving the future framework direction.
Proxy all unknown extension methods. Rejected because unknown extension routing must remain default-deny and explicitly owned.
This issue should finish with MCP Apps delivered through a minimal built-in extension-shaped substrate. The broader registry, discovery, generic auto-proxy, Admin API/UI, and custom handler framework can later replace or expand the substrate without requiring MCP Apps to be rewritten as a standalone feature.
🧭 Type of Feature
Please select the most appropriate category:
🧭 Epic
Title: Deliver MCP Apps through a minimal extension substrate
Goal: Ship MCP Apps support in ContextForge while establishing the first extension-shaped foundation that future generic extension framework work can replace or expand without rewriting MCP Apps as a one-off feature.
Why now: MCP Apps support is needed as a concrete product capability, and it should be delivered using the same extension-oriented boundaries described in #2527 and #4957. This keeps MCP Apps aligned with
capabilities.extensions["io.modelcontextprotocol/ui"]and avoids embedding MCP Apps-specific behavior directly into the core MCP dispatcher.🧑🏻💻 User Story 1
As a: MCP client or host
I want: ContextForge to advertise MCP Apps through
capabilities.extensionsSo that: clients can negotiate MCP Apps using the official extension capability model.
✅ Acceptance Criteria
🧑🏻💻 User Story 2
As a: platform maintainer
I want: a minimal built-in extension substrate for MCP Apps
So that: MCP Apps is implemented as an extension handler rather than as scattered dispatcher-specific logic.
✅ Acceptance Criteria
🧑🏻💻 User Story 3
As a: server administrator
I want: to register and serve MCP Apps UI resources
So that: tools can return interactive UI metadata backed by
ui://resources.✅ Acceptance Criteria
🧑🏻💻 User Story 4
As a: tool author
I want: tools to declare associated UI resources and app/model visibility
So that: MCP Apps can show interactive views without exposing app-only helper tools to the model.
✅ Acceptance Criteria
🧑🏻💻 User Story 5
As a: security administrator
I want: MCP Apps sessions, AppBridge calls, CSP, and sandbox policy to be enforced
So that: interactive UI content cannot cross server, team, or origin boundaries.
✅ Acceptance Criteria
📐 Design Sketch (optional)
flowchart TD Client[MCP Client / Host] -->|initialize| Gateway[ContextForge] Gateway --> BuiltInExt[Built-in Extension Substrate] BuiltInExt --> UIExt[io.modelcontextprotocol/ui Handler] UIExt --> InitCaps[capabilities.extensions] Client -->|tools/call| ToolSvc[Tool Service] ToolSvc --> UIMeta[_meta.ui.resourceUri] Client -->|resources/read ui://dashboard| ResourceSvc[Resource Service] ResourceSvc --> UIStore[UI Resource Store] AppView[Sandboxed App View] -->|AppBridge JSON-RPC| AppBridge[AppBridge Handler] AppBridge --> Policy[Same-server + RBAC + Token Scope] Policy --> ToolSvc🔗 MCP Standards Check
capabilities.extensionsio.modelcontextprotocol/uiextension identifierui://resources and served through MCP resource flowsNo intentional deviations. Legacy
capabilities.experimentalmay be preserved as compatibility metadata, but it is not the canonical MCP Apps signal.🔄 Alternatives Considered
📓 Additional Context
Related work:
This issue should finish with MCP Apps delivered through a minimal built-in extension-shaped substrate. The broader registry, discovery, generic auto-proxy, Admin API/UI, and custom handler framework can later replace or expand the substrate without requiring MCP Apps to be rewritten as a standalone feature.