Skip to content

Latest commit

 

History

History
191 lines (135 loc) · 7.4 KB

File metadata and controls

191 lines (135 loc) · 7.4 KB
title MCP Apps
author mikekistler
description How to use the MCP Apps extension to deliver interactive UIs from MCP servers.
uid apps

MCP Apps

MCP Apps is an extension to the Model Context Protocol that enables MCP servers to deliver interactive user interfaces — dashboards, forms, visualizations, and more — directly inside conversational AI clients.

Important

MCP Apps support is experimental. All types are marked with [Experimental("MCPEXP003")] and require suppressing that diagnostic to use.

Installation

MCP Apps is provided in the ModelContextProtocol.Extensions.Apps package, which layers on top of the core SDK:

dotnet add package ModelContextProtocol.Extensions.Apps

Overview

The MCP Apps extension introduces the concept of UI resources — HTML pages served by the MCP server that a client can display alongside the conversation. Tools can be associated with a UI resource so the client knows which interface to show when a tool is called.

The key concepts are:

  • UI capability negotiation — Client and server declare support via extensions["io.modelcontextprotocol/ui"]
  • UI resources — HTML content served with the MIME type text/html;profile=mcp-app
  • Tool UI metadata — Tools declare their associated UI resource in _meta.ui

Associating tools with UI resources

Using the builder extension (recommended)

The simplest approach is to apply [McpAppUi] attributes to your tool methods and call WithMcpApps() on the server builder:

[McpServerToolType]
public class WeatherTools
{
    [McpServerTool, Description("Get current weather for a location")]
    [McpAppUi(ResourceUri = "ui://weather/view.html")]
    public static string GetWeather(string location) => $"Weather for {location}";

    [McpServerTool, Description("Get forecast (model-only tool)")]
    [McpAppUi(ResourceUri = "ui://weather/forecast.html", Visibility = [McpUiToolVisibility.Model])]
    public static string GetForecast(string location) => $"Forecast for {location}";
}
builder.Services.AddMcpServer()
    .WithTools<WeatherTools>()
    .WithMcpApps();

The WithMcpApps() call registers a post-configuration step that processes all registered tools and applies [McpAppUi] attribute metadata to their _meta.ui field automatically.

Using the attribute with manual processing

If you create tools manually (without WithMcpApps()), you can still use the attribute and process tools explicitly:

var tools = new[]
{
    McpServerTool.Create(typeof(WeatherTools).GetMethod(nameof(WeatherTools.GetWeather))!),
    McpServerTool.Create(typeof(WeatherTools).GetMethod(nameof(WeatherTools.GetForecast))!),
};

McpApps.ApplyAppUiAttributes(tools);

Using the programmatic API

For full control, use McpApps.SetAppUi to set UI metadata directly:

var tool = McpServerTool.Create((string location) => $"Weather for {location}");

McpApps.SetAppUi(tool, new McpUiToolMeta
{
    ResourceUri = "ui://weather/view.html",
    Visibility = [McpUiToolVisibility.Model, McpUiToolVisibility.App],
});

Checking client capabilities

During a session, you can check whether the connected client supports MCP Apps:

[McpServerTool, Description("Get weather")]
[McpAppUi(ResourceUri = "ui://weather/view.html")]
public static string GetWeather(McpServer server, string location)
{
    var uiCapability = McpApps.GetUiCapability(server.ClientCapabilities);
    if (uiCapability is not null)
    {
        // Client supports MCP Apps — the UI will be displayed
    }

    return $"Weather for {location}";
}

Tool visibility

The Visibility property controls which principals can invoke the tool:

Value Meaning
McpUiToolVisibility.Model Only the LLM can call this tool
McpUiToolVisibility.App Only the app UI can call this tool
Both (or null/empty) Both the model and app can call the tool (default)

UI resources

UI resources are HTML pages registered with the MCP server using the ui:// URI scheme and the text/html;profile=mcp-app MIME type. The McpUiResourceMeta type provides metadata for these resources, including:

  • CSP (Content Security Policy) — Controls allowed origins for network requests and resource loads
  • Permissions — Sandbox permissions (scripts, forms, popups, etc.)
  • Domain — Dedicated origin for OAuth flows and CORS
  • PrefersBorder — Whether the host should render a visual border

App-only tools

Tools with Visibility = [McpUiToolVisibility.App] are not visible to the LLM — they are intended only for use by the app UI. This is useful for tools that serve UI interaction (button handlers, form submissions) without cluttering the model's tool list:

[McpServerTool, Description("Submit the weather form")]
[McpAppUi(ResourceUri = "ui://weather/view.html", Visibility = [McpUiToolVisibility.App])]
public static string SubmitWeatherForm(string city) => GetWeatherHtml(city);

Graceful degradation

Not all clients support MCP Apps. Use GetUiCapability to detect support and return text-only content as a fallback:

[McpServerTool, Description("Get weather")]
[McpAppUi(ResourceUri = "ui://weather/view.html")]
public static string GetWeather(McpServer server, string location)
{
    var uiCapability = McpApps.GetUiCapability(server.ClientCapabilities);
    if (uiCapability is null)
    {
        // Client doesn't support MCP Apps — return plain text
        return $"Current weather for {location}: 72°F, sunny";
    }

    // Client supports MCP Apps — the UI resource will be displayed
    return $"Weather data for {location} loaded into UI";
}

Display modes

The MCP Apps spec defines display modes (inline, fullscreen, pip) that control how the host renders the UI. Display mode is negotiated between the client and server during capability exchange and is not set per-tool — it depends on the host implementation.

Host theming

Hosts pass standardized CSS custom properties (e.g., --color-background-primary, --color-text-primary) to app iframes. Your HTML can reference these variables to automatically match the host's theme without any server-side configuration.

See the MCP Apps specification for the full list of CSS variables.

Single-file HTML bundling

The default Content Security Policy restricts external script and style loads. For production apps, bundle all JavaScript and CSS into a single HTML file using tools like vite-plugin-singlefile. For simple apps, inline <script> and <style> tags work directly.

Constants

The xref:ModelContextProtocol.Extensions.Apps.McpApps class provides constants for protocol values:

Constant Value Usage
McpApps.ResourceMimeType text/html;profile=mcp-app MIME type for UI resources
McpApps.ExtensionId io.modelcontextprotocol/ui Key in extensions capability dictionary

Serialization

MCP Apps types use source-generated JSON serialization for Native AOT compatibility. Use McpApps.SerializerOptions when serializing extension types:

var json = JsonSerializer.Serialize(toolMeta, McpApps.SerializerOptions);
var deserialized = JsonSerializer.Deserialize<McpUiToolMeta>(json, McpApps.SerializerOptions);