diff --git a/mcp_examples/bin/file_system_server.dart b/mcp_examples/bin/file_system_server.dart index 0a1c3fa2..08ead76f 100644 --- a/mcp_examples/bin/file_system_server.dart +++ b/mcp_examples/bin/file_system_server.dart @@ -33,10 +33,7 @@ final class SimpleFileSystemServer extends MCPServer with LoggingSupport, RootsTrackingSupport, ToolsSupport { SimpleFileSystemServer.fromStreamChannel(super.channel) : super.fromStreamChannel( - implementation: ServerImplementation( - name: 'file system', - version: '0.0.1', - ), + implementation: Implementation(name: 'file system', version: '0.0.1'), ); @override diff --git a/mcp_examples/bin/workflow_client.dart b/mcp_examples/bin/workflow_client.dart index b3855a0f..08cf9730 100644 --- a/mcp_examples/bin/workflow_client.dart +++ b/mcp_examples/bin/workflow_client.dart @@ -107,9 +107,7 @@ final class WorkflowClient extends MCPClient with RootsSupport { stdinQueue = StreamQueue( stdin.transform(utf8.decoder).transform(const LineSplitter()), ), - super( - ClientImplementation(name: 'Gemini workflow client', version: '0.1.0'), - ) { + super(Implementation(name: 'Gemini workflow client', version: '0.1.0')) { logSink = _createLogSink(logFile); addRoot( Root( diff --git a/mcp_examples/pubspec.yaml b/mcp_examples/pubspec.yaml index bb97f221..a064d98d 100644 --- a/mcp_examples/pubspec.yaml +++ b/mcp_examples/pubspec.yaml @@ -14,3 +14,7 @@ dependencies: google_generative_ai: ^0.4.7 path: ^1.9.1 stream_channel: ^2.1.4 + +dependency_overrides: + dart_mcp: + path: ../pkgs/dart_mcp diff --git a/pkgs/dart_mcp/CHANGELOG.md b/pkgs/dart_mcp/CHANGELOG.md index 7ef10b2e..d76e0a41 100644 --- a/pkgs/dart_mcp/CHANGELOG.md +++ b/pkgs/dart_mcp/CHANGELOG.md @@ -1,5 +1,9 @@ -## 0.2.2-wip +## 0.2.2 +- Refactor `ClientImplementation` and `ServerImplementation` to the shared + `Implementation` type to match the spec. The old names are deprecated but will + still work until the next breaking release. +- Add `clientInfo` field to `MCPServer`, assigned during initialization. - Move the `done` future from the `ServerConnection` into `MCPBase` so it is available to the `MPCServer` class as well. diff --git a/pkgs/dart_mcp/README.md b/pkgs/dart_mcp/README.md index 687b6d50..ebe54f89 100644 --- a/pkgs/dart_mcp/README.md +++ b/pkgs/dart_mcp/README.md @@ -36,7 +36,7 @@ an error, which may result in a better UX for the users of the client. To implement a client, import `package:dart_mcp/client.dart` and extend the `MCPClient` class, or directly call its constructor with a -`ClientImplementation` if you aren't implementing any "capabilities". +`Implementation` if you aren't implementing any "capabilities". For each specific MCP capability your client supports, there is a corresponding mixin that you can use (`RootsSupport`, `SamplingSupport`, etc). Each mixin has diff --git a/pkgs/dart_mcp/example/simple_client.dart b/pkgs/dart_mcp/example/simple_client.dart index e99ba72e..2b2d51a2 100644 --- a/pkgs/dart_mcp/example/simple_client.dart +++ b/pkgs/dart_mcp/example/simple_client.dart @@ -6,7 +6,7 @@ import 'package:dart_mcp/client.dart'; void main() async { final client = MCPClient( - ClientImplementation(name: 'example dart client', version: '0.1.0'), + Implementation(name: 'example dart client', version: '0.1.0'), ); print('connecting to server'); final server = await client.connectStdioServer('dart', [ diff --git a/pkgs/dart_mcp/example/simple_server.dart b/pkgs/dart_mcp/example/simple_server.dart index d862f480..35522a95 100644 --- a/pkgs/dart_mcp/example/simple_server.dart +++ b/pkgs/dart_mcp/example/simple_server.dart @@ -29,7 +29,7 @@ void main() { base class DartMCPServer extends MCPServer with ToolsSupport { DartMCPServer(super.channel) : super.fromStreamChannel( - implementation: ServerImplementation( + implementation: Implementation( name: 'example dart server', version: '0.1.0', ), diff --git a/pkgs/dart_mcp/lib/src/api/initialization.dart b/pkgs/dart_mcp/lib/src/api/initialization.dart index bfc92f20..ec6acba9 100644 --- a/pkgs/dart_mcp/lib/src/api/initialization.dart +++ b/pkgs/dart_mcp/lib/src/api/initialization.dart @@ -13,7 +13,7 @@ extension type InitializeRequest._fromMap(Map _value) factory InitializeRequest({ required ProtocolVersion protocolVersion, required ClientCapabilities capabilities, - required ClientImplementation clientInfo, + required Implementation clientInfo, MetaWithProgressToken? meta, }) => InitializeRequest._fromMap({ 'protocolVersion': protocolVersion.versionString, @@ -33,8 +33,7 @@ extension type InitializeRequest._fromMap(Map _value) ClientCapabilities get capabilities => _value['capabilities'] as ClientCapabilities; - ClientImplementation get clientInfo => - _value['clientInfo'] as ClientImplementation; + Implementation get clientInfo => _value['clientInfo'] as Implementation; } /// After receiving an initialize request from the client, the server sends @@ -44,7 +43,7 @@ extension type InitializeResult.fromMap(Map _value) factory InitializeResult({ required ProtocolVersion protocolVersion, required ServerCapabilities serverCapabilities, - required ServerImplementation serverInfo, + required Implementation serverInfo, String? instructions, }) => InitializeResult.fromMap({ 'protocolVersion': protocolVersion.versionString, @@ -74,8 +73,7 @@ extension type InitializeResult.fromMap(Map _value) ServerCapabilities get capabilities => _value['capabilities'] as ServerCapabilities; - ServerImplementation get serverInfo => - _value['serverInfo'] as ServerImplementation; + Implementation get serverInfo => _value['serverInfo'] as Implementation; /// Instructions describing how to use the server and its features. /// @@ -295,24 +293,17 @@ extension type Tools.fromMap(Map _value) { } } -/// Describes the name and version of an MCP client implementation. -extension type ClientImplementation.fromMap(Map _value) { - factory ClientImplementation({ - required String name, - required String version, - }) => ClientImplementation.fromMap({'name': name, 'version': version}); +/// Describes the name and version of an MCP implementation. +extension type Implementation.fromMap(Map _value) { + factory Implementation({required String name, required String version}) => + Implementation.fromMap({'name': name, 'version': version}); String get name => _value['name'] as String; String get version => _value['version'] as String; } -/// Describes the name and version of an MCP server implementation. -extension type ServerImplementation.fromMap(Map _value) { - factory ServerImplementation({ - required String name, - required String version, - }) => ServerImplementation.fromMap({'name': name, 'version': version}); +@Deprecated('Use Implementation instead.') +typedef ClientImplementation = Implementation; - String get name => _value['name'] as String; - String get version => _value['version'] as String; -} +@Deprecated('Use Implementation instead.') +typedef ServerImplementation = Implementation; diff --git a/pkgs/dart_mcp/lib/src/client/client.dart b/pkgs/dart_mcp/lib/src/client/client.dart index 34c22fc2..cde9930d 100644 --- a/pkgs/dart_mcp/lib/src/client/client.dart +++ b/pkgs/dart_mcp/lib/src/client/client.dart @@ -29,7 +29,7 @@ part 'sampling_support.dart'; /// this will be invoked at the end of base class constructor. base class MCPClient { /// A description of the client sent to servers during initialization. - final ClientImplementation implementation; + final Implementation implementation; MCPClient(this.implementation) { initialize(); @@ -128,10 +128,10 @@ base class ServerConnection extends MCPBase { /// protocol version. late ProtocolVersion protocolVersion; - /// The [ServerImplementation] returned from the [initialize] request. + /// The [Implementation] returned from the [initialize] request. /// /// Only non-null after [initialize] has successfully completed. - ServerImplementation? serverInfo; + Implementation? serverInfo; /// The [ServerCapabilities] returned from the [initialize] request. /// diff --git a/pkgs/dart_mcp/lib/src/client/sampling_support.dart b/pkgs/dart_mcp/lib/src/client/sampling_support.dart index 803ffbfe..98cdf16d 100644 --- a/pkgs/dart_mcp/lib/src/client/sampling_support.dart +++ b/pkgs/dart_mcp/lib/src/client/sampling_support.dart @@ -26,6 +26,6 @@ base mixin SamplingSupport on MCPClient { /// request gave when it was initialized. FutureOr handleCreateMessage( CreateMessageRequest request, - ServerImplementation serverInfo, + Implementation serverInfo, ); } diff --git a/pkgs/dart_mcp/lib/src/server/server.dart b/pkgs/dart_mcp/lib/src/server/server.dart index 452e9a37..a0ab0e0a 100644 --- a/pkgs/dart_mcp/lib/src/server/server.dart +++ b/pkgs/dart_mcp/lib/src/server/server.dart @@ -32,7 +32,7 @@ abstract base class MCPServer extends MCPBase { bool get ready => isActive && _initialized.isCompleted; /// The name, current version, and other info to give to the client. - final ServerImplementation implementation; + final Implementation implementation; /// Instructions for how to use this server, which are given to the client. /// @@ -49,6 +49,11 @@ abstract base class MCPServer extends MCPBase { /// Only assigned after `initialize` has been called. late ClientCapabilities clientCapabilities; + /// The client implementation information provided during initialization. + /// + /// Only assigned after `initialize` has been called. + late Implementation clientInfo; + @override String get name => implementation.name; @@ -106,6 +111,9 @@ abstract base class MCPServer extends MCPBase { _rootsListChangedController!.sink.add, ); } + + clientInfo = request.clientInfo; + assert(!_initialized.isCompleted); return InitializeResult( protocolVersion: protocolVersion, diff --git a/pkgs/dart_mcp/pubspec.yaml b/pkgs/dart_mcp/pubspec.yaml index b5c1371e..0a09b1c8 100644 --- a/pkgs/dart_mcp/pubspec.yaml +++ b/pkgs/dart_mcp/pubspec.yaml @@ -1,5 +1,5 @@ name: dart_mcp -version: 0.2.2-wip +version: 0.2.2 description: A package for making MCP servers and clients. repository: https://github.com/dart-lang/ai/tree/main/pkgs/dart_mcp issue_tracker: https://github.com/dart-lang/ai/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Adart_mcp diff --git a/pkgs/dart_mcp/test/api/sampling_test.dart b/pkgs/dart_mcp/test/api/sampling_test.dart index 2ebe616c..af1d486d 100644 --- a/pkgs/dart_mcp/test/api/sampling_test.dart +++ b/pkgs/dart_mcp/test/api/sampling_test.dart @@ -45,7 +45,7 @@ final class SamplingTestMCPClient extends TestMCPClient with SamplingSupport { @override FutureOr handleCreateMessage( CreateMessageRequest request, - ServerImplementation serverInfo, + Implementation serverInfo, ) { if (nextResult case final result?) { nextResult = null; diff --git a/pkgs/dart_mcp/test/client_and_server_test.dart b/pkgs/dart_mcp/test/client_and_server_test.dart index 428746ae..3aa3faa5 100644 --- a/pkgs/dart_mcp/test/client_and_server_test.dart +++ b/pkgs/dart_mcp/test/client_and_server_test.dart @@ -23,6 +23,12 @@ void main() { expect(initializeResult.instructions, environment.server.instructions); expect(initializeResult.protocolVersion, ProtocolVersion.latestSupported); + expect(environment.server.clientInfo, environment.client.implementation); + expect( + environment.serverConnection.serverInfo, + environment.server.implementation, + ); + expect( environment.serverConnection.listTools(ListToolsRequest()), throwsA( @@ -337,7 +343,7 @@ void main() { InitializeRequest( protocolVersion: ProtocolVersion.latestSupported, capabilities: ClientCapabilities(), - clientInfo: ClientImplementation(name: '', version: ''), + clientInfo: Implementation(name: '', version: ''), ), ), throwsA( diff --git a/pkgs/dart_mcp/test/test_utils.dart b/pkgs/dart_mcp/test/test_utils.dart index 261ce297..9294eb60 100644 --- a/pkgs/dart_mcp/test/test_utils.dart +++ b/pkgs/dart_mcp/test/test_utils.dart @@ -78,16 +78,13 @@ class TestEnvironment { base class TestMCPClient extends MCPClient { TestMCPClient() - : super(ClientImplementation(name: 'test client', version: '0.1.0')); + : super(Implementation(name: 'test client', version: '0.1.0')); } base class TestMCPServer extends MCPServer { TestMCPServer(super.channel, {super.protocolLogSink}) : super.fromStreamChannel( - implementation: ServerImplementation( - name: 'test server', - version: '0.1.0', - ), + implementation: Implementation(name: 'test server', version: '0.1.0'), instructions: 'A test server', ); } diff --git a/pkgs/dart_mcp_server/lib/src/server.dart b/pkgs/dart_mcp_server/lib/src/server.dart index b937dce9..6b8a68ef 100644 --- a/pkgs/dart_mcp_server/lib/src/server.dart +++ b/pkgs/dart_mcp_server/lib/src/server.dart @@ -40,7 +40,7 @@ final class DartMCPServer extends MCPServer this.forceRootsFallback = false, super.protocolLogSink, }) : super.fromStreamChannel( - implementation: ServerImplementation( + implementation: Implementation( name: 'dart and flutter tooling', version: '0.1.0-wip', ), diff --git a/pkgs/dart_mcp_server/pubspec.yaml b/pkgs/dart_mcp_server/pubspec.yaml index b560d110..4c9b9999 100644 --- a/pkgs/dart_mcp_server/pubspec.yaml +++ b/pkgs/dart_mcp_server/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: args: ^2.7.0 async: ^2.13.0 collection: ^1.19.1 - dart_mcp: ^0.2.1 + dart_mcp: ^0.2.2 dds_service_extensions: ^2.0.1 devtools_shared: ^11.2.0 dtd: ^2.4.0 diff --git a/pkgs/dart_mcp_server/test/test_harness.dart b/pkgs/dart_mcp_server/test/test_harness.dart index 2b30dc02..c11d887c 100644 --- a/pkgs/dart_mcp_server/test/test_harness.dart +++ b/pkgs/dart_mcp_server/test/test_harness.dart @@ -282,7 +282,7 @@ final class AppDebugSession { final class DartToolingMCPClient extends MCPClient with RootsSupport { DartToolingMCPClient() : super( - ClientImplementation( + Implementation( name: 'test client for the dart tooling mcp server', version: '0.1.0', ), diff --git a/pkgs/dart_mcp_server/test/tools/roots_fallback_support_test.dart b/pkgs/dart_mcp_server/test/tools/roots_fallback_support_test.dart index a97dacf0..a93865ab 100644 --- a/pkgs/dart_mcp_server/test/tools/roots_fallback_support_test.dart +++ b/pkgs/dart_mcp_server/test/tools/roots_fallback_support_test.dart @@ -190,7 +190,7 @@ void main() { final class TestClientWithoutRoots extends MCPClient { TestClientWithoutRoots() : super( - ClientImplementation( + Implementation( name: 'test client with no roots support', version: '0.1.0', ), @@ -201,7 +201,7 @@ final class TestClientWithoutRoots extends MCPClient { final class TestClientWithRoots extends MCPClient with RootsSupport { TestClientWithRoots() : super( - ClientImplementation( + Implementation( name: 'test client with roots support', version: '0.1.0', ), @@ -223,10 +223,7 @@ final class TestServer extends MCPServer super.protocolLogSink, this.forceRootsFallback = false, }) : super.fromStreamChannel( - implementation: ServerImplementation( - name: 'test server', - version: '0.1.0', - ), + implementation: Implementation(name: 'test server', version: '0.1.0'), instructions: 'A test server with roots fallback support', ); }