-
Notifications
You must be signed in to change notification settings - Fork 663
Description
MCP Apps Support for the C# SDK — Product Requirements Document
Background
MCP Apps is the first official extension to the Model Context Protocol, co-developed by Anthropic and OpenAI and released as an open standard in January 2026. It enables MCP servers to deliver interactive user interfaces — dashboards, forms, visualizations, and more — directly inside conversational AI clients such as Claude, ChatGPT, VS Code, and Goose.
The extension is specified in ext-apps/specification/2026-01-26/apps.mdx and uses existing MCP primitives (tools, resources, capabilities) augmented with:
ui://URI scheme for UI resources_meta.uimetadata on tools to associate them with UI resourcesextensionscapability negotiation via the"io.modelcontextprotocol/ui"keytext/html;profile=mcp-appMIME type for HTML UI resources- CSP configuration for sandboxed iframe security
The UI protocol itself (ui/initialize, ui/context, etc.) runs between the host (chat client iframe bridge) and the view (iframe app) — not through the standard MCP client/server channel. Therefore, the base SDKs primarily need to support capability negotiation, typed metadata, and convenience helpers for server authors.
Current State of SDK Support
TypeScript SDK (@modelcontextprotocol/sdk)
The TypeScript SDK provides the foundation, and a dedicated package @modelcontextprotocol/ext-apps delivers full MCP Apps support:
extensionsfield onClientCapabilitiesandServerCapabilities- Generic
_metaon tool definitions @modelcontextprotocol/ext-apps/servermodule with:registerAppTool()— registers tools with normalized UI metadataregisterAppResource()— registers resources with default MCP Apps MIME typegetUiCapability()— reads MCP Apps capabilities from client- Typed interfaces:
McpUiToolMeta,McpUiResourceMeta,McpUiResourceCsp,McpUiClientCapabilities - Constants:
RESOURCE_MIME_TYPE,EXTENSION_ID,RESOURCE_URI_META_KEY
Python SDK (mcp)
extensionsfield exists on capabilities in_types.py- Generic
_metasupport on tool definitions - No dedicated MCP Apps helpers — servers must manually populate
_meta.uiand serveui://resources
Java SDK
- No explicit MCP Apps support
- Open feature request: java-sdk#780 (status: waiting for triage)
- The Spring AI
mcp-annotationsproject is exploring ergonomic_metaattribute handling
C# SDK (ModelContextProtocol)
The C# SDK has the foundational primitives in place:
| Feature | Status | Location |
|---|---|---|
Extensions on ServerCapabilities |
✅ Present | IDictionary<string, object>?, marked [Experimental] |
Extensions on ClientCapabilities |
✅ Present | Same as above |
_meta on Tool |
✅ Present | JsonObject? Meta property |
| Resources capability | ✅ Present | Standard resource registration |
A C# MCP server can support MCP Apps today by manually constructing the _meta JSON and serving ui:// resources. However, the experience is untyped, error-prone, and requires knowledge of the spec's internal structure.
Proposed Features
The goal is to add a convenience layer to the C# SDK — analogous to @modelcontextprotocol/ext-apps/server in TypeScript — that makes it easy for C# server authors to build MCP Apps.
F1: Constants
Define well-known constants used throughout the MCP Apps extension:
| Constant | Value | Purpose |
|---|---|---|
ResourceMimeType |
"text/html;profile=mcp-app" |
MIME type for MCP App HTML resources |
ExtensionId |
"io.modelcontextprotocol/ui" |
Key in extensions for capability negotiation |
ResourceUriMetaKey |
"ui/resourceUri" |
Legacy flat _meta key (deprecated but needed for backward compat) |
F2: Typed Metadata Models
Provide strongly-typed C# classes for MCP Apps metadata, eliminating the need to construct raw JSON:
-
McpUiToolMeta— UI metadata for toolsResourceUri(string?) — URI of the UI resource (e.g.,"ui://weather/view.html")Visibility(IList<McpUiToolVisibility>?) — Who can access the tool:"model","app", or both (default)
-
McpUiResourceMeta— UI metadata for resourcesCsp(McpUiResourceCsp?) — Content Security Policy configurationPermissions(McpUiResourcePermissions?) — Sandbox permissionsDomain(string?) — Dedicated origin for CORS/OAuthPrefersBorder(bool?) — Visual boundary preference
-
McpUiResourceCsp— CSP domain allowlistsConnectDomains(IList<string>?) — Origins for fetch/XHR/WebSocket (connect-src)ResourceDomains(IList<string>?) — Origins for scripts/styles/images/fontsFrameDomains(IList<string>?) — Origins for nested iframes (frame-src)BaseUris(IList<string>?) — Allowed base URIs (base-uri)
-
McpUiClientCapabilities— Client-advertised MCP Apps capabilitiesMimeTypes(IList<string>?) — Supported MIME types (must include"text/html;profile=mcp-app")
-
McpUiToolVisibility— Enum or string constants:"model","app"
F3: GetUiCapability() Helper
A helper method to extract MCP Apps capability settings from client capabilities:
public static McpUiClientCapabilities? GetUiCapability(ClientCapabilities? capabilities)- Reads
capabilities.Extensions["io.modelcontextprotocol/ui"] - Deserializes to
McpUiClientCapabilities - Returns
nullif extensions are missing or MCP Apps is not advertised
This enables server authors to conditionally register app-enhanced vs. text-only tools based on client support.
F4: Tool Registration Helper
A convenience method for registering tools with UI metadata:
public static void RegisterAppTool(McpServer server, string name, McpUiAppToolConfig config, ToolCallback callback)Key behaviors:
- Accepts a typed
McpUiAppToolConfigthat includesMcpUiToolMeta - Normalizes metadata: if
_meta.ui.resourceUriis set, also populates the legacy_meta["ui/resourceUri"]key (and vice versa) for compatibility with older hosts - Delegates to the standard
RegisterToolmethod
F5: Resource Registration Helper
A convenience method for registering UI resources:
public static void RegisterAppResource(McpServer server, string name, string uri, McpUiAppResourceConfig config, ReadResourceCallback callback)Key behaviors:
- Defaults the MIME type to
"text/html;profile=mcp-app"(can be overridden) - Accepts optional
McpUiResourceMetafor CSP, permissions, domain configuration - Delegates to the standard
RegisterResourcemethod
F6: Attribute-Based UI Metadata (McpAppUiAttribute)
The C# SDK's idiomatic tool declaration pattern uses [McpServerTool] with attributes:
[McpServerTool]
[Description("Get current weather for a location")]
public string GetWeather(string location) => ...;Today, UI metadata can technically be added via the generic [McpMeta] attribute with raw JSON:
[McpServerTool]
[McpMeta("ui", JsonValue = """{"resourceUri": "ui://weather/view.html"}""")]
public string GetWeather(string location) => ...;This works because McpMetaAttribute supports arbitrary JSON values and the CreateMetaFromAttributes pipeline in AIFunctionMcpServerTool adds them to Tool.Meta. However, it has significant drawbacks:
- Not type-safe — the JSON is a raw string; typos in field names silently pass
- Not discoverable — no IntelliSense for nested
resourceUri,visibility, etc. - No backward-compat normalization — doesn't also set the legacy
_meta["ui/resourceUri"]key - Verbose — requires knowledge of the spec's exact JSON structure
A dedicated attribute would provide a first-class experience:
[McpServerTool]
[McpAppUi(ResourceUri = "ui://weather/view.html")]
[Description("Get current weather for a location")]
public string GetWeather(string location) => ...;McpAppUiAttribute properties:
| Property | Type | Description |
|---|---|---|
ResourceUri |
string |
URI of the UI resource (e.g., "ui://weather/view.html") |
Visibility |
string[]? |
Who can access the tool: "model", "app", or both (default) |
Implementation considerations:
- The attribute should be processed in the existing
CreateMetaFromAttributespipeline (or alongside it) inAIFunctionMcpServerTool - When present, it should populate both
_meta.ui.resourceUriand the legacy_meta["ui/resourceUri"]key for backward compatibility with older hosts - It should take precedence over any raw
[McpMeta("ui", ...)]on the same method - Following the SDK's existing pattern, this could be marked
[Experimental]initially, matching theExtensionsproperty
This is analogous to how McpServerToolAttribute already has typed properties for Destructive, ReadOnly, Idempotent, OpenWorld, and TaskSupport — rather than requiring developers to construct ToolAnnotations or ToolExecution JSON manually.
F7: Programmatic UI Metadata on McpServerToolCreateOptions
For tools created programmatically via McpServerTool.Create(delegate, options), the McpServerToolCreateOptions class should also support typed UI metadata. Currently developers would need to manually construct the Meta JsonObject:
// Current: manual JSON construction
var tool = McpServerTool.Create(handler, new McpServerToolCreateOptions
{
Meta = new JsonObject
{
["ui"] = JsonSerializer.SerializeToNode(new { resourceUri = "ui://weather/view.html" }),
["ui/resourceUri"] = "ui://weather/view.html" // legacy key — easy to forget
}
});A typed property would be cleaner:
// Proposed: typed property
var tool = McpServerTool.Create(handler, new McpServerToolCreateOptions
{
AppUi = new McpUiToolMeta
{
ResourceUri = "ui://weather/view.html",
Visibility = ["model", "app"]
}
});The McpServerToolCreateOptions.AppUi property would:
- Merge into
Metaduring tool creation, populating both_meta.uiand_meta["ui/resourceUri"] - Be overridden by explicit
Metaentries if both are set (consistent with howMcpMetaAttributedoesn't overwrite existing properties)
Out of Scope
The following are not in scope for this work:
- UI protocol implementation (
ui/initialize,ui/context,ui/message, etc.) — this runs between host and view iframe, not through the MCP SDK Appclass /AppBridgeclass — these are client-side JavaScript constructs for the iframe- React/Blazor hooks — UI framework integrations for the view side
PostMessageTransport— browser-specific iframe communication
These would belong in a separate C# host-side or view-side package if needed.
References
- MCP Apps Specification
- MCP Apps Announcement
- ext-apps TypeScript SDK — reference implementation
- C# SDK Repository
- Java SDK Feature Request #780 — comparable request for Java