Add MCP Apps extension support (typed metadata, attribute, and helpers) (#1484)
This commit is contained in:
parent
de75c7d0df
commit
f93df7e172
12 changed files with 1896 additions and 1 deletions
|
|
@ -50,6 +50,26 @@ internal static class Experimentals
|
|||
/// </summary>
|
||||
public const string Extensions_Url = "https://github.com/modelcontextprotocol/csharp-sdk/blob/main/docs/list-of-diagnostics.md#mcpexp001";
|
||||
|
||||
/// <summary>
|
||||
/// Diagnostic ID for experimental MCP Apps extension APIs.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// MCP Apps is the first official MCP extension (<c>"io.modelcontextprotocol/ui"</c>), enabling
|
||||
/// servers to deliver interactive UIs inside AI clients. This uses a dedicated diagnostic ID
|
||||
/// so that users can suppress it independently from other experimental APIs.
|
||||
/// </remarks>
|
||||
public const string Apps_DiagnosticId = "MCPEXP003";
|
||||
|
||||
/// <summary>
|
||||
/// Message for the experimental MCP Apps extension APIs.
|
||||
/// </summary>
|
||||
public const string Apps_Message = "The MCP Apps extension is experimental and subject to change as the specification evolves.";
|
||||
|
||||
/// <summary>
|
||||
/// URL for the experimental MCP Apps extension APIs.
|
||||
/// </summary>
|
||||
public const string Apps_Url = "https://github.com/modelcontextprotocol/csharp-sdk/blob/main/docs/list-of-diagnostics.md#mcpexp003";
|
||||
|
||||
/// <summary>
|
||||
/// Diagnostic ID for experimental SDK APIs unrelated to the MCP specification,
|
||||
/// such as subclassing <c>McpClient</c>/<c>McpServer</c> or referencing <c>RunSessionHandler</c>.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net10.0;net9.0;net8.0;netstandard2.0</TargetFrameworks>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<IsPackable>true</IsPackable>
|
||||
<PackageId>ModelContextProtocol.Extensions.Apps</PackageId>
|
||||
<Description>MCP Apps extension for the .NET Model Context Protocol (MCP) SDK</Description>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<!-- Suppress the experimental MCP warnings for internal usage -->
|
||||
<NoWarn>$(NoWarn);MCPEXP001;MCPEXP003</NoWarn>
|
||||
<!-- New package with no published baseline yet -->
|
||||
<EnablePackageValidation>false</EnablePackageValidation>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard2.0'">
|
||||
<IsAotCompatible>true</IsAotCompatible>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
|
||||
<!-- CS0436: Allow ObsoleteAttribute to be redefined internally -->
|
||||
<NoWarn>$(NoWarn);CS0436</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Common\Experimentals.cs" Link="Experimentals.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Exclude polyfills inherited from Directory.Build.props; this package only needs the ExperimentalAttribute polyfill. -->
|
||||
<ItemGroup>
|
||||
<Compile Remove="..\Common\Polyfills\**\*.cs" />
|
||||
<Compile Include="..\Common\Polyfills\System\Diagnostics\CodeAnalysis\ExperimentalAttribute.cs"
|
||||
Link="Polyfills\ExperimentalAttribute.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ModelContextProtocol\ModelContextProtocol.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\PACKAGE.md" Pack="true" PackagePath="\README.md" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
using ModelContextProtocol.Protocol;
|
||||
using ModelContextProtocol.Server;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ModelContextProtocol.Extensions.Apps;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies MCP Apps UI metadata for a tool method.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Apply this attribute alongside <see cref="McpServerToolAttribute"/> to associate an MCP Apps
|
||||
/// UI resource with the tool. When processed by <see cref="McpApps.ApplyAppUiAttributes(McpServerTool)"/>
|
||||
/// or <see cref="McpApps.ApplyAppUiAttributes(IEnumerable{McpServerTool})"/>, it populates the
|
||||
/// structured <c>_meta.ui</c> object in the tool's metadata.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Explicit <c>Meta["ui"]</c> set via <see cref="McpServerToolCreateOptions"/> or a raw
|
||||
/// <c>[McpMeta("ui", ...)]</c> attribute takes precedence over this attribute: if the tool
|
||||
/// already has a <c>ui</c> key in <see cref="Tool.Meta"/>, this attribute is ignored.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="csharp">
|
||||
/// [McpServerTool]
|
||||
/// [McpAppUi(ResourceUri = "ui://weather/view.html")]
|
||||
/// [Description("Get current weather for a location")]
|
||||
/// public string GetWeather(string location) => ...;
|
||||
///
|
||||
/// // Restrict visibility to model only:
|
||||
/// [McpServerTool]
|
||||
/// [McpAppUi(ResourceUri = "ui://weather/view.html", Visibility = [McpUiToolVisibility.Model])]
|
||||
/// public string GetWeatherModelOnly(string location) => ...;
|
||||
/// </code>
|
||||
/// </example>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
[Experimental(Experimentals.Apps_DiagnosticId, UrlFormat = Experimentals.Apps_Url)]
|
||||
public sealed class McpAppUiAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the URI of the UI resource associated with this tool.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This should be a <c>ui://</c> URI pointing to the HTML resource registered
|
||||
/// with the server (e.g., <c>"ui://weather/view.html"</c>).
|
||||
/// </remarks>
|
||||
public string? ResourceUri { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the visibility of the tool, controlling which principals can invoke it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Allowed values are <see cref="McpUiToolVisibility.Model"/> and <see cref="McpUiToolVisibility.App"/>.
|
||||
/// When <see langword="null"/> or empty, the tool is visible to both the model and the app (the default).
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public string[]? Visibility { get; set; }
|
||||
}
|
||||
265
src/ModelContextProtocol.Extensions.Apps/Server/McpApps.cs
Normal file
265
src/ModelContextProtocol.Extensions.Apps/Server/McpApps.cs
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
using ModelContextProtocol.Protocol;
|
||||
using ModelContextProtocol.Server;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace ModelContextProtocol.Extensions.Apps;
|
||||
|
||||
/// <summary>
|
||||
/// Provides constants and helper methods for building MCP Apps-enabled servers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// 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.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Use the constants in this class when populating the <c>extensions</c> capability and the
|
||||
/// <c>_meta</c> field of tools and resources. Use <see cref="GetUiCapability"/> to check whether
|
||||
/// the connected client supports the MCP Apps extension.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Use <see cref="SetAppUi"/> to set the <c>_meta.ui</c> metadata on a tool, or
|
||||
/// <see cref="ApplyAppUiAttributes(IEnumerable{McpServerTool})"/> to automatically process
|
||||
/// <see cref="McpAppUiAttribute"/> instances on tools created from methods.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Experimental(Experimentals.Apps_DiagnosticId, UrlFormat = Experimentals.Apps_Url)]
|
||||
public static class McpApps
|
||||
{
|
||||
/// <summary>
|
||||
/// The MIME type used for MCP App HTML resources.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This MIME type should be used when registering UI resources with
|
||||
/// <c>text/html;profile=mcp-app</c> to indicate they are MCP App resources.
|
||||
/// </remarks>
|
||||
public const string HtmlMimeType = "text/html;profile=mcp-app";
|
||||
|
||||
/// <summary>
|
||||
/// The extension identifier used for MCP Apps capability negotiation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This key is used in the <see cref="ClientCapabilities.Extensions"/> and
|
||||
/// <see cref="ServerCapabilities.Extensions"/> dictionaries to advertise support for
|
||||
/// the MCP Apps extension.
|
||||
/// </remarks>
|
||||
public const string ExtensionId = "io.modelcontextprotocol/ui";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonSerializerOptions"/> configured with source-generated metadata
|
||||
/// for MCP Apps extension types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use these options when serializing or deserializing MCP Apps types such as
|
||||
/// <see cref="McpUiToolMeta"/>, <see cref="McpUiClientCapabilities"/>, and <see cref="McpUiResourceMeta"/>.
|
||||
/// </remarks>
|
||||
public static JsonSerializerOptions SerializerOptions { get; } = CreateSerializerOptions();
|
||||
|
||||
private static JsonSerializerOptions CreateSerializerOptions()
|
||||
{
|
||||
var options = new JsonSerializerOptions(McpJsonUtilities.DefaultOptions);
|
||||
options.TypeInfoResolverChain.Insert(0, McpAppsJsonContext.Default);
|
||||
options.MakeReadOnly();
|
||||
return options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the MCP Apps client capability, if advertised by the connected client.
|
||||
/// </summary>
|
||||
/// <param name="capabilities">The client capabilities received during the MCP initialize handshake.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="McpUiClientCapabilities"/> instance if the client advertises support for the MCP Apps extension;
|
||||
/// otherwise, <see langword="null"/>.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Use this method to determine whether the connected client supports the MCP Apps extension
|
||||
/// and to read the client's supported MIME types.
|
||||
/// </remarks>
|
||||
public static McpUiClientCapabilities? GetUiCapability(ClientCapabilities? capabilities)
|
||||
{
|
||||
if (capabilities?.Extensions is not { } extensions ||
|
||||
!extensions.TryGetValue(ExtensionId, out var value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Handle the case where the value was set programmatically (e.g. in tests
|
||||
// or a non-JSON code path) rather than deserialized from the handshake.
|
||||
if (value is McpUiClientCapabilities uiCapabilities)
|
||||
{
|
||||
return uiCapabilities;
|
||||
}
|
||||
|
||||
if (value is JsonElement element)
|
||||
{
|
||||
// Guard against malformed extension values (e.g. a bare string or number)
|
||||
// that would throw JsonException during deserialization. Return null
|
||||
// consistently for any non-object value, matching the other failure modes.
|
||||
if (element.ValueKind is JsonValueKind.Null or JsonValueKind.Undefined)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (element.ValueKind != JsonValueKind.Object)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return JsonSerializer.Deserialize(element, McpAppsJsonContext.Default.McpUiClientCapabilities);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the MCP Apps UI metadata on a tool's <see cref="Tool.Meta"/> property.
|
||||
/// </summary>
|
||||
/// <param name="tool">The tool to set the UI metadata on.</param>
|
||||
/// <param name="appUi">The UI metadata to apply.</param>
|
||||
/// <returns>The same <paramref name="tool"/> instance, for chaining.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method sets the <c>ui</c> key in the tool's <see cref="Tool.Meta"/> object.
|
||||
/// If a <c>ui</c> key is already present in <see cref="Tool.Meta"/>, it is not overwritten.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="tool"/> or <paramref name="appUi"/> is <see langword="null"/>.</exception>
|
||||
public static McpServerTool SetAppUi(McpServerTool tool, McpUiToolMeta appUi)
|
||||
{
|
||||
#if NET
|
||||
ArgumentNullException.ThrowIfNull(tool);
|
||||
ArgumentNullException.ThrowIfNull(appUi);
|
||||
#else
|
||||
if (tool is null) throw new ArgumentNullException(nameof(tool));
|
||||
if (appUi is null) throw new ArgumentNullException(nameof(appUi));
|
||||
#endif
|
||||
|
||||
var protocolTool = tool.ProtocolTool;
|
||||
protocolTool.Meta ??= new JsonObject();
|
||||
|
||||
if (!protocolTool.Meta.ContainsKey("ui"))
|
||||
{
|
||||
var uiNode = JsonSerializer.SerializeToNode(appUi, McpAppsJsonContext.Default.McpUiToolMeta);
|
||||
if (uiNode is not null)
|
||||
{
|
||||
protocolTool.Meta["ui"] = uiNode;
|
||||
}
|
||||
}
|
||||
|
||||
return tool;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the MCP Apps UI metadata on a resource's <see cref="ResourceTemplate.Meta"/> property.
|
||||
/// </summary>
|
||||
/// <param name="resource">The resource to set the UI metadata on.</param>
|
||||
/// <param name="resourceUi">The UI metadata to apply.</param>
|
||||
/// <returns>The same <paramref name="resource"/> instance, for chaining.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method sets the <c>ui</c> key in the resource's <see cref="ResourceTemplate.Meta"/> object.
|
||||
/// If a <c>ui</c> key is already present in <see cref="ResourceTemplate.Meta"/>, it is not overwritten.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="resource"/> or <paramref name="resourceUi"/> is <see langword="null"/>.</exception>
|
||||
public static McpServerResource SetResourceUi(McpServerResource resource, McpUiResourceMeta resourceUi)
|
||||
{
|
||||
#if NET
|
||||
ArgumentNullException.ThrowIfNull(resource);
|
||||
ArgumentNullException.ThrowIfNull(resourceUi);
|
||||
#else
|
||||
if (resource is null) throw new ArgumentNullException(nameof(resource));
|
||||
if (resourceUi is null) throw new ArgumentNullException(nameof(resourceUi));
|
||||
#endif
|
||||
|
||||
var protocolResource = resource.ProtocolResourceTemplate;
|
||||
protocolResource.Meta ??= new JsonObject();
|
||||
|
||||
if (!protocolResource.Meta.ContainsKey("ui"))
|
||||
{
|
||||
var uiNode = JsonSerializer.SerializeToNode(resourceUi, McpAppsJsonContext.Default.McpUiResourceMeta);
|
||||
if (uiNode is not null)
|
||||
{
|
||||
protocolResource.Meta["ui"] = uiNode;
|
||||
}
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes a collection of tools, applying <see cref="McpAppUiAttribute"/> metadata to any
|
||||
/// tool whose underlying method has the attribute.
|
||||
/// </summary>
|
||||
/// <param name="tools">The tools to process.</param>
|
||||
/// <returns>The same <paramref name="tools"/> enumerable, for chaining.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// For each tool that has a <see cref="McpAppUiAttribute"/> in its <see cref="McpServerTool.Metadata"/>,
|
||||
/// this method sets the <c>ui</c> key in the tool's <see cref="Tool.Meta"/> if not already present.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If <see cref="Tool.Meta"/> already contains a <c>ui</c> key (e.g., set explicitly via
|
||||
/// <see cref="McpServerToolCreateOptions.Meta"/>), the attribute is not applied.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="tools"/> is <see langword="null"/>.</exception>
|
||||
public static IEnumerable<McpServerTool> ApplyAppUiAttributes(IEnumerable<McpServerTool> tools)
|
||||
{
|
||||
#if NET
|
||||
ArgumentNullException.ThrowIfNull(tools);
|
||||
#else
|
||||
if (tools is null) throw new ArgumentNullException(nameof(tools));
|
||||
#endif
|
||||
|
||||
foreach (var tool in tools)
|
||||
{
|
||||
ApplyAppUiAttributes(tool);
|
||||
}
|
||||
|
||||
return tools;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes a single tool, applying <see cref="McpAppUiAttribute"/> metadata if the tool's
|
||||
/// underlying method has the attribute.
|
||||
/// </summary>
|
||||
/// <param name="tool">The tool to process.</param>
|
||||
/// <returns>The same <paramref name="tool"/> instance, for chaining.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// If the tool has a <see cref="McpAppUiAttribute"/> in its <see cref="McpServerTool.Metadata"/>,
|
||||
/// this method sets the <c>ui</c> key in the tool's <see cref="Tool.Meta"/> if not already present.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="tool"/> is <see langword="null"/>.</exception>
|
||||
public static McpServerTool ApplyAppUiAttributes(McpServerTool tool)
|
||||
{
|
||||
#if NET
|
||||
ArgumentNullException.ThrowIfNull(tool);
|
||||
#else
|
||||
if (tool is null) throw new ArgumentNullException(nameof(tool));
|
||||
#endif
|
||||
|
||||
// Look for McpAppUiAttribute in tool metadata (attributes from the method)
|
||||
foreach (var metadataItem in tool.Metadata)
|
||||
{
|
||||
if (metadataItem is McpAppUiAttribute appUiAttr)
|
||||
{
|
||||
var meta = new McpUiToolMeta
|
||||
{
|
||||
ResourceUri = appUiAttr.ResourceUri,
|
||||
Visibility = appUiAttr.Visibility,
|
||||
};
|
||||
|
||||
SetAppUi(tool, meta);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return tool;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ModelContextProtocol.Protocol;
|
||||
using ModelContextProtocol.Server;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ModelContextProtocol.Extensions.Apps;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IMcpServerBuilder"/> to enable MCP Apps support.
|
||||
/// </summary>
|
||||
[Experimental(Experimentals.Apps_DiagnosticId, UrlFormat = Experimentals.Apps_Url)]
|
||||
public static class McpAppsBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Enables MCP Apps support by automatically processing <see cref="McpAppUiAttribute"/> on registered tools.
|
||||
/// </summary>
|
||||
/// <param name="builder">The server builder.</param>
|
||||
/// <returns>The builder provided in <paramref name="builder"/>.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Call this method after registering tools (e.g., after <c>WithTools<T>()</c>) to automatically
|
||||
/// apply <see cref="McpAppUiAttribute"/> metadata to the tool's <c>_meta.ui</c> field.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Tools that already have a <c>ui</c> key in their <see cref="Protocol.Tool.Meta"/> (e.g., set explicitly
|
||||
/// via <see cref="McpServerToolCreateOptions.Meta"/>) are not modified.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="csharp">
|
||||
/// builder.Services
|
||||
/// .AddMcpServer()
|
||||
/// .WithTools<MyToolType>()
|
||||
/// .WithMcpApps();
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static IMcpServerBuilder WithMcpApps(this IMcpServerBuilder builder)
|
||||
{
|
||||
#if NET
|
||||
ArgumentNullException.ThrowIfNull(builder);
|
||||
#else
|
||||
if (builder is null) throw new ArgumentNullException(nameof(builder));
|
||||
#endif
|
||||
|
||||
builder.Services.AddSingleton<IPostConfigureOptions<McpServerOptions>, McpAppsPostConfigureOptions>();
|
||||
return builder;
|
||||
}
|
||||
|
||||
private sealed class McpAppsPostConfigureOptions : IPostConfigureOptions<McpServerOptions>
|
||||
{
|
||||
public void PostConfigure(string? name, McpServerOptions options)
|
||||
{
|
||||
// Advertise server-side MCP Apps support in capabilities.
|
||||
options.Capabilities ??= new ServerCapabilities();
|
||||
options.Capabilities.Extensions ??= new Dictionary<string, object>();
|
||||
if (!options.Capabilities.Extensions.ContainsKey(McpApps.ExtensionId))
|
||||
{
|
||||
options.Capabilities.Extensions[McpApps.ExtensionId] = new System.Text.Json.Nodes.JsonObject();
|
||||
}
|
||||
|
||||
if (options.ToolCollection is { IsEmpty: false } tools)
|
||||
{
|
||||
foreach (var tool in tools)
|
||||
{
|
||||
McpApps.ApplyAppUiAttributes(tool);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ModelContextProtocol.Extensions.Apps;
|
||||
|
||||
/// <summary>
|
||||
/// Provides source-generated JSON serialization metadata for MCP Apps extension types.
|
||||
/// </summary>
|
||||
[JsonSourceGenerationOptions(
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
|
||||
[JsonSerializable(typeof(McpUiToolMeta))]
|
||||
[JsonSerializable(typeof(McpUiClientCapabilities))]
|
||||
[JsonSerializable(typeof(McpUiResourceMeta))]
|
||||
[JsonSerializable(typeof(McpUiResourceCsp))]
|
||||
[JsonSerializable(typeof(McpUiResourcePermissions))]
|
||||
internal sealed partial class McpAppsJsonContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ModelContextProtocol.Extensions.Apps;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the MCP Apps capabilities advertised by a client.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This object is the value associated with the <c>"io.modelcontextprotocol/ui"</c> key in the
|
||||
/// <see cref="Protocol.ClientCapabilities.Extensions"/> dictionary.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Experimental(Experimentals.Apps_DiagnosticId, UrlFormat = Experimentals.Apps_Url)]
|
||||
public sealed class McpUiClientCapabilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the list of MIME types supported by the client for MCP App UI resources.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A client that supports MCP Apps must include <c>"text/html;profile=mcp-app"</c> in this list.
|
||||
/// </remarks>
|
||||
[JsonPropertyName("mimeTypes")]
|
||||
public IList<string>? MimeTypes { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ModelContextProtocol.Extensions.Apps;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the Content Security Policy (CSP) domain allowlists for an MCP Apps UI resource.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// These allowlists are used by the MCP host to construct the Content-Security-Policy HTTP header
|
||||
/// for the sandboxed iframe that hosts the UI resource.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Each list contains origins (e.g., <c>"https://api.example.com"</c>) that are permitted for
|
||||
/// the corresponding CSP directive.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Experimental(Experimentals.Apps_DiagnosticId, UrlFormat = Experimentals.Apps_Url)]
|
||||
public sealed class McpUiResourceCsp
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the list of origins allowed for fetch, XMLHttpRequest, WebSocket, and EventSource
|
||||
/// connections (<c>connect-src</c> CSP directive).
|
||||
/// </summary>
|
||||
[JsonPropertyName("connectDomains")]
|
||||
public IList<string>? ConnectDomains { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of origins allowed for loading scripts, stylesheets, images, and fonts
|
||||
/// (<c>script-src</c>, <c>style-src</c>, <c>img-src</c>, <c>font-src</c> CSP directives).
|
||||
/// </summary>
|
||||
[JsonPropertyName("resourceDomains")]
|
||||
public IList<string>? ResourceDomains { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of origins allowed for loading nested frames
|
||||
/// (<c>frame-src</c> CSP directive).
|
||||
/// </summary>
|
||||
[JsonPropertyName("frameDomains")]
|
||||
public IList<string>? FrameDomains { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of allowed base URIs
|
||||
/// (<c>base-uri</c> CSP directive).
|
||||
/// </summary>
|
||||
[JsonPropertyName("baseUris")]
|
||||
public IList<string>? BaseUris { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ModelContextProtocol.Extensions.Apps;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the UI metadata associated with an MCP resource in the MCP Apps extension.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This metadata is placed under the <c>ui</c> key in the resource's <c>_meta</c> object.
|
||||
/// It provides Content Security Policy (CSP) configuration, sandbox permissions, CORS origin, and
|
||||
/// visual boundary preferences for the UI resource served by this MCP server.
|
||||
/// </remarks>
|
||||
[Experimental(Experimentals.Apps_DiagnosticId, UrlFormat = Experimentals.Apps_Url)]
|
||||
public sealed class McpUiResourceMeta
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Content Security Policy configuration for this resource.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Specifies the allowed origins for network requests, resource loads, and nested frames.
|
||||
/// </remarks>
|
||||
[JsonPropertyName("csp")]
|
||||
public McpUiResourceCsp? Csp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sandbox permissions for this resource.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Controls which browser sandbox features the UI resource is allowed to use.
|
||||
/// </remarks>
|
||||
[JsonPropertyName("permissions")]
|
||||
public McpUiResourcePermissions? Permissions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the dedicated origin domain for this resource.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When set, the host will serve the resource from this dedicated origin,
|
||||
/// enabling OAuth flows and CORS without wildcard exceptions.
|
||||
/// </remarks>
|
||||
[JsonPropertyName("domain")]
|
||||
public string? Domain { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the host should render a visual border around the UI.
|
||||
/// </summary>
|
||||
[JsonPropertyName("prefersBorder")]
|
||||
public bool? PrefersBorder { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ModelContextProtocol.Extensions.Apps;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the sandbox permissions requested by an MCP Apps UI resource.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This maps to the <c>allow</c> attribute on the iframe sandbox in the MCP host.
|
||||
/// Permissions are specified as standard browser iframe permission strings,
|
||||
/// such as <c>"camera"</c>, <c>"microphone"</c>, or <c>"geolocation"</c>.
|
||||
/// </remarks>
|
||||
[Experimental(Experimentals.Apps_DiagnosticId, UrlFormat = Experimentals.Apps_Url)]
|
||||
public sealed class McpUiResourcePermissions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the list of permissions granted to the sandboxed UI resource.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// These correspond to values allowed in the <c>allow</c> attribute of an HTML iframe,
|
||||
/// for example <c>"camera"</c>, <c>"microphone"</c>, <c>"geolocation"</c>,
|
||||
/// <c>"clipboard-read"</c>, or <c>"clipboard-write"</c>.
|
||||
/// </remarks>
|
||||
[JsonPropertyName("allow")]
|
||||
public IList<string>? Allow { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ModelContextProtocol.Extensions.Apps;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the UI metadata associated with an MCP tool in the MCP Apps extension.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This metadata is placed under the <c>ui</c> key in the tool's <c>_meta</c> object.
|
||||
/// It associates the tool with a UI resource (identified by a <c>ui://</c> URI) and optionally
|
||||
/// controls which principals (model, app) can call the tool.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Experimental(Experimentals.Apps_DiagnosticId, UrlFormat = Experimentals.Apps_Url)]
|
||||
public sealed class McpUiToolMeta
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the URI of the UI resource associated with this tool.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This should be a <c>ui://</c> URI pointing to the HTML resource registered
|
||||
/// with the server (e.g., <c>"ui://weather/view.html"</c>).
|
||||
/// </remarks>
|
||||
[JsonPropertyName("resourceUri")]
|
||||
public string? ResourceUri { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the visibility of the tool, controlling which principals can invoke it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Allowed values are <see cref="McpUiToolVisibility.Model"/> (<c>"model"</c>) and
|
||||
/// <see cref="McpUiToolVisibility.App"/> (<c>"app"</c>). When <see langword="null"/>
|
||||
/// or empty, the tool is visible to both the model and the app (the default).
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[JsonPropertyName("visibility")]
|
||||
public IList<string>? Visibility { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ModelContextProtocol.Extensions.Apps;
|
||||
|
||||
/// <summary>
|
||||
/// Provides well-known visibility values for <see cref="McpUiToolMeta.Visibility"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use these constants to specify which principals can invoke a tool in the MCP Apps extension.
|
||||
/// When <see cref="McpUiToolMeta.Visibility"/> is <see langword="null"/> or empty, the tool
|
||||
/// is visible to both the model and the app by default.
|
||||
/// </remarks>
|
||||
[Experimental(Experimentals.Apps_DiagnosticId, UrlFormat = Experimentals.Apps_Url)]
|
||||
public static class McpUiToolVisibility
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that the tool can be invoked by the AI model.
|
||||
/// </summary>
|
||||
public const string Model = "model";
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the tool can be invoked by the UI app (iframe).
|
||||
/// </summary>
|
||||
public const string App = "app";
|
||||
}
|
||||
Loading…
Reference in a new issue