blob: 8802772d0e821b811c033b0260641bea2ab18510 [file]
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of 'api.dart';
/// One extension identifier: a prefix of dot separated labels, a slash, and a
/// name which may be empty.
///
/// A label starts with a letter and ends with a letter or digit, with letters,
/// digits and hyphens in between. A name which is not empty starts and ends
/// with an alphanumeric character, with alphanumerics, hyphens, underscores
/// and dots in between. These are the `_meta` key naming rules, except that
/// the prefix a `_meta` key may leave out is required here.
///
/// Read 2026-09-07 from
/// https://modelcontextprotocol.io/specification/2026-07-28/schema#metaobject.
final _extensionIdentifierPattern = RegExp(
r'^[A-Za-z](?:[A-Za-z0-9-]*[A-Za-z0-9])?'
r'(?:\.[A-Za-z](?:[A-Za-z0-9-]*[A-Za-z0-9])?)*'
r'/(?:[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?)?$',
);
/// Throws an [ArgumentError] unless [extensions] is a map keyed by extension
/// identifiers.
///
/// Reads [extensions] and leaves it alone, so a caller keeps the map it
/// passed in and the settings under each identifier.
void _validateExtensions(Object? extensions) {
if (extensions is! Map) {
throw ArgumentError.value(
extensions,
'extensions',
'Must be a map keyed by extension identifiers',
);
}
for (final identifier in extensions.keys) {
if (identifier is! String ||
!_extensionIdentifierPattern.hasMatch(identifier)) {
throw ArgumentError.value(
identifier,
'extensions',
'Must use the vendor-prefix/extension-name format',
);
}
}
}
/// Throws an [ArgumentError] unless the extensions in [capabilities] are
/// valid.
void _validateCapabilityMap(Map<String, Object?> capabilities) {
if (capabilities.containsKey(Keys.extensions)) {
_validateExtensions(capabilities[Keys.extensions]);
}
}
ClientCapabilities _validatedClientCapabilities(
ClientCapabilities capabilities,
) => ClientCapabilities.fromMap(capabilities._value);
ServerCapabilities _validatedServerCapabilities(
ServerCapabilities capabilities,
) => ServerCapabilities.fromMap(capabilities._value);
/// This request is sent from the client to the server when it first connects,
/// asking it to begin initialization.
extension type InitializeRequest._fromMap(Map<String, Object?> _value)
implements Request {
static const methodName = 'initialize';
factory InitializeRequest({
required ProtocolVersion protocolVersion,
required ClientCapabilities capabilities,
required Implementation clientInfo,
MetaWithProgressToken? meta,
}) => InitializeRequest._fromMap({
Keys.protocolVersion: protocolVersion.versionString,
Keys.capabilities: _validatedClientCapabilities(capabilities),
Keys.clientInfo: clientInfo,
if (meta != null) Keys.meta: meta,
});
/// The latest version of the Model Context Protocol that the client supports.
///
/// The client MAY decide to support older versions as well.
///
/// May be `null` if the version is not recognized.
ProtocolVersion? get protocolVersion =>
ProtocolVersion.tryParse(_value[Keys.protocolVersion] as String? ?? '');
ClientCapabilities get capabilities {
final capabilities = _value[Keys.capabilities] as Map<String, Object?>?;
if (capabilities == null) {
throw ArgumentError('Missing capabilities field in $InitializeRequest.');
}
return ClientCapabilities.fromMap(capabilities);
}
Implementation get clientInfo {
final clientInfo = _value[Keys.clientInfo] as Implementation?;
if (clientInfo == null) {
throw ArgumentError('Missing clientInfo field in $InitializeRequest.');
}
return clientInfo;
}
}
/// After receiving an initialize request from the client, the server sends
/// this response.
extension type InitializeResult.fromMap(Map<String, Object?> _value)
implements Result {
factory InitializeResult({
required ProtocolVersion protocolVersion,
required ServerCapabilities serverCapabilities,
required Implementation serverInfo,
String? instructions,
}) => InitializeResult.fromMap({
Keys.protocolVersion: protocolVersion.versionString,
Keys.capabilities: _validatedServerCapabilities(serverCapabilities),
Keys.serverInfo: serverInfo,
if (instructions != null) Keys.instructions: instructions,
});
/// The version of the Model Context Protocol that the server wants to use.
///
/// This may not match the version that the client requested. If the client
/// cannot support this version, it MUST disconnect.
///
/// May be `null` if the version is not recognized.
ProtocolVersion? get protocolVersion =>
ProtocolVersion.tryParse(_value[Keys.protocolVersion] as String);
/// Sets the protocol version, by default this is set for you, but you can
/// override it to a specific version if desired.
///
/// While this API is typed as nullable, `null` is not an allowed value.
set protocolVersion(ProtocolVersion? value) {
assert(value != null);
_value[Keys.protocolVersion] = value!.versionString;
}
ServerCapabilities get capabilities => ServerCapabilities.fromMap(
_value[Keys.capabilities] as Map<String, Object?>,
);
Implementation get serverInfo => _value[Keys.serverInfo] as Implementation;
/// Instructions describing how to use the server and its features.
///
/// This can be used by clients to improve the LLM's understanding of
/// available tools, resources, etc. It can be thought of like a "hint" to the
/// model. For example, this information MAY be added to the system prompt.
String? get instructions => _value[Keys.instructions] as String?;
}
/// This notification is sent from the client to the server after initialization
/// has finished.
extension type InitializedNotification.fromMap(Map<String, Object?> _value)
implements Notification {
static const methodName = 'notifications/initialized';
factory InitializedNotification({Meta? meta}) =>
InitializedNotification.fromMap({if (meta != null) Keys.meta: meta});
}
/// A [Meta] object carrying the envelope keys a request on the 2026-07-28
/// revision sends.
///
/// Has arbitrary other keys.
extension type MetaWithRequestEnvelope.fromMap(Map<String, Object?> _value)
implements MetaWithProgressToken {
factory MetaWithRequestEnvelope({
required ProtocolVersion protocolVersion,
required ClientCapabilities capabilities,
Implementation? clientInfo,
LoggingLevel? logLevel,
ProgressToken? progressToken,
}) => MetaWithRequestEnvelope.fromMap({
Keys.protocolVersionMeta: protocolVersion.versionString,
Keys.clientCapabilitiesMeta: _validatedClientCapabilities(capabilities),
if (clientInfo != null) Keys.clientInfoMeta: clientInfo,
if (logLevel != null) Keys.logLevelMeta: logLevel.name,
if (progressToken != null) Keys.progressToken: progressToken,
});
}
/// A request from the client asking the server to advertise its supported
/// protocol versions, capabilities, and other metadata.
///
/// Servers on protocol version 2026-07-28 MUST implement this method. Clients
/// MAY call it but are not required to: a client can also send any request
/// inline and handle the error if the server does not support the version it
/// asked for.
///
/// It has no parameters of its own beyond the `_meta` envelope that every
/// request on this revision sends.
extension type DiscoverRequest.fromMap(Map<String, Object?> _value)
implements Request {
static const methodName = 'server/discover';
factory DiscoverRequest({MetaWithProgressToken? meta}) =>
DiscoverRequest.fromMap({if (meta != null) Keys.meta: meta});
}
/// The server's response to a [DiscoverRequest] from the client.
extension type DiscoverResult.fromMap(Map<String, Object?> _value)
implements CacheableResult {
factory DiscoverResult({
required List<String> supportedVersions,
required ServerCapabilities capabilities,
String? instructions,
int? ttlMs,
CacheScope? cacheScope,
Meta? meta,
}) {
assert(ttlMs == null || ttlMs >= 0);
return DiscoverResult.fromMap({
Keys.supportedVersions: supportedVersions,
Keys.capabilities: _validatedServerCapabilities(capabilities),
if (instructions != null) Keys.instructions: instructions,
if (ttlMs != null) Keys.ttlMs: ttlMs,
if (cacheScope != null) Keys.cacheScope: cacheScope.name,
if (meta != null) Keys.meta: meta,
});
}
/// The protocol versions this server supports.
///
/// The client should choose one of these to use for its subsequent
/// requests.
///
/// These are the version strings as they appear on the wire rather than
/// [ProtocolVersion] values. That enum is a closed set, so a version this
/// package does not know would be dropped from the list the client is
/// choosing between.
List<String> get supportedVersions {
final supportedVersions = _value[Keys.supportedVersions] as List?;
if (supportedVersions == null) {
throw ArgumentError(
'Missing supportedVersions field in $DiscoverResult.',
);
}
return supportedVersions.cast<String>();
}
/// The capabilities of the server.
ServerCapabilities get capabilities {
final capabilities = _value[Keys.capabilities] as Map<String, Object?>?;
if (capabilities == null) {
throw ArgumentError('Missing capabilities field in $DiscoverResult.');
}
return ServerCapabilities.fromMap(capabilities);
}
/// Natural-language guidance describing the server and its features.
///
/// This can be used by clients to improve an LLM's understanding of
/// available tools, for instance by including it in a system prompt. It
/// should focus on information that helps the model use the server
/// effectively, and should not duplicate information already in tool
/// descriptions.
String? get instructions => _value[Keys.instructions] as String?;
}
/// Capabilities a client may support.
///
/// Known capabilities are defined here, in this schema, but this is not a
/// closed set: any client can define its own, additional capabilities.
extension type ClientCapabilities._fromMap(Map<String, Object?> _value) {
/// Wraps [value], which stays the map this reads and writes through.
factory ClientCapabilities.fromMap(Map<String, Object?> value) {
_validateCapabilityMap(value);
return ClientCapabilities._fromMap(value);
}
factory ClientCapabilities({
Map<String, Object?>? experimental,
RootsCapabilities? roots,
Map<String, Object?>? sampling,
ElicitationCapability? elicitation,
Map<String, Object?>? extensions,
}) => ClientCapabilities.fromMap({
if (experimental != null) Keys.experimental: experimental,
if (roots != null) Keys.roots: roots,
if (sampling != null) Keys.sampling: sampling,
if (elicitation != null) Keys.elicitation: elicitation,
if (extensions != null) Keys.extensions: extensions,
});
/// Experimental, non-standard capabilities that the client supports.
Map<String, Object?>? get experimental =>
_value[Keys.experimental] as Map<String, Object?>?;
/// Sets [experimental] asserting it is non-null first.
set experimental(Map<String, Object?>? value) {
assert(experimental == null);
_value[Keys.experimental] = value;
}
/// Present if the client supports any capabilities regarding roots.
RootsCapabilities? get roots => _value[Keys.roots] as RootsCapabilities?;
/// Sets [roots] asserting it is non-null first.
set roots(RootsCapabilities? value) {
assert(roots == null);
_value[Keys.roots] = value;
}
/// Present if the client supports sampling from an LLM.
Map<String, Object?>? get sampling =>
(_value[Keys.sampling] as Map?)?.cast<String, Object?>();
/// Sets [sampling] asserting it is non-null first.
set sampling(Map<String, Object?>? value) {
assert(sampling == null);
_value[Keys.sampling] = value;
}
/// Present if the client supports elicitation.
ElicitationCapability? get elicitation =>
_value[Keys.elicitation] as ElicitationCapability?;
/// Sets [elicitation], asserting it is null first.
set elicitation(ElicitationCapability? value) {
assert(elicitation == null);
_value[Keys.elicitation] = value;
}
/// Optional MCP extensions that the client supports.
///
/// Keys are extension identifiers in the `{vendor-prefix}/{extension-name}`
/// format, such as `io.modelcontextprotocol/oauth-client-credentials`, and
/// values are per-extension settings objects. An empty object indicates
/// support with no settings.
Map<String, Object?>? get extensions {
if (!_value.containsKey(Keys.extensions)) return null;
final extensions = _value[Keys.extensions];
_validateExtensions(extensions);
return (extensions as Map).cast<String, Object?>();
}
/// Sets [extensions], asserting it is null first.
set extensions(Map<String, Object?>? value) {
assert(extensions == null);
if (value == null) {
_value.remove(Keys.extensions);
} else {
_validateExtensions(value);
_value[Keys.extensions] = value;
}
}
}
/// Whether the client supports notifications for changes to the roots list.
extension type RootsCapabilities.fromMap(Map<String, Object?> _value) {
factory RootsCapabilities({bool? listChanged}) => RootsCapabilities.fromMap({
if (listChanged != null) Keys.listChanged: listChanged,
});
/// Present if the client supports listing roots.
bool? get listChanged => _value[Keys.listChanged] as bool?;
/// Sets whether [listChanged] is supported.
set listChanged(bool? value) {
assert(listChanged == null);
_value[Keys.listChanged] = value;
}
}
/// Whether the client supports elicitation.
extension type ElicitationCapability.fromMap(Map<String, Object?> _value) {
factory ElicitationCapability({
Map<String, Object?>? form,
Map<String, Object?>? url,
}) => ElicitationCapability.fromMap({
if (form != null) Keys.form: form,
if (url != null) Keys.url: url,
});
/// Whether form-based elicitation is supported.
Map<String, Object?>? get form => _value[Keys.form] as Map<String, Object?>?;
/// Sets whether [form] is supported.
set form(Map<String, Object?>? value) {
assert(form == null);
_value[Keys.form] = value;
}
/// Whether URL-based elicitation is supported.
Map<String, Object?>? get url => _value[Keys.url] as Map<String, Object?>?;
/// Sets whether [url] is supported.
set url(Map<String, Object?>? value) {
assert(url == null);
_value[Keys.url] = value;
}
}
/// Capabilities that a server may support.
///
/// Known capabilities are defined here, in this schema, but this is not a
/// closed set: any server can define its own, additional capabilities.
extension type ServerCapabilities._fromMap(Map<String, Object?> _value) {
/// Wraps [value], which stays the map this reads and writes through.
factory ServerCapabilities.fromMap(Map<String, Object?> value) {
_validateCapabilityMap(value);
return ServerCapabilities._fromMap(value);
}
factory ServerCapabilities({
Map<String, Object?>? experimental,
Completions? completions,
Logging? logging,
Prompts? prompts,
Resources? resources,
Tools? tools,
@Deprecated('Do not use, only clients have this capability')
Elicitation? elicitation,
Map<String, Object?>? extensions,
}) => ServerCapabilities.fromMap({
if (experimental != null) Keys.experimental: experimental,
if (completions != null) Keys.completions: completions,
if (logging != null) Keys.logging: logging,
if (prompts != null) Keys.prompts: prompts,
if (resources != null) Keys.resources: resources,
if (tools != null) Keys.tools: tools,
if (elicitation != null) Keys.elicitation: elicitation,
if (extensions != null) Keys.extensions: extensions,
});
/// Experimental, non-standard capabilities that the server supports.
Map<String, Object?>? get experimental =>
(_value[Keys.experimental] as Map?)?.cast<String, Object?>();
/// Sets [experimental] if it is null, otherwise throws.
set experimental(Map<String, Object?>? value) {
assert(experimental == null);
_value[Keys.experimental] = value;
}
/// Present if the server supports sending completion requests to the client.
Completions? get completions => _value[Keys.completions] as Completions?;
/// Sets [completions] if it is null, otherwise throws.
set completions(Completions? value) {
assert(completions == null);
_value[Keys.completions] = value;
}
/// Present if the server supports sending log messages to the client.
Logging? get logging =>
(_value[Keys.logging] as Map?)?.cast<String, Object?>() as Logging?;
/// Sets [logging] if it is null, otherwise throws.
set logging(Logging? value) {
assert(logging == null);
_value[Keys.logging] = value;
}
/// Present if the server offers any prompt templates.
Prompts? get prompts => _value[Keys.prompts] as Prompts?;
/// Sets [prompts] if it is null, otherwise throws.
set prompts(Prompts? value) {
assert(prompts == null);
_value[Keys.prompts] = value;
}
/// Whether this server supports subscribing to resource updates.
Resources? get resources => _value[Keys.resources] as Resources?;
/// Sets [resources] if it is null, otherwise throws.
set resources(Resources? value) {
assert(resources == null);
_value[Keys.resources] = value;
}
/// Present if the server offers any tools to call.
Tools? get tools => _value[Keys.tools] as Tools?;
/// Sets [tools] if it is null, otherwise throws.
set tools(Tools? value) {
assert(tools == null);
_value[Keys.tools] = value;
}
/// Present if the server supports elicitation.
@Deprecated('Do not use, only clients have this capability')
Elicitation? get elicitation => _value[Keys.elicitation] as Elicitation?;
/// Sets [elicitation] if it is null, otherwise asserts.
@Deprecated('Do not use, only clients have this capability')
set elicitation(Elicitation? value) {
assert(elicitation == null);
_value[Keys.elicitation] = value;
}
/// Optional MCP extensions that the server supports.
///
/// Keys are extension identifiers in the `{vendor-prefix}/{extension-name}`
/// format, such as `io.modelcontextprotocol/tasks`, and values are
/// per-extension settings objects. An empty object indicates support with
/// no settings.
Map<String, Object?>? get extensions {
if (!_value.containsKey(Keys.extensions)) return null;
final extensions = _value[Keys.extensions];
_validateExtensions(extensions);
return (extensions as Map).cast<String, Object?>();
}
/// Sets [extensions] if it is null, otherwise throws.
set extensions(Map<String, Object?>? value) {
assert(extensions == null);
if (value == null) {
_value.remove(Keys.extensions);
} else {
_validateExtensions(value);
_value[Keys.extensions] = value;
}
}
}
/// Completions parameter for [ServerCapabilities].
extension type Completions.fromMap(Map<String, Object?> _value) {
factory Completions() => Completions.fromMap({});
}
/// Prompts parameter for [ServerCapabilities].
extension type Prompts.fromMap(Map<String, Object?> _value) {
factory Prompts({bool? listChanged}) =>
Prompts.fromMap({if (listChanged != null) Keys.listChanged: listChanged});
/// Whether this server supports notifications for changes to the prompt list.
bool? get listChanged => _value[Keys.listChanged] as bool?;
/// Sets whether [listChanged] is supported.
set listChanged(bool? value) {
assert(listChanged == null);
_value[Keys.listChanged] = value;
}
}
/// Resources parameter for [ServerCapabilities].
extension type Resources.fromMap(Map<String, Object?> _value) {
factory Resources({bool? listChanged, bool? subscribe}) => Resources.fromMap({
if (listChanged != null) Keys.listChanged: listChanged,
if (subscribe != null) Keys.subscribe: subscribe,
});
/// Whether this server supports notifications for changes to the resource
/// list.
bool? get listChanged => _value[Keys.listChanged] as bool?;
/// Sets whether [listChanged] is supported.
set listChanged(bool? value) {
assert(listChanged == null);
_value[Keys.listChanged] = value;
}
/// Present if the server offers any resources to read.
bool? get subscribe => _value[Keys.subscribe] as bool?;
/// Sets whether [subscribe] is supported.
set subscribe(bool? value) {
assert(subscribe == null);
_value[Keys.subscribe] = value;
}
}
/// Tools parameter for [ServerCapabilities].
extension type Tools.fromMap(Map<String, Object?> _value) {
factory Tools({bool? listChanged}) =>
Tools.fromMap({if (listChanged != null) Keys.listChanged: listChanged});
/// Whether this server supports notifications for changes to the tool list.
bool? get listChanged => _value[Keys.listChanged] as bool?;
/// Sets whether [listChanged] is supported.
set listChanged(bool? value) {
assert(listChanged == null);
_value[Keys.listChanged] = value;
}
}
/// Elicitation parameter for [ServerCapabilities].
@Deprecated('Do not use, only clients have this capability')
extension type Elicitation.fromMap(Map<String, Object?> _value) {
factory Elicitation() => Elicitation.fromMap({});
}
/// Describes the name and version of an MCP implementation.
extension type Implementation.fromMap(Map<String, Object?> _value)
implements BaseMetadata {
factory Implementation({
required String name,
required String version,
String? title,
String? description,
List<Icon>? icons,
String? websiteUrl,
}) => Implementation.fromMap({
Keys.name: name,
Keys.version: version,
if (title != null) Keys.title: title,
if (description != null) Keys.description: description,
if (icons != null) Keys.icons: icons,
if (websiteUrl != null) Keys.websiteUrl: websiteUrl,
});
String get version {
final version = _value[Keys.version] as String?;
if (version == null) {
throw ArgumentError('Missing version field in $Implementation.');
}
return version;
}
/// A human-readable description of what this implementation does.
String? get description => _value[Keys.description] as String?;
/// Optional set of sized icons that the client can display in a user
/// interface.
List<Icon>? get icons => (_value[Keys.icons] as List?)?.cast<Icon>();
/// Optional URL to the website of the implementation.
String? get websiteUrl => _value[Keys.websiteUrl] as String?;
}
@Deprecated('Use Implementation instead.')
typedef ClientImplementation = Implementation;
@Deprecated('Use Implementation instead.')
typedef ServerImplementation = Implementation;