Add MCP Apps extension support (typed metadata, attribute, and helpers) (#1484)
This commit is contained in:
parent
de75c7d0df
commit
f93df7e172
4 changed files with 1896 additions and 1 deletions
191
docs/concepts/apps/apps.md
Normal file
191
docs/concepts/apps/apps.md
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
---
|
||||
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.
|
||||
|
||||
[MCP Apps]: https://modelcontextprotocol.io/extensions/apps/overview
|
||||
|
||||
> [!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:
|
||||
|
||||
```shell
|
||||
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:
|
||||
|
||||
```csharp
|
||||
[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}";
|
||||
}
|
||||
```
|
||||
|
||||
```csharp
|
||||
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:
|
||||
|
||||
```csharp
|
||||
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:
|
||||
|
||||
```csharp
|
||||
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:
|
||||
|
||||
```csharp
|
||||
[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:
|
||||
|
||||
```csharp
|
||||
[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:
|
||||
|
||||
```csharp
|
||||
[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](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx) 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](https://github.com/richardtallent/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.HtmlMimeType` | `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:
|
||||
|
||||
```csharp
|
||||
var json = JsonSerializer.Serialize(toolMeta, McpApps.SerializerOptions);
|
||||
var deserialized = JsonSerializer.Deserialize<McpUiToolMeta>(json, McpApps.SerializerOptions);
|
||||
```
|
||||
|
|
@ -41,4 +41,10 @@ Install the SDK and build your first MCP client and server.
|
|||
| [Stateless and Stateful](stateless/stateless.md) | Learn when to use stateless vs. stateful mode for HTTP servers and how to configure sessions. |
|
||||
| [HTTP Context](httpcontext/httpcontext.md) | Learn how to access the underlying `HttpContext` for a request. |
|
||||
| [MCP Server Handler Filters](filters.md) | Learn how to add filters to the handler pipeline. Filters let you wrap the original handler with additional functionality. |
|
||||
|
||||
### Extensions
|
||||
|
||||
| Title | Description |
|
||||
| - | - |
|
||||
| [MCP Apps](apps/apps.md) | Learn how to use the MCP Apps extension to deliver interactive UIs from MCP servers. |
|
||||
| [Identity and Roles](identity/identity.md) | Learn how to access caller identity and roles in MCP tool, prompt, and resource handlers. |
|
||||
|
|
|
|||
|
|
@ -47,5 +47,9 @@ items:
|
|||
uid: httpcontext
|
||||
- name: Filters
|
||||
uid: filters
|
||||
- name: Extensions
|
||||
items:
|
||||
- name: MCP Apps
|
||||
uid: apps
|
||||
- name: Identity and Roles
|
||||
uid: identity
|
||||
uid: identity
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ If you use experimental APIs, you will get one of the diagnostics shown below. T
|
|||
| :------------ | :---------- |
|
||||
| `MCPEXP001` | Experimental APIs for features in the MCP specification itself, including Tasks and Extensions. Tasks provide a mechanism for asynchronous long-running operations that can be polled for status and results (see [SEP-2663](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md)). Extensions provide a framework for extending the Model Context Protocol while maintaining interoperability (see [SEP-2133](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2133)). |
|
||||
| `MCPEXP002` | Experimental SDK APIs unrelated to the MCP specification itself, including subclassing `McpClient`/`McpServer` (see [#1363](https://github.com/modelcontextprotocol/csharp-sdk/pull/1363)) and `RunSessionHandler`, which may be removed or change signatures in a future release (consider using `ConfigureSessionOptions` instead). |
|
||||
| `MCPEXP003` | Experimental MCP Apps extension APIs. MCP Apps is the first official MCP extension (`io.modelcontextprotocol/ui`), enabling servers to deliver interactive UIs inside AI clients (see [MCP Apps specification](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx)). |
|
||||
|
||||
## Obsolete APIs
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue