Skip to content

Use shared Implementation type, add clientInfo field to MCPServer #175

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions mcp_examples/bin/file_system_server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions mcp_examples/bin/workflow_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
4 changes: 4 additions & 0 deletions mcp_examples/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 5 additions & 1 deletion pkgs/dart_mcp/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
2 changes: 1 addition & 1 deletion pkgs/dart_mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion pkgs/dart_mcp/example/simple_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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', [
Expand Down
2 changes: 1 addition & 1 deletion pkgs/dart_mcp/example/simple_server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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',
),
Expand Down
33 changes: 12 additions & 21 deletions pkgs/dart_mcp/lib/src/api/initialization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ extension type InitializeRequest._fromMap(Map<String, Object?> _value)
factory InitializeRequest({
required ProtocolVersion protocolVersion,
required ClientCapabilities capabilities,
required ClientImplementation clientInfo,
required Implementation clientInfo,
MetaWithProgressToken? meta,
}) => InitializeRequest._fromMap({
'protocolVersion': protocolVersion.versionString,
Expand All @@ -33,8 +33,7 @@ extension type InitializeRequest._fromMap(Map<String, Object?> _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
Expand All @@ -44,7 +43,7 @@ extension type InitializeResult.fromMap(Map<String, Object?> _value)
factory InitializeResult({
required ProtocolVersion protocolVersion,
required ServerCapabilities serverCapabilities,
required ServerImplementation serverInfo,
required Implementation serverInfo,
String? instructions,
}) => InitializeResult.fromMap({
'protocolVersion': protocolVersion.versionString,
Expand Down Expand Up @@ -74,8 +73,7 @@ extension type InitializeResult.fromMap(Map<String, Object?> _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.
///
Expand Down Expand Up @@ -295,24 +293,17 @@ extension type Tools.fromMap(Map<String, Object?> _value) {
}
}

/// Describes the name and version of an MCP client implementation.
extension type ClientImplementation.fromMap(Map<String, Object?> _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<String, Object?> _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<String, Object?> _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;
6 changes: 3 additions & 3 deletions pkgs/dart_mcp/lib/src/client/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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.
///
Expand Down
2 changes: 1 addition & 1 deletion pkgs/dart_mcp/lib/src/client/sampling_support.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ base mixin SamplingSupport on MCPClient {
/// request gave when it was initialized.
FutureOr<CreateMessageResult> handleCreateMessage(
CreateMessageRequest request,
ServerImplementation serverInfo,
Implementation serverInfo,
);
}
10 changes: 9 additions & 1 deletion pkgs/dart_mcp/lib/src/server/server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand All @@ -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;

Expand Down Expand Up @@ -106,6 +111,9 @@ abstract base class MCPServer extends MCPBase {
_rootsListChangedController!.sink.add,
);
}

clientInfo = request.clientInfo;

assert(!_initialized.isCompleted);
return InitializeResult(
protocolVersion: protocolVersion,
Expand Down
2 changes: 1 addition & 1 deletion pkgs/dart_mcp/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion pkgs/dart_mcp/test/api/sampling_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ final class SamplingTestMCPClient extends TestMCPClient with SamplingSupport {
@override
FutureOr<CreateMessageResult> handleCreateMessage(
CreateMessageRequest request,
ServerImplementation serverInfo,
Implementation serverInfo,
) {
if (nextResult case final result?) {
nextResult = null;
Expand Down
8 changes: 7 additions & 1 deletion pkgs/dart_mcp/test/client_and_server_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -337,7 +343,7 @@ void main() {
InitializeRequest(
protocolVersion: ProtocolVersion.latestSupported,
capabilities: ClientCapabilities(),
clientInfo: ClientImplementation(name: '', version: ''),
clientInfo: Implementation(name: '', version: ''),
),
),
throwsA(
Expand Down
7 changes: 2 additions & 5 deletions pkgs/dart_mcp/test/test_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,13 @@ class TestEnvironment<Client extends MCPClient, Server extends MCPServer> {

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',
);
}
Expand Down
2 changes: 1 addition & 1 deletion pkgs/dart_mcp_server/lib/src/server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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',
),
Expand Down
2 changes: 1 addition & 1 deletion pkgs/dart_mcp_server/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion pkgs/dart_mcp_server/test/test_harness.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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',
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
),
Expand All @@ -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',
),
Expand All @@ -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',
);
}
Loading