22// for details. All rights reserved. Use of this source code is governed by a
33// BSD-style license that can be found in the LICENSE file.
44
5- /// Interfaces are based on https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json
5+ /// Interfaces are based on
6+ /// https://github.com/modelcontextprotocol/specification/blob/main/schema/2025-06-18/schema.ts
67library ;
78
89import 'dart:collection' ;
@@ -11,6 +12,7 @@ import 'package:collection/collection.dart';
1112import 'package:json_rpc_2/json_rpc_2.dart' ;
1213
1314part 'completions.dart' ;
15+ part 'elicitation.dart' ;
1416part 'initialization.dart' ;
1517part 'logging.dart' ;
1618part 'prompts.dart' ;
@@ -22,7 +24,8 @@ part 'tools.dart';
2224/// Enum of the known protocol versions.
2325enum ProtocolVersion {
2426 v2024_11_05 ('2024-11-05' ),
25- v2025_03_26 ('2025-03-26' );
27+ v2025_03_26 ('2025-03-26' ),
28+ v2025_06_18 ('2025-06-18' );
2629
2730 const ProtocolVersion (this .versionString);
2831
@@ -35,7 +38,7 @@ enum ProtocolVersion {
3538 static const oldestSupported = ProtocolVersion .v2024_11_05;
3639
3740 /// The most recent version supported by the current API.
38- static const latestSupported = ProtocolVersion .v2025_03_26 ;
41+ static const latestSupported = ProtocolVersion .v2025_06_18 ;
3942
4043 /// The version string used over the wire to identify this version.
4144 final String versionString;
@@ -58,9 +61,65 @@ extension type ProgressToken( /*String|int*/ Object _) {}
5861/// An opaque token used to represent a cursor for pagination.
5962extension type Cursor (String _) {}
6063
61- /// Generic metadata passed with most requests, can be anything.
64+ /// Generic metadata passed with most requests.
65+ ///
66+ /// Metadata reserved by MCP to allow clients and servers to attach additional
67+ /// metadata to their interactions.
68+ ///
69+ /// Certain key names are reserved by MCP for protocol-level metadata, as
70+ /// specified below; implementations MUST NOT make assumptions about values at
71+ /// these keys.
72+ ///
73+ /// Additionally, definitions in the schema may reserve particular names for
74+ /// purpose-specific metadata, as declared in those definitions.
75+ ///
76+ /// Key name format: valid `_meta` key names have two segments: an optional
77+ /// prefix, and a name.
78+ ///
79+ /// - Prefix: If specified, MUST be a series of labels separated by dots
80+ /// (`.` ), followed by a slash (`/` ). Labels MUST start with a letter and
81+ /// end with a letter or digit; interior characters can be letters, digits,
82+ /// or hyphens (`-` ). Any prefix beginning with zero or more valid labels,
83+ /// followed by `modelcontextprotocol` or `mcp` , followed by any valid
84+ /// label, is reserved for MCP use. For example: `modelcontextprotocol.io/` ,
85+ /// `mcp.dev/` , `api.modelcontextprotocol.org/` , and `tools.mcp.com/` are
86+ /// all reserved.
87+ /// - Name: Unless empty, MUST begin and end with an alphanumeric character
88+ /// (`[a-z0-9A-Z]` ). MAY contain hyphens (`-` ), underscores (`_` ), dots
89+ /// (`.` ), and alphanumerics in between.
6290extension type Meta .fromMap (Map <String , Object ?> _value) {}
6391
92+ /// Basic metadata required by multiple types.
93+ ///
94+ /// Not to be confused with the `_meta` property in the spec, which has a
95+ /// different purpose.
96+ extension type BaseMetadata .fromMap (Map <String , Object ?> _value)
97+ implements Meta {
98+ factory BaseMetadata ({required String name, String ? title}) =>
99+ BaseMetadata .fromMap ({'name' : name, 'title' : title});
100+
101+ /// Intended for programmatic or logical use, but used as a display name in
102+ /// past specs for fallback (if title isn't present).
103+ String get name {
104+ final name = _value['name' ] as String ? ;
105+ if (name == null ) {
106+ throw ArgumentError ('Missing name field in $runtimeType ' );
107+ }
108+ return name;
109+ }
110+
111+ /// A short title for this object.
112+ ///
113+ /// Intended for UI and end-user contexts — optimized to be human-readable and
114+ /// easily understood, even by those unfamiliar with domain-specific
115+ /// terminology.
116+ ///
117+ /// If not provided, the name should be used for display (except for Tool,
118+ /// where `annotations.title` should be given precedence over using `name` , if
119+ /// present).
120+ String ? get title => _value['title' ] as String ? ;
121+ }
122+
64123/// A "mixin"-like extension type for any extension type that might contain a
65124/// [ProgressToken] at the key "progressToken".
66125///
@@ -78,10 +137,22 @@ extension type MetaWithProgressToken.fromMap(Map<String, Object?> _value)
78137 MetaWithProgressToken .fromMap ({'progressToken' : progressToken});
79138}
80139
140+ /// Base interface for all types that can have arbitrary metadata attached.
141+ ///
142+ /// Should not be constructed directly, and has no public constructor.
143+ extension type WithMetadata ._fromMap (Map <String , Object ?> _value) {
144+ /// The `_meta` property/parameter is reserved by MCP to allow clients and
145+ /// servers to attach additional metadata to their interactions.
146+ ///
147+ /// See [Meta] for more information about the format of these values.
148+ Meta ? get meta => _value['_meta' ] as Meta ? ;
149+ }
150+
81151/// Base interface for all request types.
82152///
83153/// Should not be constructed directly, and has no public constructor.
84- extension type Request ._fromMap (Map <String , Object ?> _value) {
154+ extension type Request ._fromMap (Map <String , Object ?> _value)
155+ implements WithMetadata {
85156 /// If specified, the caller is requesting out-of-band progress notifications
86157 /// for this request (as represented by notifications/progress).
87158 ///
@@ -273,15 +344,19 @@ extension type Content._(Map<String, Object?> _value) {
273344
274345/// Text provided to or from an LLM.
275346extension type TextContent .fromMap (Map <String , Object ?> _value)
276- implements Content , Annotated {
347+ implements Content , Annotated , WithMetadata {
277348 static const expectedType = 'text' ;
278349
279- factory TextContent ({required String text, Annotations ? annotations}) =>
280- TextContent .fromMap ({
281- 'text' : text,
282- 'type' : expectedType,
283- if (annotations != null ) 'annotations' : annotations,
284- });
350+ factory TextContent ({
351+ required String text,
352+ Annotations ? annotations,
353+ Meta ? meta,
354+ }) => TextContent .fromMap ({
355+ 'text' : text,
356+ 'type' : expectedType,
357+ if (annotations != null ) 'annotations' : annotations,
358+ if (meta != null ) '_meta' : meta,
359+ });
285360
286361 String get type {
287362 final type = _value['type' ] as String ;
@@ -295,18 +370,20 @@ extension type TextContent.fromMap(Map<String, Object?> _value)
295370
296371/// An image provided to or from an LLM.
297372extension type ImageContent .fromMap (Map <String , Object ?> _value)
298- implements Content , Annotated {
373+ implements Content , Annotated , WithMetadata {
299374 static const expectedType = 'image' ;
300375
301376 factory ImageContent ({
302377 required String data,
303378 required String mimeType,
304379 Annotations ? annotations,
380+ Meta ? meta,
305381 }) => ImageContent .fromMap ({
306382 'data' : data,
307383 'mimeType' : mimeType,
308384 'type' : expectedType,
309385 if (annotations != null ) 'annotations' : annotations,
386+ if (meta != null ) '_meta' : meta,
310387 });
311388
312389 String get type {
@@ -328,18 +405,20 @@ extension type ImageContent.fromMap(Map<String, Object?> _value)
328405///
329406/// Only supported since version [ProtocolVersion.v2025_03_26] .
330407extension type AudioContent .fromMap (Map <String , Object ?> _value)
331- implements Content , Annotated {
408+ implements Content , Annotated , WithMetadata {
332409 static const expectedType = 'audio' ;
333410
334411 factory AudioContent ({
335412 required String data,
336413 required String mimeType,
337414 Annotations ? annotations,
415+ Meta ? meta,
338416 }) => AudioContent .fromMap ({
339417 'data' : data,
340418 'mimeType' : mimeType,
341419 'type' : expectedType,
342420 if (annotations != null ) 'annotations' : annotations,
421+ if (meta != null ) '_meta' : meta,
343422 });
344423
345424 String get type {
@@ -362,16 +441,18 @@ extension type AudioContent.fromMap(Map<String, Object?> _value)
362441/// It is up to the client how best to render embedded resources for the benefit
363442/// of the LLM and/or the user.
364443extension type EmbeddedResource .fromMap (Map <String , Object ?> _value)
365- implements Content , Annotated {
444+ implements Content , Annotated , WithMetadata {
366445 static const expectedType = 'resource' ;
367446
368447 factory EmbeddedResource ({
369448 required Content resource,
370449 Annotations ? annotations,
450+ Meta ? meta,
371451 }) => EmbeddedResource .fromMap ({
372452 'resource' : resource,
373453 'type' : expectedType,
374454 if (annotations != null ) 'annotations' : annotations,
455+ if (meta != null ) '_meta' : meta,
375456 });
376457
377458 String get type {
@@ -386,6 +467,76 @@ extension type EmbeddedResource.fromMap(Map<String, Object?> _value)
386467 String ? get mimeType => _value['mimeType' ] as String ? ;
387468}
388469
470+ /// A resource link returned from a tool.
471+ ///
472+ /// Resource links returned by tools are not guaranteed to appear in the results
473+ /// of a `resources/list` request.
474+ extension type ResourceLink .fromMap (Map <String , Object ?> _value)
475+ implements Content , Annotated , WithMetadata , BaseMetadata {
476+ static const expectedType = 'resource_link' ;
477+
478+ factory ResourceLink ({
479+ required String name,
480+ String ? title,
481+ required String description,
482+ required String uri,
483+ required String mimeType,
484+ Annotations ? annotations,
485+ Meta ? meta,
486+ }) => ResourceLink .fromMap ({
487+ 'name' : name,
488+ if (title != null ) 'title' : title,
489+ 'description' : description,
490+ 'uri' : uri,
491+ 'mimeType' : mimeType,
492+ 'type' : expectedType,
493+ if (annotations != null ) 'annotations' : annotations,
494+ if (meta != null ) '_meta' : meta,
495+ });
496+
497+ String get type {
498+ final type = _value['type' ] as String ;
499+ assert (type == expectedType);
500+ return type;
501+ }
502+
503+ /// The name of the resource.
504+ String get name {
505+ final name = _value['name' ] as String ? ;
506+ if (name == null ) {
507+ throw ArgumentError ('Missing name field in $ResourceLink .' );
508+ }
509+ return name;
510+ }
511+
512+ /// The description of the resource.
513+ String get description {
514+ final description = _value['description' ] as String ? ;
515+ if (description == null ) {
516+ throw ArgumentError ('Missing description field in $ResourceLink .' );
517+ }
518+ return description;
519+ }
520+
521+ /// The URI of the resource.
522+ String get uri {
523+ final uri = _value['uri' ] as String ? ;
524+ if (uri == null ) {
525+ throw ArgumentError ('Missing uri field in $ResourceLink .' );
526+ }
527+ return uri;
528+ }
529+
530+ /// The MIME type of the resource.
531+ String get mimeType {
532+ final mimeType = _value['mimeType' ] as String ? ;
533+ if (mimeType == null ) {
534+ throw ArgumentError ('Missing mimeType field in $ResourceLink .' );
535+ }
536+ return mimeType;
537+ }
538+ }
539+
389540/// Base type for objects that include optional annotations for the client.
390541///
391542/// The client can use annotations to inform how objects are used or displayed.
@@ -396,10 +547,15 @@ extension type Annotated._fromMap(Map<String, Object?> _value) {
396547
397548/// The annotations for an [Annotated] object.
398549extension type Annotations .fromMap (Map <String , Object ?> _value) {
399- factory Annotations ({List <Role >? audience, double ? priority}) {
550+ factory Annotations ({
551+ List <Role >? audience,
552+ DateTime ? lastModified,
553+ double ? priority,
554+ }) {
400555 assert (priority == null || (priority >= 0 && priority <= 1 ));
401556 return Annotations .fromMap ({
402557 if (audience != null ) 'audience' : [for (var role in audience) role.name],
558+ if (lastModified != null ) 'lastModified' : lastModified.toIso8601String (),
403559 if (priority != null ) 'priority' : priority,
404560 });
405561 }
@@ -416,6 +572,18 @@ extension type Annotations.fromMap(Map<String, Object?> _value) {
416572 ];
417573 }
418574
575+ /// Describes when this data was last modified.
576+ ///
577+ /// The moment the resource was last modified.
578+ ///
579+ /// Examples: last activity timestamp in an open file, timestamp when the
580+ /// resource was attached, etc.
581+ DateTime ? get lastModified {
582+ final lastModified = _value['lastModified' ] as String ? ;
583+ if (lastModified == null ) return null ;
584+ return DateTime .parse (lastModified);
585+ }
586+
419587 /// Describes how important this data is for operating the server.
420588 ///
421589 /// A value of 1 means "most important," and indicates that the data is
0 commit comments