| // 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; |