Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pubspec.lock
.vscode
.idea
*.iml
.agents

# Gemini specific ignores
**/.gemini/*
Expand Down
1 change: 1 addition & 0 deletions pkgs/dart_mcp/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ dependencies:
stream_transform: ^2.1.1

dev_dependencies:
checks: ^0.3.1
dart_flutter_team_lints: ^3.2.1
test: ^1.25.15
115 changes: 48 additions & 67 deletions pkgs/dart_mcp/test/api/api_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,126 +2,107 @@
// 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.

import 'package:checks/checks.dart';
import 'package:dart_mcp/client.dart';
import 'package:test/test.dart';

void main() {
test('protocol versions can be compared', () {
expect(
check(
ProtocolVersion.latestSupported > ProtocolVersion.oldestSupported,
true,
);
expect(
).isTrue();
check(
ProtocolVersion.latestSupported >= ProtocolVersion.oldestSupported,
true,
);
expect(
).isTrue();
check(
ProtocolVersion.latestSupported < ProtocolVersion.oldestSupported,
false,
);
expect(
).isFalse();
check(
ProtocolVersion.latestSupported <= ProtocolVersion.oldestSupported,
false,
);
).isFalse();

expect(
check(
ProtocolVersion.oldestSupported > ProtocolVersion.latestSupported,
false,
);
expect(
).isFalse();
check(
ProtocolVersion.oldestSupported >= ProtocolVersion.latestSupported,
false,
);
expect(
).isFalse();
check(
ProtocolVersion.oldestSupported < ProtocolVersion.latestSupported,
true,
);
expect(
).isTrue();
check(
ProtocolVersion.oldestSupported <= ProtocolVersion.latestSupported,
true,
);
).isTrue();

expect(
check(
ProtocolVersion.latestSupported <= ProtocolVersion.latestSupported,
true,
);
expect(
).isTrue();
check(
ProtocolVersion.latestSupported >= ProtocolVersion.latestSupported,
true,
);
expect(
).isTrue();
check(
ProtocolVersion.latestSupported < ProtocolVersion.latestSupported,
false,
);
expect(
).isFalse();
check(
ProtocolVersion.latestSupported > ProtocolVersion.latestSupported,
false,
);
).isFalse();
});

group('API object validation', () {
test('throws when required fields are missing', () {
expect(() => Root.fromMap({}).uri, throwsA(isA<ArgumentError>()));
expect(
check(() => Root.fromMap({}).uri).throws<ArgumentError>();
check(
() => Implementation.fromMap({'name': 'test'}).version,
throwsA(isA<ArgumentError>()),
);
expect(
() => BaseMetadata.fromMap({}).name,
throwsA(isA<ArgumentError>()),
);
).throws<ArgumentError>();
check(() => BaseMetadata.fromMap({}).name).throws<ArgumentError>();

final empty = <String, Object?>{};

// Initialization
expect(
check(
() => (empty as InitializeRequest).capabilities,
throwsArgumentError,
);
expect(
).throws<ArgumentError>();
check(
() => (empty as InitializeRequest).clientInfo,
throwsArgumentError,
);
).throws<ArgumentError>();

// Tools
expect(() => (empty as CallToolRequest).name, throwsArgumentError);
check(() => (empty as CallToolRequest).name).throws<ArgumentError>();

// Resources
expect(() => (empty as ReadResourceRequest).uri, throwsArgumentError);
expect(() => (empty as SubscribeRequest).uri, throwsArgumentError);
expect(() => (empty as UnsubscribeRequest).uri, throwsArgumentError);
check(() => (empty as ReadResourceRequest).uri).throws<ArgumentError>();
check(() => (empty as SubscribeRequest).uri).throws<ArgumentError>();
check(() => (empty as UnsubscribeRequest).uri).throws<ArgumentError>();

// Roots
expect(() => (empty as ListRootsResult).roots, throwsArgumentError);
check(() => (empty as ListRootsResult).roots).throws<ArgumentError>();

// Prompts
expect(() => (empty as GetPromptRequest).name, throwsArgumentError);
check(() => (empty as GetPromptRequest).name).throws<ArgumentError>();

// Completions
expect(() => (empty as CompleteRequest).ref, throwsArgumentError);
expect(() => (empty as CompleteRequest).argument, throwsArgumentError);
check(() => (empty as CompleteRequest).ref).throws<ArgumentError>();
check(() => (empty as CompleteRequest).argument).throws<ArgumentError>();

// Logging
expect(() => (empty as SetLevelRequest).level, throwsArgumentError);
check(() => (empty as SetLevelRequest).level).throws<ArgumentError>();

// Sampling
expect(
check(
() => (empty as CreateMessageRequest).messages,
throwsArgumentError,
);
expect(
).throws<ArgumentError>();
check(
() => (empty as CreateMessageRequest).maxTokens,
throwsArgumentError,
);
).throws<ArgumentError>();
});
test('meta field is parsed correctly', () {
final root = Root.fromMap({
'uri': 'file:///foo/bar',
'_meta': {'foo': 'bar'},
});
expect(root.meta, isNotNull);
check(root.meta).isNotNull();
final metaMap = root.meta as Map;
expect(metaMap['foo'], 'bar');
check(metaMap['foo']).equals('bar');
});
});
}
92 changes: 49 additions & 43 deletions pkgs/dart_mcp/test/api/completions_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart:async';

import 'package:checks/checks.dart';
import 'package:dart_mcp/server.dart';
import 'package:test/test.dart';

Expand All @@ -16,26 +17,28 @@ void main() {
TestMCPServerWithCompletions.new,
);
final initializeResult = await environment.initializeServer();
expect(initializeResult.capabilities.completions, Completions());
check(
initializeResult.capabilities.completions as Map<String, Object?>?,
).isNotNull().deepEquals(Completions() as Map<String, Object?>);

final serverConnection = environment.serverConnection;
expect(
(await serverConnection.requestCompletions(
CompleteRequest(
ref: TestMCPServerWithCompletions.languagePromptRef,
argument: CompletionArgument(
name:
TestMCPServerWithCompletions
.languagePrompt
.arguments!
.single
.name,
value: 'c',
),
final result = await serverConnection.requestCompletions(
CompleteRequest(
ref: TestMCPServerWithCompletions.languagePromptRef,
argument: CompletionArgument(
name:
TestMCPServerWithCompletions
.languagePrompt
.arguments!
.single
.name,
value: 'c',
),
)).completion.values,
TestMCPServerWithCompletions.cLanguages,
),
);
check(
result.completion.values,
).deepEquals(TestMCPServerWithCompletions.cLanguages);
});

test('client can request resource completions', () async {
Expand All @@ -44,27 +47,30 @@ void main() {
TestMCPServerWithCompletions.new,
);
final initializeResult = await environment.initializeServer();
expect(initializeResult.capabilities.completions, Completions());
check(
initializeResult.capabilities.completions as Map<String, Object?>?,
).isNotNull().deepEquals(Completions() as Map<String, Object?>);

final serverConnection = environment.serverConnection;
expect(
(await serverConnection.requestCompletions(
CompleteRequest(
ref: TestMCPServerWithCompletions.packageUriTemplateRef,
argument: CompletionArgument(name: 'package_name', value: 'a'),
),
)).completion.values,
TestMCPServerWithCompletions.aPackages,
final result1 = await serverConnection.requestCompletions(
CompleteRequest(
ref: TestMCPServerWithCompletions.packageUriTemplateRef,
argument: CompletionArgument(name: 'package_name', value: 'a'),
),
);
expect(
(await serverConnection.requestCompletions(
CompleteRequest(
ref: TestMCPServerWithCompletions.packageUriTemplateRef,
argument: CompletionArgument(name: 'path', value: 'a'),
),
)).completion.values,
TestMCPServerWithCompletions.packagePaths,
check(
result1.completion.values,
).deepEquals(TestMCPServerWithCompletions.aPackages);

final result2 = await serverConnection.requestCompletions(
CompleteRequest(
ref: TestMCPServerWithCompletions.packageUriTemplateRef,
argument: CompletionArgument(name: 'path', value: 'a'),
),
);
check(
result2.completion.values,
).deepEquals(TestMCPServerWithCompletions.packagePaths);
});

test('client can request resource completions with context', () async {
Expand All @@ -73,19 +79,19 @@ void main() {
TestMCPServerWithCompletions.new,
);
final initializeResult = await environment.initializeServer();
expect(initializeResult.capabilities.completions, Completions());
check(
initializeResult.capabilities.completions as Map<String, Object?>?,
).isNotNull().deepEquals(Completions() as Map<String, Object?>);

final serverConnection = environment.serverConnection;
expect(
(await serverConnection.requestCompletions(
CompleteRequest(
ref: TestMCPServerWithCompletions.packageUriTemplateRef,
argument: CompletionArgument(name: 'path', value: 'a'),
context: CompletionContext(arguments: {'package_name': 'async'}),
),
)).completion.values,
['async.dart'],
final result = await serverConnection.requestCompletions(
CompleteRequest(
ref: TestMCPServerWithCompletions.packageUriTemplateRef,
argument: CompletionArgument(name: 'path', value: 'a'),
context: CompletionContext(arguments: {'package_name': 'async'}),
),
);
check(result.completion.values).deepEquals(['async.dart']);
});
}

Expand Down
5 changes: 3 additions & 2 deletions pkgs/dart_mcp/test/api/elicitation_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart:async';

import 'package:checks/checks.dart';
import 'package:dart_mcp/client.dart';
import 'package:dart_mcp/server.dart';
import 'package:test/test.dart';
Expand Down Expand Up @@ -50,8 +51,8 @@ void main() {
);

final result = await elicitationRequest;
expect(result.action, ElicitationAction.accept);
expect(result.content, {'name': 'John Doe'});
check(result.action).equals(ElicitationAction.accept);
check(result.content).isNotNull().deepEquals({'name': 'John Doe'});
});
});
}
Expand Down
5 changes: 3 additions & 2 deletions pkgs/dart_mcp/test/api/initialization_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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.

import 'package:checks/checks.dart';
import 'package:dart_mcp/server.dart';
import 'package:test/test.dart';

Expand All @@ -14,7 +15,7 @@ void main() {
);

final map = result as Map<String, Object?>;
expect(map.containsKey('instructions'), isFalse);
check(map).not((m) => m.containsKey('instructions'));
});

test('nonnull instructions', () async {
Expand All @@ -26,6 +27,6 @@ void main() {
);

final map = result as Map<String, Object?>;
expect(map['instructions'], equals('foo'));
check(map)['instructions'].equals('foo');
Comment thread
jakemac53 marked this conversation as resolved.
});
}
Loading
Loading