Add support for URL mode elicitation (#1021)
This commit is contained in:
parent
c447973972
commit
ae17ba0b4b
1 changed files with 1241 additions and 92 deletions
|
|
@ -1,4 +1,5 @@
|
|||
using System.ComponentModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using ModelContextProtocol.Client;
|
||||
|
||||
|
|
@ -10,17 +11,117 @@ namespace ModelContextProtocol.Protocol;
|
|||
/// <remarks>
|
||||
/// <para>
|
||||
/// This capability enables the MCP client to respond to elicitation requests from an MCP server.
|
||||
/// Clients must support at least one elicitation mode: form (in-band) or url (out-of-band via URL).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// When this capability is enabled, an MCP server can request the client to provide additional information
|
||||
/// during interactions. The client must set a <see cref="McpClientHandlers.ElicitationHandler"/> to process these requests.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This class is intentionally empty as the Model Context Protocol specification does not
|
||||
/// currently define additional properties for sampling capabilities. Future versions of the
|
||||
/// specification may extend this capability with additional configuration options.
|
||||
/// Two modes of elicitation are supported:
|
||||
/// <list type="bullet">
|
||||
/// <item><description><b>form</b>: In-band elicitation where data is collected via a form and exposed to the client</description></item>
|
||||
/// <item><description><b>url</b>: URL mode (out-of-band) elicitation via navigation where sensitive data is not exposed to the client</description></item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[JsonConverter(typeof(Converter))]
|
||||
public sealed class ElicitationCapability
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the form mode elicitation (in-band) capability, indicating support for in-band elicitation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When present, indicates the client supports form mode elicitation where structured data
|
||||
/// is collected through a form interface and returned to the server.
|
||||
/// </remarks>
|
||||
[JsonPropertyName("form")]
|
||||
public FormElicitationCapability? Form { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the URL mode (out-of-band) elicitation capability.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When present, indicates the client supports URL mode elicitation for secure out-of-band
|
||||
/// interactions such as OAuth flows, payments, or collecting sensitive credentials.
|
||||
/// </remarks>
|
||||
[JsonPropertyName("url")]
|
||||
public UrlElicitationCapability? Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Provides a converter that normalizes blank capability objects to imply form support.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public sealed class Converter : JsonConverter<ElicitationCapability>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override ElicitationCapability? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using var document = JsonDocument.ParseValue(ref reader);
|
||||
|
||||
if (document.RootElement.ValueKind != JsonValueKind.Object)
|
||||
{
|
||||
throw new JsonException("elicitation capability must be an object.");
|
||||
}
|
||||
|
||||
var capability = new ElicitationCapability();
|
||||
bool hasForm = false;
|
||||
bool hasUrl = false;
|
||||
|
||||
foreach (var property in document.RootElement.EnumerateObject())
|
||||
{
|
||||
if (property.NameEquals("form"))
|
||||
{
|
||||
capability.Form = property.Value.ValueKind == JsonValueKind.Null
|
||||
? null
|
||||
: capability.Form ?? new FormElicitationCapability();
|
||||
hasForm = true;
|
||||
}
|
||||
else if (property.NameEquals("url"))
|
||||
{
|
||||
capability.Url = property.Value.ValueKind == JsonValueKind.Null
|
||||
? null
|
||||
: capability.Url ?? new UrlElicitationCapability();
|
||||
hasUrl = capability.Url is not null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasForm && !hasUrl)
|
||||
{
|
||||
capability.Form = new FormElicitationCapability();
|
||||
}
|
||||
|
||||
return capability;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(Utf8JsonWriter writer, ElicitationCapability value, JsonSerializerOptions options)
|
||||
{
|
||||
Throw.IfNull(writer);
|
||||
|
||||
writer.WriteStartObject();
|
||||
|
||||
bool writeForm = value.Form is not null || value.Url is null;
|
||||
if (writeForm)
|
||||
{
|
||||
writer.WritePropertyName("form");
|
||||
writer.WriteStartObject();
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
if (value.Url is not null)
|
||||
{
|
||||
writer.WritePropertyName("url");
|
||||
writer.WriteStartObject();
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue