From f39cd8942657a2d368a9c879d5c1498937baea80 Mon Sep 17 00:00:00 2001 From: Jhin Lee Date: Tue, 23 Dec 2025 10:28:14 -0500 Subject: [PATCH 1/3] refactor: rename Client to McpClient and standardize request parameter types BREAKING CHANGES: - Renamed core classes: - Client -> McpClient (avoids conflicts with http library) - ClientOptions -> McpClientOptions - ServerOptions -> McpServerOptions - Renamed request/notification parameter types: - ReadResourceRequestParams -> ReadResourceRequest - GetPromptRequestParams -> GetPromptRequest - ElicitRequestParams -> ElicitRequest - CreateMessageRequestParams -> CreateMessageRequest - LoggingMessageNotificationParams -> LoggingMessageNotification All breaking changes are auto-fixable via `dart fix --apply`. Added fix_data.yaml for automatic migration support. --- CHANGELOG.md | 18 + example/anthropic-client/bin/main.dart | 2 +- .../lib/anthropic_client.dart | 2 +- .../authentication/github_oauth_example.dart | 2 +- .../authentication/github_pat_example.dart | 2 +- .../authentication/oauth_client_example.dart | 2 +- example/client_stdio.dart | 6 +- example/completions_capability_demo.dart | 2 +- example/elicitation_http_server.dart | 30 +- .../lib/services/streamable_mcp_service.dart | 6 +- example/gemini-client/bin/main.dart | 2 +- example/gemini-client/lib/gemini_client.dart | 2 +- .../server_iostream.dart | 2 +- example/iostream-client-server/simple.dart | 4 +- .../with_pipe_helper.dart | 4 +- example/server_sse.dart | 2 +- example/server_stdio.dart | 2 +- example/simple_task_interactive_client.dart | 8 +- example/simple_task_interactive_server.dart | 2 +- .../client_streamable_https.dart | 6 +- .../streamable_https/high_level_server.dart | 8 +- .../server_streamable_https.dart | 8 +- lib/fix_data.yaml | 347 ++++++++++++++++++ lib/src/client/client.dart | 50 +-- lib/src/client/task_client.dart | 8 +- lib/src/server/mcp_server.dart | 10 +- lib/src/server/server.dart | 27 +- lib/src/server/tasks/handler.dart | 4 +- lib/src/server/tasks/session.dart | 6 +- lib/src/shared/protocol.dart | 10 +- lib/src/types/completion.dart | 16 +- lib/src/types/elicitation.dart | 49 ++- lib/src/types/initialization.dart | 16 +- lib/src/types/json_rpc.dart | 2 +- lib/src/types/logging.dart | 32 +- lib/src/types/prompts.dart | 38 +- lib/src/types/resources.dart | 107 +++--- lib/src/types/sampling.dart | 16 +- lib/src/types/tasks.dart | 85 +++-- .../mcp_dart_cli/lib/src/doctor_command.dart | 4 +- .../mcp_dart_cli/lib/src/inspect_command.dart | 15 +- .../lib/src/utils/inspect_handlers.dart | 4 +- .../lib/src/utils/mcp_connection.dart | 12 +- pubspec.yaml | 2 +- test/client/client_test.dart | 20 +- ...t_client_with_ts_server_features_test.dart | 8 +- .../dart_client_with_ts_server_task_test.dart | 6 +- .../dart_client_with_ts_server_test.dart | 16 +- test/interop/test_dart_server.dart | 4 +- test/server/server_test.dart | 32 +- 50 files changed, 765 insertions(+), 303 deletions(-) create mode 100644 lib/fix_data.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index c2ffeec..ed00d2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## 1.2.0 + +### Breaking Changes + +> [!TIP] +> All breaking changes below are auto-fixable. Run `dart fix --apply` to automatically update your code. + +- **Renamed Core Classes**: + - `Client` is now `McpClient` to avoid conflicts with other libraries (like `http`). + - `ClientOptions` is now `McpClientOptions`. + - `ServerOptions` is now `McpServerOptions`. +- **Renamed Request/Notification Parameters**: + - `ReadResourceRequestParams` -> `ReadResourceRequest` + - `GetPromptRequestParams` -> `GetPromptRequest` + - `ElicitRequestParams` -> `ElicitRequest` + - `CreateMessageRequestParams` -> `CreateMessageRequest` + - `LoggingMessageNotificationParams` -> `LoggingMessageNotification` (typedef deprecated) + ## 1.1.2 - **Fixed StdioClientTransport stderr handling**: Corrected process mode to always use `ProcessStartMode.normal` to ensure stdin/stdout piping works correctly. Fixed inverted stderr mode logic where `stderrMode: normal` now properly exposes stderr via getter (without internal listening), and `stderrMode: inheritStdio` now manually pipes stderr to parent process. diff --git a/example/anthropic-client/bin/main.dart b/example/anthropic-client/bin/main.dart index 392c37e..ceb62e2 100644 --- a/example/anthropic-client/bin/main.dart +++ b/example/anthropic-client/bin/main.dart @@ -21,7 +21,7 @@ Future main(List args) async { final client = AnthropicMcpClient( AnthropicClient(apiKey: apiKey), - Client(Implementation(name: "mcp-client-cli", version: "1.0.0")), + McpClient(Implementation(name: "mcp-client-cli", version: "1.0.0")), ); try { await client.connectToServer(args[0], args.sublist(1)); diff --git a/example/anthropic-client/lib/anthropic_client.dart b/example/anthropic-client/lib/anthropic_client.dart index f9291b3..5e4f723 100644 --- a/example/anthropic-client/lib/anthropic_client.dart +++ b/example/anthropic-client/lib/anthropic_client.dart @@ -6,7 +6,7 @@ import 'package:mcp_dart/mcp_dart.dart' as mcp_dart; /// A client for interacting with an MCP server and Anthropic's API. class AnthropicMcpClient { - final mcp_dart.Client mcp; + final mcp_dart.McpClient mcp; final AnthropicClient anthropic; mcp_dart.StdioClientTransport? transport; List tools = []; diff --git a/example/authentication/github_oauth_example.dart b/example/authentication/github_oauth_example.dart index b6d177b..57803df 100644 --- a/example/authentication/github_oauth_example.dart +++ b/example/authentication/github_oauth_example.dart @@ -393,7 +393,7 @@ Future main(List args) async { ); // Create MCP client - final client = Client( + final client = McpClient( const Implementation(name: 'github-mcp-dart-client', version: '1.0.0'), ); diff --git a/example/authentication/github_pat_example.dart b/example/authentication/github_pat_example.dart index fea4df9..c22c403 100644 --- a/example/authentication/github_pat_example.dart +++ b/example/authentication/github_pat_example.dart @@ -86,7 +86,7 @@ Future main(List args) async { } // Create MCP client - final client = Client( + final client = McpClient( const Implementation(name: 'github-mcp-pat-client', version: '1.0.0'), ); diff --git a/example/authentication/oauth_client_example.dart b/example/authentication/oauth_client_example.dart index de6b130..f73368d 100644 --- a/example/authentication/oauth_client_example.dart +++ b/example/authentication/oauth_client_example.dart @@ -375,7 +375,7 @@ Future main(List args) async { final authProvider = OAuth2Provider(config: config, storage: storage); // Create MCP client - final client = Client( + final client = McpClient( const Implementation(name: 'oauth-example-client', version: '1.0.0'), ); diff --git a/example/client_stdio.dart b/example/client_stdio.dart index 885e202..e3cfa9d 100644 --- a/example/client_stdio.dart +++ b/example/client_stdio.dart @@ -31,7 +31,7 @@ Future main() async { const Implementation(name: 'ExampleClient', version: '1.0.0'); // Create the MCP client - final client = Client(clientInfo); + final client = McpClient(clientInfo); // Set up error and close handlers transport.onerror = (error) { @@ -76,13 +76,13 @@ Future main() async { print('Calling a tool...'); final resourceResult = await client.readResource( - const ReadResourceRequestParams(uri: 'file:///logs'), + const ReadResourceRequest(uri: 'file:///logs'), ); print('Tool result: ${resourceResult.toJson()}'); print('Calling a prompt...'); final promptResult = await client.getPrompt( - const GetPromptRequestParams( + const GetPromptRequest( name: 'analyze-code', arguments: {'language': "python"}, ), diff --git a/example/completions_capability_demo.dart b/example/completions_capability_demo.dart index 5097130..4d515c8 100644 --- a/example/completions_capability_demo.dart +++ b/example/completions_capability_demo.dart @@ -13,7 +13,7 @@ void main() async { // Server declares completions support explicitly per 2025-06-18 spec final server = McpServer( const Implementation(name: "completions-demo", version: "1.0.0"), - options: const ServerOptions( + options: const McpServerOptions( capabilities: ServerCapabilities( completions: ServerCapabilitiesCompletions(), resources: ServerCapabilitiesResources(), diff --git a/example/elicitation_http_server.dart b/example/elicitation_http_server.dart index 7ffd801..eb36310 100644 --- a/example/elicitation_http_server.dart +++ b/example/elicitation_http_server.dart @@ -78,7 +78,7 @@ McpServer getServer() { try { // Collect username final usernameResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Enter your username (3-20 characters)', requestedSchema: JsonSchema.object( properties: { @@ -105,7 +105,7 @@ McpServer getServer() { // Collect email final emailResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Enter your email address', requestedSchema: JsonSchema.object( properties: { @@ -131,7 +131,7 @@ McpServer getServer() { // Collect password final passwordResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Enter your password (min 8 characters)', requestedSchema: JsonSchema.object( properties: { @@ -155,7 +155,7 @@ McpServer getServer() { // Collect newsletter preference final newsletterResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Subscribe to newsletter?', requestedSchema: JsonSchema.object( properties: { @@ -205,7 +205,7 @@ Newsletter: ${newsletter ? 'Yes' : 'No'}''', try { // Step 1: Collect basic event information final titleResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Step 1: Enter event title', requestedSchema: JsonSchema.object( properties: { @@ -228,7 +228,7 @@ Newsletter: ${newsletter ? 'Yes' : 'No'}''', final title = titleResult.content?['title'] as String; final descriptionResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Enter event description (optional, or type "skip")', requestedSchema: JsonSchema.object( properties: { @@ -250,7 +250,7 @@ Newsletter: ${newsletter ? 'Yes' : 'No'}''', // Step 2: Collect date and time final dateResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Step 2: Enter event date (YYYY-MM-DD)', requestedSchema: JsonSchema.object( properties: { @@ -273,7 +273,7 @@ Newsletter: ${newsletter ? 'Yes' : 'No'}''', final date = dateResult.content?['date'] as String; final startTimeResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Enter start time (HH:MM)', requestedSchema: JsonSchema.object( properties: { @@ -296,7 +296,7 @@ Newsletter: ${newsletter ? 'Yes' : 'No'}''', final startTime = startTimeResult.content?['startTime'] as String; final durationResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Enter duration in minutes (15-480)', requestedSchema: JsonSchema.object( properties: { @@ -354,7 +354,7 @@ Duration: $duration minutes''', try { // Collect name final nameResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Enter recipient full name', requestedSchema: JsonSchema.object( properties: { @@ -380,7 +380,7 @@ Duration: $duration minutes''', // Collect street address final streetResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Enter street address', requestedSchema: JsonSchema.object( properties: { @@ -406,7 +406,7 @@ Duration: $duration minutes''', // Collect city final cityResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Enter city', requestedSchema: JsonSchema.object( properties: { @@ -432,7 +432,7 @@ Duration: $duration minutes''', // Collect state (2 letters) final stateResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Enter state/province (2 letters)', requestedSchema: JsonSchema.object( properties: { @@ -460,7 +460,7 @@ Duration: $duration minutes''', // Collect ZIP code final zipResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Enter ZIP/Postal code', requestedSchema: JsonSchema.object( properties: { @@ -487,7 +487,7 @@ Duration: $duration minutes''', // Collect optional phone number final phoneResult = await server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: 'Enter phone number (optional, or type "skip")', requestedSchema: JsonSchema.object( properties: { diff --git a/example/flutter_http_client/lib/services/streamable_mcp_service.dart b/example/flutter_http_client/lib/services/streamable_mcp_service.dart index 42223df..f168245 100644 --- a/example/flutter_http_client/lib/services/streamable_mcp_service.dart +++ b/example/flutter_http_client/lib/services/streamable_mcp_service.dart @@ -24,7 +24,7 @@ class NotificationMessage { /// MCP Client Service with StreamableHttpClientTransport class StreamableMcpService extends ChangeNotifier { // MCP client properties - Client? _client; + McpClient? _client; StreamableHttpClientTransport? _transport; String serverUrl; String? _sessionId; @@ -75,7 +75,7 @@ class StreamableMcpService extends ChangeNotifier { try { // Create a new client - _client = Client( + _client = McpClient( Implementation(name: 'flutter-mcp-client', version: '1.0.0'), ); @@ -390,7 +390,7 @@ class StreamableMcpService extends ChangeNotifier { throw Exception('Not connected to server.'); } - final params = GetPromptRequestParams( + final params = GetPromptRequest( name: name, arguments: Map.from( args.map((key, value) => MapEntry(key, value.toString())), diff --git a/example/gemini-client/bin/main.dart b/example/gemini-client/bin/main.dart index b76bfb9..8d16d2d 100644 --- a/example/gemini-client/bin/main.dart +++ b/example/gemini-client/bin/main.dart @@ -18,7 +18,7 @@ void main(List args) async { final client = GoogleMcpClient( GenerativeModel(model: 'gemini-2.0-flash', apiKey: apiKey), - Client(Implementation(name: "gemini-client", version: "1.0.0")), + McpClient(Implementation(name: "gemini-client", version: "1.0.0")), ); try { diff --git a/example/gemini-client/lib/gemini_client.dart b/example/gemini-client/lib/gemini_client.dart index eaf1f55..a1f4261 100644 --- a/example/gemini-client/lib/gemini_client.dart +++ b/example/gemini-client/lib/gemini_client.dart @@ -48,7 +48,7 @@ extension SchemaExtension on Schema { /// A client for interacting with an MCP server and Google's Generative AI API. class GoogleMcpClient { /// The MCP client instance. - final mcp_dart.Client mcp; + final mcp_dart.McpClient mcp; /// The Generative AI model instance. final GenerativeModel model; diff --git a/example/iostream-client-server/server_iostream.dart b/example/iostream-client-server/server_iostream.dart index 6cd1d81..d32a9a1 100644 --- a/example/iostream-client-server/server_iostream.dart +++ b/example/iostream-client-server/server_iostream.dart @@ -8,7 +8,7 @@ Future getServer() async { name: "example-dart-iostream-server", version: "1.0.0", ), - options: const ServerOptions(capabilities: ServerCapabilities()), + options: const McpServerOptions(capabilities: ServerCapabilities()), ); mcpServer.registerTool( diff --git a/example/iostream-client-server/simple.dart b/example/iostream-client-server/simple.dart index a5e5112..cf35c45 100644 --- a/example/iostream-client-server/simple.dart +++ b/example/iostream-client-server/simple.dart @@ -6,12 +6,12 @@ import 'server_iostream.dart'; /// Creates and returns a client with custom stream transport connected to a server. Future main() async { // Create a client - final client = Client( + final client = McpClient( const Implementation( name: "example-dart-iostream-client", version: "1.0.0", ), - options: const ClientOptions(capabilities: ClientCapabilities()), + options: const McpClientOptions(capabilities: ClientCapabilities()), ); final server = await getServer(); diff --git a/example/iostream-client-server/with_pipe_helper.dart b/example/iostream-client-server/with_pipe_helper.dart index efa9579..b876e13 100644 --- a/example/iostream-client-server/with_pipe_helper.dart +++ b/example/iostream-client-server/with_pipe_helper.dart @@ -32,12 +32,12 @@ class PipeTransport { /// Creates and returns a client with custom stream transport connected to a server. Future main() async { // Create a client - final client = Client( + final client = McpClient( const Implementation( name: "example-dart-iostream-client", version: "1.0.0", ), - options: const ClientOptions(capabilities: ClientCapabilities()), + options: const McpClientOptions(capabilities: ClientCapabilities()), ); final server = await getServer(); diff --git a/example/server_sse.dart b/example/server_sse.dart index 70170d3..0e6fa6e 100644 --- a/example/server_sse.dart +++ b/example/server_sse.dart @@ -5,7 +5,7 @@ import 'package:mcp_dart/mcp_dart.dart'; Future main() async { final mcpServer = McpServer( const Implementation(name: "example-dart-server", version: "1.0.0"), - options: const ServerOptions(capabilities: ServerCapabilities()), + options: const McpServerOptions(capabilities: ServerCapabilities()), ); mcpServer.registerTool( diff --git a/example/server_stdio.dart b/example/server_stdio.dart index 079ed32..d2c38f0 100644 --- a/example/server_stdio.dart +++ b/example/server_stdio.dart @@ -3,7 +3,7 @@ import 'package:mcp_dart/mcp_dart.dart'; void main() async { final McpServer server = McpServer( const Implementation(name: "example_server", version: "1.0.0"), - options: const ServerOptions( + options: const McpServerOptions( capabilities: ServerCapabilities( resources: ServerCapabilitiesResources(), tools: ServerCapabilitiesTools(), diff --git a/example/simple_task_interactive_client.dart b/example/simple_task_interactive_client.dart index 68ef789..69022d4 100644 --- a/example/simple_task_interactive_client.dart +++ b/example/simple_task_interactive_client.dart @@ -41,7 +41,7 @@ String getTextContent(CallToolResult result) { return textContent?.text ?? '(no text)'; } -Future elicitationCallback(ElicitRequestParams params) async { +Future elicitationCallback(ElicitRequest params) async { // Give the polling loop a chance to print the status update await Future.delayed(const Duration(milliseconds: 200)); @@ -59,7 +59,7 @@ Future elicitationCallback(ElicitRequestParams params) async { } Future samplingCallback( - CreateMessageRequestParams params, + CreateMessageRequest params, ) async { // Give the polling loop a chance to print the status update await Future.delayed(const Duration(milliseconds: 200)); @@ -96,12 +96,12 @@ Future run(String url) async { print('Connecting to $url...'); // Create client with elicitation and sampling capabilities - final client = Client( + final client = McpClient( const Implementation( name: 'simple-task-interactive-client', version: '1.0.0', ), - options: const ClientOptions( + options: const McpClientOptions( capabilities: ClientCapabilities( elicitation: ClientElicitation.formOnly(), sampling: ClientCapabilitiesSampling(), diff --git a/example/simple_task_interactive_server.dart b/example/simple_task_interactive_server.dart index 3b6d27f..b018458 100644 --- a/example/simple_task_interactive_server.dart +++ b/example/simple_task_interactive_server.dart @@ -44,7 +44,7 @@ class InteractiveServer { final server = McpServer( const Implementation(name: 'simple-task-interactive', version: '1.0.0'), - options: const ServerOptions( + options: const McpServerOptions( capabilities: ServerCapabilities( tools: ServerCapabilitiesTools(), tasks: ServerCapabilitiesTasks(listChanged: true), diff --git a/example/streamable_https/client_streamable_https.dart b/example/streamable_https/client_streamable_https.dart index 3ac59ec..4ed734a 100644 --- a/example/streamable_https/client_streamable_https.dart +++ b/example/streamable_https/client_streamable_https.dart @@ -5,7 +5,7 @@ import 'dart:io'; import 'package:mcp_dart/mcp_dart.dart'; // Global client and transport for interactive commands -Client? client; +McpClient? client; StreamableHttpClientTransport? transport; String serverUrl = 'http://localhost:3000/mcp'; String? notificationsToolLastEventId; @@ -187,7 +187,7 @@ Future connect([String? url]) async { try { // Create a new client - client = Client( + client = McpClient( const Implementation(name: 'example-client', version: '1.0.0'), ); client!.onerror = (error) { @@ -424,7 +424,7 @@ Future getPrompt(String name, Map args) async { } try { - final params = GetPromptRequestParams( + final params = GetPromptRequest( name: name, arguments: Map.from( args.map( diff --git a/example/streamable_https/high_level_server.dart b/example/streamable_https/high_level_server.dart index b0d4dbc..8ba797e 100644 --- a/example/streamable_https/high_level_server.dart +++ b/example/streamable_https/high_level_server.dart @@ -76,7 +76,7 @@ McpServer getServer() { // Send debug notification await extra.sendNotification( JsonRpcLoggingMessageNotification( - logParams: LoggingMessageNotificationParams( + logParams: LoggingMessageNotification( level: LoggingLevel.debug, data: 'Starting multi-greet for $name', ), @@ -88,7 +88,7 @@ McpServer getServer() { // Send first info notification await extra.sendNotification( JsonRpcLoggingMessageNotification( - logParams: LoggingMessageNotificationParams( + logParams: LoggingMessageNotification( level: LoggingLevel.info, data: 'Sending first greeting to $name', ), @@ -100,7 +100,7 @@ McpServer getServer() { // Send second info notification await extra.sendNotification( JsonRpcLoggingMessageNotification( - logParams: LoggingMessageNotificationParams( + logParams: LoggingMessageNotification( level: LoggingLevel.info, data: 'Sending second greeting to $name', ), @@ -171,7 +171,7 @@ McpServer getServer() { try { await extra.sendNotification( JsonRpcLoggingMessageNotification( - logParams: LoggingMessageNotificationParams( + logParams: LoggingMessageNotification( level: LoggingLevel.info, data: 'Periodic notification #$counter at ${DateTime.now().toIso8601String()}', diff --git a/example/streamable_https/server_streamable_https.dart b/example/streamable_https/server_streamable_https.dart index aeed2cd..b145706 100644 --- a/example/streamable_https/server_streamable_https.dart +++ b/example/streamable_https/server_streamable_https.dart @@ -110,7 +110,7 @@ McpServer getServer() { // Send debug notification await extra.sendNotification( JsonRpcLoggingMessageNotification( - logParams: LoggingMessageNotificationParams( + logParams: LoggingMessageNotification( level: LoggingLevel.debug, data: 'Starting multi-greet for $name', ), @@ -122,7 +122,7 @@ McpServer getServer() { // Send first info notification await extra.sendNotification( JsonRpcLoggingMessageNotification( - logParams: LoggingMessageNotificationParams( + logParams: LoggingMessageNotification( level: LoggingLevel.info, data: 'Sending first greeting to $name', ), @@ -134,7 +134,7 @@ McpServer getServer() { // Send second info notification await extra.sendNotification( JsonRpcLoggingMessageNotification( - logParams: LoggingMessageNotificationParams( + logParams: LoggingMessageNotification( level: LoggingLevel.info, data: 'Sending second greeting to $name', ), @@ -206,7 +206,7 @@ McpServer getServer() { try { await extra.sendNotification( JsonRpcLoggingMessageNotification( - logParams: LoggingMessageNotificationParams( + logParams: LoggingMessageNotification( level: LoggingLevel.info, data: 'Periodic notification #$counter at ${DateTime.now().toIso8601String()}', diff --git a/lib/fix_data.yaml b/lib/fix_data.yaml new file mode 100644 index 0000000..829f44f --- /dev/null +++ b/lib/fix_data.yaml @@ -0,0 +1,347 @@ +version: 1 + +transforms: + # --- Types: Elicitation --- + - title: "Rename to 'ElicitRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/elicitation.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'ElicitRequestParams' + changes: + - kind: 'rename' + newName: 'ElicitRequest' + + - title: "Rename to 'ElicitationCompleteNotification'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/elicitation.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'ElicitationCompleteParams' + changes: + - kind: 'rename' + newName: 'ElicitationCompleteNotification' + + # --- Types: Client/Server Options --- + - title: "Rename to 'McpClientOptions'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/client/client.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'ClientOptions' + changes: + - kind: 'rename' + newName: 'McpClientOptions' + + - title: "Rename to 'McpServerOptions'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/server/server.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'ServerOptions' + changes: + - kind: 'rename' + newName: 'McpServerOptions' + + - title: "Rename to 'McpClient'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/client/client.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'Client' + changes: + - kind: 'rename' + newName: 'McpClient' + + - title: "Rename to 'McpServer'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/server/server.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'Server' + changes: + - kind: 'rename' + newName: 'McpServer' + + # --- Types: Initialization --- + - title: "Rename to 'InitializeRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/initialization.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'InitializeRequestParams' + changes: + - kind: 'rename' + newName: 'InitializeRequest' + + # --- Types: Tools --- + - title: "Rename to 'ListToolsRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/tools.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'ListToolsRequestParams' + changes: + - kind: 'rename' + newName: 'ListToolsRequest' + + - title: "Rename to 'CallToolRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/tools.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'CallToolRequestParams' + changes: + - kind: 'rename' + newName: 'CallToolRequest' + + # --- Types: Resources --- + - title: "Rename to 'ListResourcesRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/resources.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'ListResourcesRequestParams' + changes: + - kind: 'rename' + newName: 'ListResourcesRequest' + + - title: "Rename to 'ListResourceTemplatesRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/resources.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'ListResourceTemplatesRequestParams' + changes: + - kind: 'rename' + newName: 'ListResourceTemplatesRequest' + + - title: "Rename to 'ReadResourceRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/resources.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'ReadResourceRequestParams' + changes: + - kind: 'rename' + newName: 'ReadResourceRequest' + + - title: "Rename to 'SubscribeRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/resources.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'SubscribeRequestParams' + changes: + - kind: 'rename' + newName: 'SubscribeRequest' + + - title: "Rename to 'UnsubscribeRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/resources.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'UnsubscribeRequestParams' + changes: + - kind: 'rename' + newName: 'UnsubscribeRequest' + + - title: "Rename to 'ResourceUpdatedNotification'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/resources.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'ResourceUpdatedNotificationParams' + changes: + - kind: 'rename' + newName: 'ResourceUpdatedNotification' + + # --- Types: Prompts --- + - title: "Rename to 'ListPromptsRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/prompts.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'ListPromptsRequestParams' + changes: + - kind: 'rename' + newName: 'ListPromptsRequest' + + - title: "Rename to 'GetPromptRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/prompts.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'GetPromptRequestParams' + changes: + - kind: 'rename' + newName: 'GetPromptRequest' + + # --- Types: Completion --- + - title: "Rename to 'CompleteRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/completion.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'CompleteRequestParams' + changes: + - kind: 'rename' + newName: 'CompleteRequest' + + # --- Types: Logging --- + - title: "Rename to 'SetLevelRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/logging.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'SetLevelRequestParams' + changes: + - kind: 'rename' + newName: 'SetLevelRequest' + + - title: "Rename to 'LoggingMessageNotification'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/logging.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'LoggingMessageNotificationParams' + changes: + - kind: 'rename' + newName: 'LoggingMessageNotification' + + # --- Types: Sampling --- + - title: "Rename to 'CreateMessageRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/sampling.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'CreateMessageRequestParams' + changes: + - kind: 'rename' + newName: 'CreateMessageRequest' + + # --- Types: Tasks --- + - title: "Rename to 'ListTasksRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/tasks.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'ListTasksRequestParams' + changes: + - kind: 'rename' + newName: 'ListTasksRequest' + + - title: "Rename to 'CancelTaskRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/tasks.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'CancelTaskRequestParams' + changes: + - kind: 'rename' + newName: 'CancelTaskRequest' + + - title: "Rename to 'GetTaskRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/tasks.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'GetTaskRequestParams' + changes: + - kind: 'rename' + newName: 'GetTaskRequest' + + - title: "Rename to 'TaskResultRequest'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/tasks.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'TaskResultRequestParams' + changes: + - kind: 'rename' + newName: 'TaskResultRequest' + + - title: "Rename to 'TaskStatusNotification'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/tasks.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'TaskStatusNotificationParams' + changes: + - kind: 'rename' + newName: 'TaskStatusNotification' + + # --- Methods: McpServer --- + - title: "Rename to 'registerResource'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/server/mcp_server.dart' + - 'package:mcp_dart/mcp_dart.dart' + method: 'resource' + inClass: 'McpServer' + changes: + - kind: 'rename' + newName: 'registerResource' + + - title: "Rename to 'registerResourceTemplate'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/server/mcp_server.dart' + - 'package:mcp_dart/mcp_dart.dart' + method: 'resourceTemplate' + inClass: 'McpServer' + changes: + - kind: 'rename' + newName: 'registerResourceTemplate' + + - title: "Rename to 'registerTool'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/server/mcp_server.dart' + - 'package:mcp_dart/mcp_dart.dart' + method: 'tool' + inClass: 'McpServer' + changes: + - kind: 'rename' + newName: 'registerTool' + + - title: "Rename to 'registerPrompt'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/server/mcp_server.dart' + - 'package:mcp_dart/mcp_dart.dart' + method: 'prompt' + inClass: 'McpServer' + changes: + - kind: 'rename' + newName: 'registerPrompt' diff --git a/lib/src/client/client.dart b/lib/src/client/client.dart index 3edb1ed..c681759 100644 --- a/lib/src/client/client.dart +++ b/lib/src/client/client.dart @@ -7,17 +7,21 @@ import 'package:mcp_dart/src/types.dart'; final _logger = Logger("mcp_dart.client"); -/// Options for configuring the MCP [Client]. -class ClientOptions extends ProtocolOptions { +/// Options for configuring the MCP [McpClient]. +class McpClientOptions extends ProtocolOptions { /// Capabilities to advertise as being supported by this client. final ClientCapabilities? capabilities; - const ClientOptions({ + const McpClientOptions({ super.enforceStrictCapabilities, this.capabilities, }); } +/// Deprecated alias for [McpClientOptions]. +@Deprecated('Use McpClientOptions instead') +typedef ClientOptions = McpClientOptions; + /// Recursively applies default values from a JSON Schema to a data object. /// Recursively applies default values from a JSON Schema to a data object. // Recursively applies default values from a JSON Schema to a data object. @@ -64,7 +68,7 @@ dynamic _deepCopy(dynamic value) { /// /// Handles the initialization handshake with the server upon connection /// and provides methods for making standard MCP requests. -class Client extends Protocol { +class McpClient extends Protocol { ServerCapabilities? _serverCapabilities; Implementation? _serverVersion; ClientCapabilities _capabilities; @@ -79,23 +83,23 @@ class Client extends Protocol { /// This will be called when the server sends an `elicitation/create` request /// to collect structured user input. The client should prompt the user /// and return an [ElicitResult] with the action taken and content provided. - Future Function(ElicitRequestParams)? onElicitRequest; + Future Function(ElicitRequest)? onElicitRequest; /// Callback for handling task status notifications from the server. - FutureOr Function(TaskStatusNotificationParams params)? onTaskStatus; + FutureOr Function(TaskStatusNotification params)? onTaskStatus; /// Callback for handling sampling requests from the server. /// /// This will be called when the server sends a `sampling/createMessage` request /// to request an LLM completion from the client. - Future Function(CreateMessageRequestParams params)? + Future Function(CreateMessageRequest params)? onSamplingRequest; /// Initializes this client with its implementation details and options. /// /// - [_clientInfo]: Information about this client's name and version. /// - [options]: Optional configuration settings including client capabilities. - Client(this._clientInfo, {ClientOptions? options}) + McpClient(this._clientInfo, {McpClientOptions? options}) : _capabilities = options?.capabilities ?? const ClientCapabilities(), super(options) { // Register elicit handler if capability is present @@ -126,7 +130,7 @@ class Client extends Protocol { }, (id, params, meta) => JsonRpcElicitRequest( id: id, - elicitParams: ElicitRequestParams.fromJson(params ?? {}), + elicitParams: ElicitRequest.fromJson(params ?? {}), meta: meta, ), ); @@ -140,7 +144,7 @@ class Client extends Protocol { await onTaskStatus?.call(notification.statusParams); }, (params, meta) => JsonRpcTaskStatusNotification( - statusParams: TaskStatusNotificationParams.fromJson(params ?? {}), + statusParams: TaskStatusNotification.fromJson(params ?? {}), meta: meta, ), ); @@ -161,7 +165,7 @@ class Client extends Protocol { }, (id, params, meta) => JsonRpcCreateMessageRequest( id: id, - createParams: CreateMessageRequestParams.fromJson(params ?? {}), + createParams: CreateMessageRequest.fromJson(params ?? {}), meta: meta, ), ); @@ -195,7 +199,7 @@ class Client extends Protocol { } try { - final initParams = InitializeRequestParams( + final initParams = InitializeRequest( protocolVersion: latestProtocolVersion, capabilities: _capabilities, clientInfo: _clientInfo, @@ -379,7 +383,7 @@ class Client extends Protocol { /// Sends a `completion/complete` request to the server for argument completion. Future complete( - CompleteRequestParams params, [ + CompleteRequest params, [ RequestOptions? options, ]) { final req = JsonRpcCompleteRequest(id: -1, completeParams: params); @@ -395,14 +399,14 @@ class Client extends Protocol { LoggingLevel level, [ RequestOptions? options, ]) { - final params = SetLevelRequestParams(level: level); + final params = SetLevelRequest(level: level); final req = JsonRpcSetLevelRequest(id: -1, setParams: params); return request(req, (json) => const EmptyResult(), options); } /// Sends a `prompts/get` request to retrieve a specific prompt/template. Future getPrompt( - GetPromptRequestParams params, [ + GetPromptRequest params, [ RequestOptions? options, ]) { final req = JsonRpcGetPromptRequest(id: -1, getParams: params); @@ -415,7 +419,7 @@ class Client extends Protocol { /// Sends a `prompts/list` request to list available prompts/templates. Future listPrompts({ - ListPromptsRequestParams? params, + ListPromptsRequest? params, RequestOptions? options, }) { final req = JsonRpcListPromptsRequest(id: -1, params: params); @@ -428,7 +432,7 @@ class Client extends Protocol { /// Sends a `resources/list` request to list available resources. Future listResources({ - ListResourcesRequestParams? params, + ListResourcesRequest? params, RequestOptions? options, }) { final req = JsonRpcListResourcesRequest(id: -1, params: params); @@ -441,7 +445,7 @@ class Client extends Protocol { /// Sends a `resources/templates/list` request to list available resource templates. Future listResourceTemplates({ - ListResourceTemplatesRequestParams? params, + ListResourceTemplatesRequest? params, RequestOptions? options, }) { final req = JsonRpcListResourceTemplatesRequest(id: -1, params: params); @@ -454,7 +458,7 @@ class Client extends Protocol { /// Sends a `resources/read` request to read the content of a resource. Future readResource( - ReadResourceRequestParams params, [ + ReadResourceRequest params, [ RequestOptions? options, ]) { final req = JsonRpcReadResourceRequest(id: -1, readParams: params); @@ -467,7 +471,7 @@ class Client extends Protocol { /// Sends a `resources/subscribe` request to subscribe to updates for a resource. Future subscribeResource( - SubscribeRequestParams params, [ + SubscribeRequest params, [ RequestOptions? options, ]) { final req = JsonRpcSubscribeRequest(id: -1, subParams: params); @@ -476,7 +480,7 @@ class Client extends Protocol { /// Sends a `resources/unsubscribe` request to cancel a resource subscription. Future unsubscribeResource( - UnsubscribeRequestParams params, [ + UnsubscribeRequest params, [ RequestOptions? options, ]) { final req = JsonRpcUnsubscribeRequest(id: -1, unsubParams: params); @@ -555,3 +559,7 @@ class Client extends Protocol { return notification(notif); } } + +/// Deprecated alias for [McpClient]. +@Deprecated('Use McpClient instead') +typedef Client = McpClient; diff --git a/lib/src/client/task_client.dart b/lib/src/client/task_client.dart index ddd3959..309c2dd 100644 --- a/lib/src/client/task_client.dart +++ b/lib/src/client/task_client.dart @@ -21,7 +21,7 @@ class _RawResult implements BaseResultData { /// which may either return an immediate result or create a long-running task. /// It handles polling for task status and retrieving the final result. class TaskClient { - final Client client; + final McpClient client; TaskClient(this.client); @@ -145,7 +145,7 @@ class TaskClient { Future _getTask(String taskId) async { final req = JsonRpcGetTaskRequest( id: -1, - getParams: GetTaskRequestParams(taskId: taskId), + getParams: GetTaskRequest(taskId: taskId), ); return await client.request( @@ -157,7 +157,7 @@ class TaskClient { Future _getTaskResult(String taskId) async { final req = JsonRpcTaskResultRequest( id: -1, - resultParams: TaskResultRequestParams(taskId: taskId), + resultParams: TaskResultRequest(taskId: taskId), ); return await client.request( req, @@ -179,7 +179,7 @@ class TaskClient { Future cancelTask(String taskId) async { final req = JsonRpcCancelTaskRequest( id: -1, - cancelParams: CancelTaskRequestParams(taskId: taskId), + cancelParams: CancelTaskRequest(taskId: taskId), ); await client.request( req, diff --git a/lib/src/server/mcp_server.dart b/lib/src/server/mcp_server.dart index 6c36cb9..b2ff8cc 100644 --- a/lib/src/server/mcp_server.dart +++ b/lib/src/server/mcp_server.dart @@ -685,7 +685,7 @@ class ExperimentalMcpServerTasks { /// Sends an `elicitation/create` request associated with a specific task. Future elicitForTask( String taskId, - ElicitRequestParams params, [ + ElicitRequest params, [ RequestOptions? options, ]) { final req = JsonRpcElicitRequest( @@ -705,7 +705,7 @@ class ExperimentalMcpServerTasks { /// Sends a `sampling/createMessage` request associated with a specific task. Future createMessageForTask( String taskId, - CreateMessageRequestParams params, [ + CreateMessageRequest params, [ RequestOptions? options, ]) { final req = JsonRpcCreateMessageRequest( @@ -779,7 +779,7 @@ class McpServer { _experimental ??= ExperimentalMcpServerTasks(this); /// Creates an [McpServer] instance. - McpServer(Implementation serverInfo, {ServerOptions? options}) { + McpServer(Implementation serverInfo, {McpServerOptions? options}) { // ignore: deprecated_member_use_from_same_package server = Server(serverInfo, options: options); } @@ -799,7 +799,7 @@ class McpServer { /// Sends a logging message to the client, if connected. Future sendLoggingMessage( - LoggingMessageNotificationParams params, { + LoggingMessageNotification params, { String? sessionId, }) async { return server.sendLoggingMessage(params, sessionId: sessionId); @@ -1711,7 +1711,7 @@ class McpServer { /// Requests structured user input from the client using form mode. Future elicitInput( - ElicitRequestParams params, [ + ElicitRequest params, [ RequestOptions? options, ]) async { return server.elicitInput(params, options); diff --git a/lib/src/server/server.dart b/lib/src/server/server.dart index cc71d64..5f890d4 100644 --- a/lib/src/server/server.dart +++ b/lib/src/server/server.dart @@ -7,21 +7,25 @@ import 'package:mcp_dart/src/types.dart'; final _logger = Logger("mcp_dart.server"); -/// Options for configuring the MCP server. -class ServerOptions extends ProtocolOptions { +/// Options for configuring the MCP [McpServer]. +class McpServerOptions extends ProtocolOptions { /// Capabilities to advertise as being supported by this server. final ServerCapabilities? capabilities; /// Optional instructions describing how to use the server and its features. final String? instructions; - const ServerOptions({ + const McpServerOptions({ super.enforceStrictCapabilities, this.capabilities, this.instructions, }); } +/// Deprecated alias for [McpServerOptions]. +@Deprecated('Use McpServerOptions instead') +typedef ServerOptions = McpServerOptions; + /// An MCP server implementation built on top of a pluggable [Transport]. /// /// This server automatically handles the initialization flow initiated by the client. @@ -52,11 +56,12 @@ class Server extends Protocol { LoggingLevel.emergency: 7, }; - /// Callback invoked when initialization has fully completed. + /// Callback to be notified when the server is fully initialized. void Function()? oninitialized; /// Initializes this server with its implementation details and options. - Server(this._serverInfo, {ServerOptions? options}) + /// - [options]: Optional configuration settings including server capabilities. + Server(this._serverInfo, {McpServerOptions? options}) : _capabilities = options?.capabilities ?? const ServerCapabilities(), _instructions = options?.instructions, super(options) { @@ -165,7 +170,7 @@ class Server extends Protocol { } /// Handles the client's `initialize` request. - Future _oninitialize(InitializeRequestParams params) async { + Future _oninitialize(InitializeRequest params) async { final requestedVersion = params.protocolVersion; _clientCapabilities = params.capabilities; @@ -411,7 +416,7 @@ class Server extends Protocol { /// Sends a `sampling/createMessage` request to the client to ask it to sample an LLM. Future createMessage( - CreateMessageRequestParams params, [ + CreateMessageRequest params, [ RequestOptions? options, ]) { // Capability check - only required when tools/toolChoice are provided @@ -489,7 +494,7 @@ class Server extends Protocol { /// Creates an elicitation request for the given parameters. Future elicitInput( - ElicitRequestParams params, [ + ElicitRequest params, [ RequestOptions? options, ]) async { // Mode defaults to 'form' if omitted (handled in types, but logic here too) @@ -559,7 +564,7 @@ class Server extends Protocol { return () => notification( JsonRpcElicitationCompleteNotification( - completeParams: ElicitationCompleteParams( + completeParams: ElicitationCompleteNotification( elicitationId: elicitationId, ), ), @@ -578,7 +583,7 @@ class Server extends Protocol { /// Sends a `notifications/message` (logging) notification to the client. Future sendLoggingMessage( - LoggingMessageNotificationParams params, { + LoggingMessageNotification params, { String? sessionId, }) async { if (_capabilities.logging != null) { @@ -590,7 +595,7 @@ class Server extends Protocol { } /// Sends a `notifications/resources/updated` notification to the client. - Future sendResourceUpdated(ResourceUpdatedNotificationParams params) { + Future sendResourceUpdated(ResourceUpdatedNotification params) { final notif = JsonRpcResourceUpdatedNotification(updatedParams: params); return notification(notif); } diff --git a/lib/src/server/tasks/handler.dart b/lib/src/server/tasks/handler.dart index e535974..bf1ceb1 100644 --- a/lib/src/server/tasks/handler.dart +++ b/lib/src/server/tasks/handler.dart @@ -137,10 +137,10 @@ class TaskResultHandler { dynamic response; if (request.method == 'elicitation/create') { - final params = ElicitRequestParams.fromJson(request.params!); + final params = ElicitRequest.fromJson(request.params!); response = await server.experimental.elicitForTask(taskId, params); } else if (request.method == 'sampling/createMessage') { - final params = CreateMessageRequestParams.fromJson(request.params!); + final params = CreateMessageRequest.fromJson(request.params!); response = await server.experimental.createMessageForTask(taskId, params); } else { diff --git a/lib/src/server/tasks/session.dart b/lib/src/server/tasks/session.dart index 4eaa24e..0eeefde 100644 --- a/lib/src/server/tasks/session.dart +++ b/lib/src/server/tasks/session.dart @@ -27,7 +27,7 @@ class TaskSession { server.server .notification( JsonRpcTaskStatusNotification( - statusParams: TaskStatusNotificationParams( + statusParams: TaskStatusNotification( taskId: taskId, status: task.status, statusMessage: task.statusMessage, @@ -53,7 +53,7 @@ class TaskSession { await _sendTaskStatusNotification(); final requestId = _nextRequestId(); - final params = ElicitRequestParams.form( + final params = ElicitRequest.form( message: message, requestedSchema: requestedSchema, ); @@ -96,7 +96,7 @@ class TaskSession { await _sendTaskStatusNotification(); final requestId = _nextRequestId(); - final params = CreateMessageRequestParams( + final params = CreateMessageRequest( messages: messages, maxTokens: maxTokens, ); diff --git a/lib/src/shared/protocol.dart b/lib/src/shared/protocol.dart index 6869c41..3919fc7 100644 --- a/lib/src/shared/protocol.dart +++ b/lib/src/shared/protocol.dart @@ -1284,7 +1284,7 @@ abstract class Protocol { final currentTask = await request( JsonRpcGetTaskRequest( id: 0, // ID will be overwritten - getParams: GetTaskRequestParams(taskId: taskId), + getParams: GetTaskRequest(taskId: taskId), ), (json) => Task.fromJson(json), options, @@ -1296,7 +1296,7 @@ abstract class Protocol { final result = await request( JsonRpcTaskResultRequest( id: 0, - resultParams: TaskResultRequestParams(taskId: taskId), + resultParams: TaskResultRequest(taskId: taskId), ), resultFactory, options, @@ -1319,7 +1319,7 @@ abstract class Protocol { final result = await request( JsonRpcTaskResultRequest( id: 0, - resultParams: TaskResultRequestParams(taskId: taskId), + resultParams: TaskResultRequest(taskId: taskId), ), resultFactory, options, @@ -1482,7 +1482,7 @@ class _RequestTaskStoreImpl implements RequestTaskStore { final task = await _store.getTask(taskId, _sessionId); if (task != null) { final notification = JsonRpcTaskStatusNotification( - statusParams: TaskStatusNotificationParams( + statusParams: TaskStatusNotification( taskId: task.taskId, status: task.status, statusMessage: task.statusMessage, @@ -1528,7 +1528,7 @@ class _RequestTaskStoreImpl implements RequestTaskStore { final updatedTask = await _store.getTask(taskId, _sessionId); if (updatedTask != null) { final notification = JsonRpcTaskStatusNotification( - statusParams: TaskStatusNotificationParams( + statusParams: TaskStatusNotification( taskId: updatedTask.taskId, status: updatedTask.status, statusMessage: updatedTask.statusMessage, diff --git a/lib/src/types/completion.dart b/lib/src/types/completion.dart index f430df1..13f629d 100644 --- a/lib/src/types/completion.dart +++ b/lib/src/types/completion.dart @@ -80,17 +80,17 @@ class ArgumentCompletionInfo { } /// Parameters for the `completion/complete` request. -class CompleteRequestParams { +class CompleteRequest { /// The reference identifying the completion target (prompt or resource). final Reference ref; /// Information about the argument being completed. final ArgumentCompletionInfo argument; - const CompleteRequestParams({required this.ref, required this.argument}); + const CompleteRequest({required this.ref, required this.argument}); - factory CompleteRequestParams.fromJson(Map json) => - CompleteRequestParams( + factory CompleteRequest.fromJson(Map json) => + CompleteRequest( ref: Reference.fromJson(json['ref'] as Map), argument: ArgumentCompletionInfo.fromJson( json['argument'] as Map, @@ -106,7 +106,7 @@ class CompleteRequestParams { /// Request sent from client to ask server for completion options for an argument. class JsonRpcCompleteRequest extends JsonRpcRequest { /// The completion parameters. - final CompleteRequestParams completeParams; + final CompleteRequest completeParams; JsonRpcCompleteRequest({ required super.id, @@ -125,7 +125,7 @@ class JsonRpcCompleteRequest extends JsonRpcRequest { final meta = paramsMap['_meta'] as Map?; return JsonRpcCompleteRequest( id: json['id'], - completeParams: CompleteRequestParams.fromJson(paramsMap), + completeParams: CompleteRequest.fromJson(paramsMap), meta: meta, ); } @@ -198,3 +198,7 @@ class JsonRpcCompletionListChangedNotification extends JsonRpcNotification { ) => const JsonRpcCompletionListChangedNotification(); } + +/// Deprecated alias for [CompleteRequest]. +@Deprecated('Use CompleteRequest instead') +typedef CompleteRequestParams = CompleteRequest; diff --git a/lib/src/types/elicitation.dart b/lib/src/types/elicitation.dart index 9a4db22..9856021 100644 --- a/lib/src/types/elicitation.dart +++ b/lib/src/types/elicitation.dart @@ -20,7 +20,12 @@ enum ElicitationMode { /// Supports two modes: /// - **Form mode**: Collects structured data directly through the MCP client /// - **URL mode**: Directs users to external URLs for sensitive interactions -class ElicitRequestParams { +/// Parameters for the `elicitation/create` request. +/// +/// Supports two modes: +/// - **Form mode**: Collects structured data directly through the MCP client +/// - **URL mode**: Directs users to external URLs for sensitive interactions +class ElicitRequest { /// The mode of elicitation. Defaults to 'form' if omitted (for backwards compatibility). final ElicitationMode? mode; @@ -39,7 +44,7 @@ class ElicitRequestParams { /// Required for URL mode to correlate with completion notifications. final String? elicitationId; - const ElicitRequestParams({ + const ElicitRequest({ this.mode, required this.message, this.requestedSchema, @@ -48,7 +53,7 @@ class ElicitRequestParams { }); /// Creates form mode elicitation parameters. - const ElicitRequestParams.form({ + const ElicitRequest.form({ required this.message, required ElicitationInputSchema this.requestedSchema, }) : mode = ElicitationMode.form, @@ -56,20 +61,20 @@ class ElicitRequestParams { elicitationId = null; /// Creates URL mode elicitation parameters. - const ElicitRequestParams.url({ + const ElicitRequest.url({ required this.message, required String this.url, required String this.elicitationId, }) : mode = ElicitationMode.url, requestedSchema = null; - factory ElicitRequestParams.fromJson(Map json) { + factory ElicitRequest.fromJson(Map json) { final modeStr = json['mode'] as String?; ElicitationMode? mode; if (modeStr != null) { mode = ElicitationMode.values.byName(modeStr); } - return ElicitRequestParams( + return ElicitRequest( mode: mode, message: json['message'] as String, requestedSchema: json['requestedSchema'] != null @@ -99,7 +104,7 @@ class ElicitRequestParams { /// Request sent from server to client to elicit user input class JsonRpcElicitRequest extends JsonRpcRequest { /// The elicit parameters - final ElicitRequestParams elicitParams; + final ElicitRequest elicitParams; JsonRpcElicitRequest({ required super.id, @@ -115,7 +120,7 @@ class JsonRpcElicitRequest extends JsonRpcRequest { final meta = paramsMap['_meta'] as Map?; return JsonRpcElicitRequest( id: json['id'], - elicitParams: ElicitRequestParams.fromJson(paramsMap), + elicitParams: ElicitRequest.fromJson(paramsMap), meta: meta, ); } @@ -180,14 +185,18 @@ class ElicitResult implements BaseResultData { /// /// Sent by servers when an out-of-band interaction started by URL mode /// elicitation is completed. -class ElicitationCompleteParams { +/// Parameters for the `notifications/elicitation/complete` notification. +/// +/// Sent by servers when an out-of-band interaction started by URL mode +/// elicitation is completed. +class ElicitationCompleteNotification { /// The unique identifier for the elicitation, matching the original request. final String elicitationId; - const ElicitationCompleteParams({required this.elicitationId}); + const ElicitationCompleteNotification({required this.elicitationId}); - factory ElicitationCompleteParams.fromJson(Map json) { - return ElicitationCompleteParams( + factory ElicitationCompleteNotification.fromJson(Map json) { + return ElicitationCompleteNotification( elicitationId: json['elicitationId'] as String, ); } @@ -201,7 +210,7 @@ class ElicitationCompleteParams { /// interaction (started via URL mode elicitation) is completed. class JsonRpcElicitationCompleteNotification extends JsonRpcNotification { /// The notification parameters containing the elicitation ID. - final ElicitationCompleteParams completeParams; + final ElicitationCompleteNotification completeParams; JsonRpcElicitationCompleteNotification({ required this.completeParams, @@ -222,7 +231,7 @@ class JsonRpcElicitationCompleteNotification extends JsonRpcNotification { } final meta = paramsMap['_meta'] as Map?; return JsonRpcElicitationCompleteNotification( - completeParams: ElicitationCompleteParams.fromJson(paramsMap), + completeParams: ElicitationCompleteNotification.fromJson(paramsMap), meta: meta, ); } @@ -235,7 +244,7 @@ class JsonRpcElicitationCompleteNotification extends JsonRpcNotification { class URLElicitationRequiredErrorData { /// List of elicitations that are required to complete. /// All elicitations MUST be URL mode and have an elicitationId. - final List elicitations; + final List elicitations; const URLElicitationRequiredErrorData({required this.elicitations}); @@ -243,7 +252,7 @@ class URLElicitationRequiredErrorData { final elicitationsList = json['elicitations'] as List? ?? []; return URLElicitationRequiredErrorData( elicitations: elicitationsList - .map((e) => ElicitRequestParams.fromJson(e as Map)) + .map((e) => ElicitRequest.fromJson(e as Map)) .toList(), ); } @@ -252,3 +261,11 @@ class URLElicitationRequiredErrorData { 'elicitations': elicitations.map((e) => e.toJson()).toList(), }; } + +/// Deprecated alias for [ElicitRequest]. +@Deprecated('Use ElicitRequest instead') +typedef ElicitRequestParams = ElicitRequest; + +/// Deprecated alias for [ElicitationCompleteNotification]. +@Deprecated('Use ElicitationCompleteNotification instead') +typedef ElicitationCompleteParams = ElicitationCompleteNotification; diff --git a/lib/src/types/initialization.dart b/lib/src/types/initialization.dart index 83f3db8..fe6cc15 100644 --- a/lib/src/types/initialization.dart +++ b/lib/src/types/initialization.dart @@ -350,7 +350,7 @@ class ClientCapabilities { } /// Parameters for the `initialize` request. -class InitializeRequestParams { +class InitializeRequest { /// The latest protocol version the client supports. final String protocolVersion; @@ -360,14 +360,14 @@ class InitializeRequestParams { /// Information about the client implementation. final Implementation clientInfo; - const InitializeRequestParams({ + const InitializeRequest({ required this.protocolVersion, required this.capabilities, required this.clientInfo, }); - factory InitializeRequestParams.fromJson(Map json) => - InitializeRequestParams( + factory InitializeRequest.fromJson(Map json) => + InitializeRequest( protocolVersion: json['protocolVersion'] as String, capabilities: ClientCapabilities.fromJson( json['capabilities'] as Map, @@ -387,7 +387,7 @@ class InitializeRequestParams { /// Request sent from client to server upon connection to begin initialization. class JsonRpcInitializeRequest extends JsonRpcRequest { /// The initialization parameters. - final InitializeRequestParams initParams; + final InitializeRequest initParams; JsonRpcInitializeRequest({ required super.id, @@ -403,7 +403,7 @@ class JsonRpcInitializeRequest extends JsonRpcRequest { final meta = paramsMap['_meta'] as Map?; return JsonRpcInitializeRequest( id: json['id'], - initParams: InitializeRequestParams.fromJson(paramsMap), + initParams: InitializeRequest.fromJson(paramsMap), meta: meta, ); } @@ -713,3 +713,7 @@ class JsonRpcInitializedNotification extends JsonRpcNotification { factory JsonRpcInitializedNotification.fromJson(Map json) => const JsonRpcInitializedNotification(); } + +/// Deprecated alias for [InitializeRequest]. +@Deprecated('Use InitializeRequest instead') +typedef InitializeRequestParams = InitializeRequest; diff --git a/lib/src/types/json_rpc.dart b/lib/src/types/json_rpc.dart index 41f6d3e..fdc4264 100644 --- a/lib/src/types/json_rpc.dart +++ b/lib/src/types/json_rpc.dart @@ -379,7 +379,7 @@ class JsonRpcListToolsRequest extends JsonRpcRequest { ) factory JsonRpcListToolsRequest.fromListParams({ required RequestId id, - ListToolsRequestParams? params, + ListToolsRequest? params, Map? meta, }) { return JsonRpcListToolsRequest( diff --git a/lib/src/types/logging.dart b/lib/src/types/logging.dart index a70c005..d6c2cb7 100644 --- a/lib/src/types/logging.dart +++ b/lib/src/types/logging.dart @@ -13,14 +13,14 @@ enum LoggingLevel { } /// Parameters for the `logging/setLevel` request. -class SetLevelRequestParams { +class SetLevelRequest { /// The minimum logging level the client wants to receive. final LoggingLevel level; - const SetLevelRequestParams({required this.level}); + const SetLevelRequest({required this.level}); - factory SetLevelRequestParams.fromJson(Map json) => - SetLevelRequestParams( + factory SetLevelRequest.fromJson(Map json) => + SetLevelRequest( level: LoggingLevel.values.byName(json['level'] as String), ); @@ -30,7 +30,7 @@ class SetLevelRequestParams { /// Request sent from client to enable or adjust logging level from the server. class JsonRpcSetLevelRequest extends JsonRpcRequest { /// The set level parameters. - final SetLevelRequestParams setParams; + final SetLevelRequest setParams; JsonRpcSetLevelRequest({ required super.id, @@ -46,14 +46,14 @@ class JsonRpcSetLevelRequest extends JsonRpcRequest { final meta = paramsMap['_meta'] as Map?; return JsonRpcSetLevelRequest( id: json['id'], - setParams: SetLevelRequestParams.fromJson(paramsMap), + setParams: SetLevelRequest.fromJson(paramsMap), meta: meta, ); } } /// Parameters for the `notifications/message` (or `logging/message`) notification. -class LoggingMessageNotificationParams { +class LoggingMessageNotification { /// The severity of this log message. final LoggingLevel level; @@ -63,16 +63,16 @@ class LoggingMessageNotificationParams { /// The data to be logged (string, object, etc.). final dynamic data; - const LoggingMessageNotificationParams({ + const LoggingMessageNotification({ required this.level, this.logger, this.data, }); - factory LoggingMessageNotificationParams.fromJson( + factory LoggingMessageNotification.fromJson( Map json, ) => - LoggingMessageNotificationParams( + LoggingMessageNotification( level: LoggingLevel.values.byName(json['level'] as String), logger: json['logger'] as String?, data: json['data'], @@ -88,7 +88,7 @@ class LoggingMessageNotificationParams { /// Notification of a log message passed from server to client. class JsonRpcLoggingMessageNotification extends JsonRpcNotification { /// The logging parameters. - final LoggingMessageNotificationParams logParams; + final LoggingMessageNotification logParams; JsonRpcLoggingMessageNotification({required this.logParams, super.meta}) : super(method: Method.notificationsMessage, params: logParams.toJson()); @@ -104,8 +104,16 @@ class JsonRpcLoggingMessageNotification extends JsonRpcNotification { } final meta = paramsMap['_meta'] as Map?; return JsonRpcLoggingMessageNotification( - logParams: LoggingMessageNotificationParams.fromJson(paramsMap), + logParams: LoggingMessageNotification.fromJson(paramsMap), meta: meta, ); } } + +/// Deprecated alias for [SetLevelRequest]. +@Deprecated('Use SetLevelRequest instead') +typedef SetLevelRequestParams = SetLevelRequest; + +/// Deprecated alias for [LoggingMessageNotification]. +@Deprecated('Use LoggingMessageNotification instead') +typedef LoggingMessageNotificationParams = LoggingMessageNotification; diff --git a/lib/src/types/prompts.dart b/lib/src/types/prompts.dart index 59355eb..fcd1579 100644 --- a/lib/src/types/prompts.dart +++ b/lib/src/types/prompts.dart @@ -76,14 +76,14 @@ class Prompt { } /// Parameters for the `prompts/list` request. Includes pagination. -class ListPromptsRequestParams { +class ListPromptsRequest { /// Opaque token for pagination. final Cursor? cursor; - const ListPromptsRequestParams({this.cursor}); + const ListPromptsRequest({this.cursor}); - factory ListPromptsRequestParams.fromJson(Map json) => - ListPromptsRequestParams(cursor: json['cursor'] as String?); + factory ListPromptsRequest.fromJson(Map json) => + ListPromptsRequest(cursor: json['cursor'] as String?); Map toJson() => {if (cursor != null) 'cursor': cursor}; } @@ -91,13 +91,13 @@ class ListPromptsRequestParams { /// Request sent from client to list available prompts and templates. class JsonRpcListPromptsRequest extends JsonRpcRequest { /// The list parameters (containing cursor). - final ListPromptsRequestParams listParams; + final ListPromptsRequest listParams; JsonRpcListPromptsRequest({ required super.id, - ListPromptsRequestParams? params, + ListPromptsRequest? params, super.meta, - }) : listParams = params ?? const ListPromptsRequestParams(), + }) : listParams = params ?? const ListPromptsRequest(), super(method: Method.promptsList, params: params?.toJson()); factory JsonRpcListPromptsRequest.fromJson(Map json) { @@ -105,9 +105,7 @@ class JsonRpcListPromptsRequest extends JsonRpcRequest { final meta = paramsMap?['_meta'] as Map?; return JsonRpcListPromptsRequest( id: json['id'], - params: paramsMap == null - ? null - : ListPromptsRequestParams.fromJson(paramsMap), + params: paramsMap == null ? null : ListPromptsRequest.fromJson(paramsMap), meta: meta, ); } @@ -147,17 +145,17 @@ class ListPromptsResult implements BaseResultData { } /// Parameters for the `prompts/get` request. -class GetPromptRequestParams { +class GetPromptRequest { /// The name of the prompt or template to retrieve. final String name; /// Arguments to use for templating the prompt. final Map? arguments; - const GetPromptRequestParams({required this.name, this.arguments}); + const GetPromptRequest({required this.name, this.arguments}); - factory GetPromptRequestParams.fromJson(Map json) => - GetPromptRequestParams( + factory GetPromptRequest.fromJson(Map json) => + GetPromptRequest( name: json['name'] as String, arguments: (json['arguments'] as Map?)?.map( (k, v) => MapEntry(k, v as String), @@ -173,7 +171,7 @@ class GetPromptRequestParams { /// Request sent from client to get a specific prompt, potentially with template arguments. class JsonRpcGetPromptRequest extends JsonRpcRequest { /// The get prompt parameters. - final GetPromptRequestParams getParams; + final GetPromptRequest getParams; JsonRpcGetPromptRequest({ required super.id, @@ -189,7 +187,7 @@ class JsonRpcGetPromptRequest extends JsonRpcRequest { final meta = paramsMap['_meta'] as Map?; return JsonRpcGetPromptRequest( id: json['id'], - getParams: GetPromptRequestParams.fromJson(paramsMap), + getParams: GetPromptRequest.fromJson(paramsMap), meta: meta, ); } @@ -267,3 +265,11 @@ class JsonRpcPromptListChangedNotification extends JsonRpcNotification { ) => const JsonRpcPromptListChangedNotification(); } + +/// Deprecated alias for [ListPromptsRequest]. +@Deprecated('Use ListPromptsRequest instead') +typedef ListPromptsRequestParams = ListPromptsRequest; + +/// Deprecated alias for [GetPromptRequest]. +@Deprecated('Use GetPromptRequest instead') +typedef GetPromptRequestParams = GetPromptRequest; diff --git a/lib/src/types/resources.dart b/lib/src/types/resources.dart index 5f7c0f4..7d4753c 100644 --- a/lib/src/types/resources.dart +++ b/lib/src/types/resources.dart @@ -150,16 +150,16 @@ class ResourceTemplate { } /// Parameters for the `resources/list` request. Includes pagination. -class ListResourcesRequestParams { +class ListResourcesRequest { /// Opaque token for pagination, requesting results after this cursor. final Cursor? cursor; /// Creates list resources parameters. - const ListResourcesRequestParams({this.cursor}); + const ListResourcesRequest({this.cursor}); /// Creates from JSON. - factory ListResourcesRequestParams.fromJson(Map json) => - ListResourcesRequestParams(cursor: json['cursor'] as String?); + factory ListResourcesRequest.fromJson(Map json) => + ListResourcesRequest(cursor: json['cursor'] as String?); /// Converts to JSON. Map toJson() => {if (cursor != null) 'cursor': cursor}; @@ -168,14 +168,14 @@ class ListResourcesRequestParams { /// Request sent from client to list available resources. class JsonRpcListResourcesRequest extends JsonRpcRequest { /// The list parameters (containing cursor). - final ListResourcesRequestParams listParams; + final ListResourcesRequest listParams; /// Creates a list resources request. JsonRpcListResourcesRequest({ required super.id, - ListResourcesRequestParams? params, + ListResourcesRequest? params, super.meta, - }) : listParams = params ?? const ListResourcesRequestParams(), + }) : listParams = params ?? const ListResourcesRequest(), super(method: Method.resourcesList, params: params?.toJson()); /// Creates from JSON. @@ -184,9 +184,8 @@ class JsonRpcListResourcesRequest extends JsonRpcRequest { final meta = paramsMap?['_meta'] as Map?; return JsonRpcListResourcesRequest( id: json['id'], - params: paramsMap == null - ? null - : ListResourcesRequestParams.fromJson(paramsMap), + params: + paramsMap == null ? null : ListResourcesRequest.fromJson(paramsMap), meta: meta, ); } @@ -233,16 +232,16 @@ class ListResourcesResult implements BaseResultData { } /// Parameters for the `resources/templates/list` request. Includes pagination. -class ListResourceTemplatesRequestParams { +class ListResourceTemplatesRequest { /// Opaque token for pagination. final Cursor? cursor; - const ListResourceTemplatesRequestParams({this.cursor}); + const ListResourceTemplatesRequest({this.cursor}); - factory ListResourceTemplatesRequestParams.fromJson( + factory ListResourceTemplatesRequest.fromJson( Map json, ) => - ListResourceTemplatesRequestParams(cursor: json['cursor'] as String?); + ListResourceTemplatesRequest(cursor: json['cursor'] as String?); Map toJson() => {if (cursor != null) 'cursor': cursor}; } @@ -250,13 +249,13 @@ class ListResourceTemplatesRequestParams { /// Request sent from client to list available resource templates. class JsonRpcListResourceTemplatesRequest extends JsonRpcRequest { /// The list parameters (containing cursor). - final ListResourceTemplatesRequestParams listParams; + final ListResourceTemplatesRequest listParams; JsonRpcListResourceTemplatesRequest({ required super.id, - ListResourceTemplatesRequestParams? params, + ListResourceTemplatesRequest? params, super.meta, - }) : listParams = params ?? const ListResourceTemplatesRequestParams(), + }) : listParams = params ?? const ListResourceTemplatesRequest(), super(method: Method.resourcesTemplatesList, params: params?.toJson()); factory JsonRpcListResourceTemplatesRequest.fromJson( @@ -268,7 +267,7 @@ class JsonRpcListResourceTemplatesRequest extends JsonRpcRequest { id: json['id'], params: paramsMap == null ? null - : ListResourceTemplatesRequestParams.fromJson(paramsMap), + : ListResourceTemplatesRequest.fromJson(paramsMap), meta: meta, ); } @@ -311,14 +310,14 @@ class ListResourceTemplatesResult implements BaseResultData { } /// Parameters for the `resources/read` request. -class ReadResourceRequestParams { +class ReadResourceRequest { /// The URI of the resource to read. final String uri; - const ReadResourceRequestParams({required this.uri}); + const ReadResourceRequest({required this.uri}); - factory ReadResourceRequestParams.fromJson(Map json) => - ReadResourceRequestParams(uri: json['uri'] as String); + factory ReadResourceRequest.fromJson(Map json) => + ReadResourceRequest(uri: json['uri'] as String); Map toJson() => {'uri': uri}; } @@ -326,7 +325,7 @@ class ReadResourceRequestParams { /// Request sent from client to read a specific resource. class JsonRpcReadResourceRequest extends JsonRpcRequest { /// The read parameters (containing URI). - final ReadResourceRequestParams readParams; + final ReadResourceRequest readParams; JsonRpcReadResourceRequest({ required super.id, @@ -342,7 +341,7 @@ class JsonRpcReadResourceRequest extends JsonRpcRequest { final meta = paramsMap['_meta'] as Map?; return JsonRpcReadResourceRequest( id: json['id'], - readParams: ReadResourceRequestParams.fromJson(paramsMap), + readParams: ReadResourceRequest.fromJson(paramsMap), meta: meta, ); } @@ -387,14 +386,14 @@ class JsonRpcResourceListChangedNotification extends JsonRpcNotification { } /// Parameters for the `resources/subscribe` request. -class SubscribeRequestParams { +class SubscribeRequest { /// The URI of the resource to subscribe to for updates. final String uri; - const SubscribeRequestParams({required this.uri}); + const SubscribeRequest({required this.uri}); - factory SubscribeRequestParams.fromJson(Map json) => - SubscribeRequestParams(uri: json['uri'] as String); + factory SubscribeRequest.fromJson(Map json) => + SubscribeRequest(uri: json['uri'] as String); Map toJson() => {'uri': uri}; } @@ -402,7 +401,7 @@ class SubscribeRequestParams { /// Request sent from client to subscribe to updates for a resource. class JsonRpcSubscribeRequest extends JsonRpcRequest { /// The subscribe parameters (containing URI). - final SubscribeRequestParams subParams; + final SubscribeRequest subParams; JsonRpcSubscribeRequest({ required super.id, @@ -418,21 +417,21 @@ class JsonRpcSubscribeRequest extends JsonRpcRequest { final meta = paramsMap['_meta'] as Map?; return JsonRpcSubscribeRequest( id: json['id'], - subParams: SubscribeRequestParams.fromJson(paramsMap), + subParams: SubscribeRequest.fromJson(paramsMap), meta: meta, ); } } /// Parameters for the `resources/unsubscribe` request. -class UnsubscribeRequestParams { +class UnsubscribeRequest { /// The URI of the resource to unsubscribe from. final String uri; - const UnsubscribeRequestParams({required this.uri}); + const UnsubscribeRequest({required this.uri}); - factory UnsubscribeRequestParams.fromJson(Map json) => - UnsubscribeRequestParams(uri: json['uri'] as String); + factory UnsubscribeRequest.fromJson(Map json) => + UnsubscribeRequest(uri: json['uri'] as String); Map toJson() => {'uri': uri}; } @@ -440,7 +439,7 @@ class UnsubscribeRequestParams { /// Request sent from client to cancel a resource subscription. class JsonRpcUnsubscribeRequest extends JsonRpcRequest { /// The unsubscribe parameters (containing URI). - final UnsubscribeRequestParams unsubParams; + final UnsubscribeRequest unsubParams; JsonRpcUnsubscribeRequest({ required super.id, @@ -456,23 +455,23 @@ class JsonRpcUnsubscribeRequest extends JsonRpcRequest { final meta = paramsMap['_meta'] as Map?; return JsonRpcUnsubscribeRequest( id: json['id'], - unsubParams: UnsubscribeRequestParams.fromJson(paramsMap), + unsubParams: UnsubscribeRequest.fromJson(paramsMap), meta: meta, ); } } /// Parameters for the `notifications/resources/updated` notification. -class ResourceUpdatedNotificationParams { +class ResourceUpdatedNotification { /// The URI of the resource that has been updated (possibly a sub-resource). final String uri; - const ResourceUpdatedNotificationParams({required this.uri}); + const ResourceUpdatedNotification({required this.uri}); - factory ResourceUpdatedNotificationParams.fromJson( + factory ResourceUpdatedNotification.fromJson( Map json, ) => - ResourceUpdatedNotificationParams(uri: json['uri'] as String); + ResourceUpdatedNotification(uri: json['uri'] as String); Map toJson() => {'uri': uri}; } @@ -480,7 +479,7 @@ class ResourceUpdatedNotificationParams { /// Notification from server indicating a subscribed resource has changed. class JsonRpcResourceUpdatedNotification extends JsonRpcNotification { /// The updated parameters (containing URI). - final ResourceUpdatedNotificationParams updatedParams; + final ResourceUpdatedNotification updatedParams; JsonRpcResourceUpdatedNotification({required this.updatedParams, super.meta}) : super( @@ -499,8 +498,32 @@ class JsonRpcResourceUpdatedNotification extends JsonRpcNotification { } final meta = paramsMap['_meta'] as Map?; return JsonRpcResourceUpdatedNotification( - updatedParams: ResourceUpdatedNotificationParams.fromJson(paramsMap), + updatedParams: ResourceUpdatedNotification.fromJson(paramsMap), meta: meta, ); } } + +/// Deprecated alias for [ListResourcesRequest]. +@Deprecated('Use ListResourcesRequest instead') +typedef ListResourcesRequestParams = ListResourcesRequest; + +/// Deprecated alias for [ListResourceTemplatesRequest]. +@Deprecated('Use ListResourceTemplatesRequest instead') +typedef ListResourceTemplatesRequestParams = ListResourceTemplatesRequest; + +/// Deprecated alias for [ReadResourceRequest]. +@Deprecated('Use ReadResourceRequest instead') +typedef ReadResourceRequestParams = ReadResourceRequest; + +/// Deprecated alias for [SubscribeRequest]. +@Deprecated('Use SubscribeRequest instead') +typedef SubscribeRequestParams = SubscribeRequest; + +/// Deprecated alias for [UnsubscribeRequest]. +@Deprecated('Use UnsubscribeRequest instead') +typedef UnsubscribeRequestParams = UnsubscribeRequest; + +/// Deprecated alias for [ResourceUpdatedNotification]. +@Deprecated('Use ResourceUpdatedNotification instead') +typedef ResourceUpdatedNotificationParams = ResourceUpdatedNotification; diff --git a/lib/src/types/sampling.dart b/lib/src/types/sampling.dart index 0ac5f00..dfd1adc 100644 --- a/lib/src/types/sampling.dart +++ b/lib/src/types/sampling.dart @@ -214,7 +214,7 @@ class SamplingMessage { enum IncludeContext { none, thisServer, allServers } /// Parameters for the `sampling/createMessage` request. -class CreateMessageRequestParams { +class CreateMessageRequest { /// The sequence of messages for the LLM prompt. final List messages; @@ -245,7 +245,7 @@ class CreateMessageRequestParams { /// Optional tool choice configuration. final Map? toolChoice; - const CreateMessageRequestParams({ + const CreateMessageRequest({ required this.messages, this.systemPrompt, this.includeContext, @@ -258,9 +258,9 @@ class CreateMessageRequestParams { this.toolChoice, }); - factory CreateMessageRequestParams.fromJson(Map json) { + factory CreateMessageRequest.fromJson(Map json) { final ctxStr = json['includeContext'] as String?; - return CreateMessageRequestParams( + return CreateMessageRequest( messages: (json['messages'] as List?) ?.map((m) => SamplingMessage.fromJson(m as Map)) .toList() ?? @@ -303,7 +303,7 @@ class CreateMessageRequestParams { /// Request sent from server to client to sample an LLM. class JsonRpcCreateMessageRequest extends JsonRpcRequest { /// The create message parameters. - final CreateMessageRequestParams createParams; + final CreateMessageRequest createParams; JsonRpcCreateMessageRequest({ required super.id, @@ -322,7 +322,7 @@ class JsonRpcCreateMessageRequest extends JsonRpcRequest { final meta = paramsMap['_meta'] as Map?; return JsonRpcCreateMessageRequest( id: json['id'], - createParams: CreateMessageRequestParams.fromJson(paramsMap), + createParams: CreateMessageRequest.fromJson(paramsMap), meta: meta, ); } @@ -393,3 +393,7 @@ class CreateMessageResult implements BaseResultData { 'content': content.toJson(), }; } + +/// Deprecated alias for [CreateMessageRequest]. +@Deprecated('Use CreateMessageRequest instead') +typedef CreateMessageRequestParams = CreateMessageRequest; diff --git a/lib/src/types/tasks.dart b/lib/src/types/tasks.dart index 4ffd4c3..9d143f8 100644 --- a/lib/src/types/tasks.dart +++ b/lib/src/types/tasks.dart @@ -119,14 +119,14 @@ class Task implements BaseResultData { } /// Parameters for the `tasks/list` request. Includes pagination. -class ListTasksRequestParams { +class ListTasksRequest { /// Opaque token for pagination. final Cursor? cursor; - const ListTasksRequestParams({this.cursor}); + const ListTasksRequest({this.cursor}); - factory ListTasksRequestParams.fromJson(Map json) => - ListTasksRequestParams(cursor: json['cursor'] as String?); + factory ListTasksRequest.fromJson(Map json) => + ListTasksRequest(cursor: json['cursor'] as String?); Map toJson() => {if (cursor != null) 'cursor': cursor}; } @@ -134,13 +134,13 @@ class ListTasksRequestParams { /// Request sent from client to list available tasks. class JsonRpcListTasksRequest extends JsonRpcRequest { /// The list parameters (containing cursor). - final ListTasksRequestParams listParams; + final ListTasksRequest listParams; JsonRpcListTasksRequest({ required super.id, - ListTasksRequestParams? params, + ListTasksRequest? params, super.meta, - }) : listParams = params ?? const ListTasksRequestParams(), + }) : listParams = params ?? const ListTasksRequest(), super(method: Method.tasksList, params: params?.toJson()); factory JsonRpcListTasksRequest.fromJson(Map json) { @@ -148,8 +148,7 @@ class JsonRpcListTasksRequest extends JsonRpcRequest { final meta = paramsMap?['_meta'] as Map?; return JsonRpcListTasksRequest( id: json['id'], - params: - paramsMap == null ? null : ListTasksRequestParams.fromJson(paramsMap), + params: paramsMap == null ? null : ListTasksRequest.fromJson(paramsMap), meta: meta, ); } @@ -189,14 +188,14 @@ class ListTasksResult implements BaseResultData { } /// Parameters for the `tasks/cancel` request. -class CancelTaskRequestParams { +class CancelTaskRequest { /// The ID of the task to cancel. final String taskId; - const CancelTaskRequestParams({required this.taskId}); + const CancelTaskRequest({required this.taskId}); - factory CancelTaskRequestParams.fromJson(Map json) => - CancelTaskRequestParams(taskId: json['taskId'] as String); + factory CancelTaskRequest.fromJson(Map json) => + CancelTaskRequest(taskId: json['taskId'] as String); Map toJson() => {'taskId': taskId}; } @@ -204,7 +203,7 @@ class CancelTaskRequestParams { /// Request sent from client to cancel a task. class JsonRpcCancelTaskRequest extends JsonRpcRequest { /// The cancel parameters. - final CancelTaskRequestParams cancelParams; + final CancelTaskRequest cancelParams; JsonRpcCancelTaskRequest({ required super.id, @@ -220,21 +219,21 @@ class JsonRpcCancelTaskRequest extends JsonRpcRequest { final meta = paramsMap['_meta'] as Map?; return JsonRpcCancelTaskRequest( id: json['id'], - cancelParams: CancelTaskRequestParams.fromJson(paramsMap), + cancelParams: CancelTaskRequest.fromJson(paramsMap), meta: meta, ); } } /// Parameters for the `tasks/get` request. -class GetTaskRequestParams { +class GetTaskRequest { /// The ID of the task to get. final String taskId; - const GetTaskRequestParams({required this.taskId}); + const GetTaskRequest({required this.taskId}); - factory GetTaskRequestParams.fromJson(Map json) => - GetTaskRequestParams(taskId: json['taskId'] as String); + factory GetTaskRequest.fromJson(Map json) => + GetTaskRequest(taskId: json['taskId'] as String); Map toJson() => {'taskId': taskId}; } @@ -242,7 +241,7 @@ class GetTaskRequestParams { /// Request sent from client to get task status. class JsonRpcGetTaskRequest extends JsonRpcRequest { /// The get task parameters. - final GetTaskRequestParams getParams; + final GetTaskRequest getParams; JsonRpcGetTaskRequest({ required super.id, @@ -258,21 +257,21 @@ class JsonRpcGetTaskRequest extends JsonRpcRequest { final meta = paramsMap['_meta'] as Map?; return JsonRpcGetTaskRequest( id: json['id'], - getParams: GetTaskRequestParams.fromJson(paramsMap), + getParams: GetTaskRequest.fromJson(paramsMap), meta: meta, ); } } /// Parameters for the `tasks/result` request. -class TaskResultRequestParams { +class TaskResultRequest { /// The ID of the task to get results for. final String taskId; - const TaskResultRequestParams({required this.taskId}); + const TaskResultRequest({required this.taskId}); - factory TaskResultRequestParams.fromJson(Map json) => - TaskResultRequestParams(taskId: json['taskId'] as String); + factory TaskResultRequest.fromJson(Map json) => + TaskResultRequest(taskId: json['taskId'] as String); Map toJson() => {'taskId': taskId}; } @@ -280,7 +279,7 @@ class TaskResultRequestParams { /// Request sent from client to retrieve task results. class JsonRpcTaskResultRequest extends JsonRpcRequest { /// The task result parameters. - final TaskResultRequestParams resultParams; + final TaskResultRequest resultParams; JsonRpcTaskResultRequest({ required super.id, @@ -296,7 +295,7 @@ class JsonRpcTaskResultRequest extends JsonRpcRequest { final meta = paramsMap['_meta'] as Map?; return JsonRpcTaskResultRequest( id: json['id'], - resultParams: TaskResultRequestParams.fromJson(paramsMap), + resultParams: TaskResultRequest.fromJson(paramsMap), meta: meta, ); } @@ -369,7 +368,7 @@ class TaskErrorMessage extends TaskStreamMessage { } /// Parameters for the `notifications/tasks/status` notification. -class TaskStatusNotificationParams { +class TaskStatusNotification { /// The ID of the task. final String taskId; @@ -391,7 +390,7 @@ class TaskStatusNotificationParams { /// ISO 8601 timestamp when the task status was last updated. final String? lastUpdatedAt; - const TaskStatusNotificationParams({ + const TaskStatusNotification({ required this.taskId, required this.status, this.statusMessage, @@ -401,8 +400,8 @@ class TaskStatusNotificationParams { this.lastUpdatedAt, }); - factory TaskStatusNotificationParams.fromJson(Map json) { - return TaskStatusNotificationParams( + factory TaskStatusNotification.fromJson(Map json) { + return TaskStatusNotification( taskId: json['taskId'] as String, status: TaskStatusName.fromString(json['status'] as String), statusMessage: json['statusMessage'] as String?, @@ -427,7 +426,7 @@ class TaskStatusNotificationParams { /// Notification from receiver indicating a task status has changed. class JsonRpcTaskStatusNotification extends JsonRpcNotification { /// The task status parameters. - final TaskStatusNotificationParams statusParams; + final TaskStatusNotification statusParams; JsonRpcTaskStatusNotification({required this.statusParams, super.meta}) : super( @@ -444,8 +443,28 @@ class JsonRpcTaskStatusNotification extends JsonRpcNotification { } final meta = paramsMap['_meta'] as Map?; return JsonRpcTaskStatusNotification( - statusParams: TaskStatusNotificationParams.fromJson(paramsMap), + statusParams: TaskStatusNotification.fromJson(paramsMap), meta: meta, ); } } + +/// Deprecated alias for [ListTasksRequest]. +@Deprecated('Use ListTasksRequest instead') +typedef ListTasksRequestParams = ListTasksRequest; + +/// Deprecated alias for [CancelTaskRequest]. +@Deprecated('Use CancelTaskRequest instead') +typedef CancelTaskRequestParams = CancelTaskRequest; + +/// Deprecated alias for [GetTaskRequest]. +@Deprecated('Use GetTaskRequest instead') +typedef GetTaskRequestParams = GetTaskRequest; + +/// Deprecated alias for [TaskResultRequest]. +@Deprecated('Use TaskResultRequest instead') +typedef TaskResultRequestParams = TaskResultRequest; + +/// Deprecated alias for [TaskStatusNotification]. +@Deprecated('Use TaskStatusNotification instead') +typedef TaskStatusNotificationParams = TaskStatusNotification; diff --git a/packages/mcp_dart_cli/lib/src/doctor_command.dart b/packages/mcp_dart_cli/lib/src/doctor_command.dart index 56bc161..e5c4a47 100644 --- a/packages/mcp_dart_cli/lib/src/doctor_command.dart +++ b/packages/mcp_dart_cli/lib/src/doctor_command.dart @@ -121,7 +121,7 @@ class DoctorCommand extends Command { for (final resource in resources.resources) { try { await connection.client - .readResource(ReadResourceRequestParams(uri: resource.uri)); + .readResource(ReadResourceRequest(uri: resource.uri)); _logger .detail(' [✓] Resource "${resource.uri}" read successfully'); } catch (e) { @@ -140,7 +140,7 @@ class DoctorCommand extends Command { for (final prompt in prompts.prompts) { try { await connection.client - .getPrompt(GetPromptRequestParams(name: prompt.name)); + .getPrompt(GetPromptRequest(name: prompt.name)); _logger.detail( ' [✓] Prompt "${prompt.name}" retrieved successfully'); } catch (e) { diff --git a/packages/mcp_dart_cli/lib/src/inspect_command.dart b/packages/mcp_dart_cli/lib/src/inspect_command.dart index d440274..01c0f4e 100644 --- a/packages/mcp_dart_cli/lib/src/inspect_command.dart +++ b/packages/mcp_dart_cli/lib/src/inspect_command.dart @@ -196,7 +196,7 @@ class InspectCommand extends Command { List serverArgs, Map envMap, ) async { - final clientOptions = ClientOptions( + final clientOptions = McpClientOptions( capabilities: const ClientCapabilities( sampling: ClientCapabilitiesSampling(), ), @@ -230,7 +230,7 @@ class InspectCommand extends Command { } Future _executeTool( - Client client, String name, Map args) async { + McpClient client, String name, Map args) async { _logger.info('Executing tool: $name...'); try { final result = @@ -241,11 +241,10 @@ class InspectCommand extends Command { } } - Future _readResource(Client client, String uri) async { + Future _readResource(McpClient client, String uri) async { _logger.info('Reading resource: $uri...'); try { - final result = - await client.readResource(ReadResourceRequestParams(uri: uri)); + final result = await client.readResource(ReadResourceRequest(uri: uri)); _printer.printResourceResult(result); } catch (e) { _logger.err('Resource read failed: $e'); @@ -253,19 +252,19 @@ class InspectCommand extends Command { } Future _getPrompt( - Client client, String name, Map args) async { + McpClient client, String name, Map args) async { _logger.info('Getting prompt: $name...'); try { final stringArgs = args.map((k, v) => MapEntry(k, v.toString())); final result = await client - .getPrompt(GetPromptRequestParams(name: name, arguments: stringArgs)); + .getPrompt(GetPromptRequest(name: name, arguments: stringArgs)); _printer.printPromptResult(result); } catch (e) { _logger.err('Get prompt failed: $e'); } } - Future _listCapabilities(Client client) async { + Future _listCapabilities(McpClient client) async { try { final tools = await client.listTools(); final resources = await client.listResources(); diff --git a/packages/mcp_dart_cli/lib/src/utils/inspect_handlers.dart b/packages/mcp_dart_cli/lib/src/utils/inspect_handlers.dart index d6c9ded..80d5ebe 100644 --- a/packages/mcp_dart_cli/lib/src/utils/inspect_handlers.dart +++ b/packages/mcp_dart_cli/lib/src/utils/inspect_handlers.dart @@ -19,7 +19,7 @@ class InspectHandlers { InspectHandlers(this._logger); /// Registers all handlers with the given client. - void registerHandlers(Client client) { + void registerHandlers(McpClient client) { // Register sampling request handler client.onSamplingRequest = _handleSamplingRequest; @@ -29,7 +29,7 @@ class InspectHandlers { /// Handles sampling/createMessage requests from the server. Future _handleSamplingRequest( - CreateMessageRequestParams params) async { + CreateMessageRequest params) async { _logger.info('\n[Sampling Request]'); _logger.info('System Prompt: ${params.systemPrompt ?? "(none)"}'); _logger.info('Messages:'); diff --git a/packages/mcp_dart_cli/lib/src/utils/mcp_connection.dart b/packages/mcp_dart_cli/lib/src/utils/mcp_connection.dart index 0d4dafa..e54e2de 100644 --- a/packages/mcp_dart_cli/lib/src/utils/mcp_connection.dart +++ b/packages/mcp_dart_cli/lib/src/utils/mcp_connection.dart @@ -10,7 +10,7 @@ import '../runner_script_generator.dart'; /// A wrapper around MCP Client connection lifecycle. class McpConnection { - final Client client; + final McpClient client; final Transport transport; McpConnection._(this.client, this.transport, Logger logger); @@ -19,7 +19,7 @@ class McpConnection { /// Generates the runner script if needed. static Future connectToLocalProject( Logger logger, { - ClientOptions? options, + McpClientOptions? options, }) async { final pubspecFile = File('pubspec.yaml'); if (!pubspecFile.existsSync()) { @@ -65,7 +65,7 @@ class McpConnection { String command, List args, { Map? env, - ClientOptions? options, + McpClientOptions? options, }) async { logger.detail('Connecting to server: $command ${args.join(' ')}'); @@ -77,7 +77,7 @@ class McpConnection { ); final transport = StdioClientTransport(serverParams); - final client = Client( + final client = McpClient( Implementation(name: 'mcp_dart_cli', version: '1.0.0'), options: options, ); @@ -96,12 +96,12 @@ class McpConnection { static Future connectToUrl( Logger logger, Uri url, { - ClientOptions? options, + McpClientOptions? options, }) async { logger.detail('Connecting to server: $url'); final transport = StreamableHttpClientTransport(url); - final client = Client( + final client = McpClient( Implementation(name: 'mcp_dart_cli', version: '1.0.0'), options: options, ); diff --git a/pubspec.yaml b/pubspec.yaml index d2fd85a..e758571 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: mcp_dart description: Dart Implementation of Model Context Protocol (MCP) SDK. -version: 1.1.2 +version: 1.2.0 repository: https://github.com/leehack/mcp_dart environment: diff --git a/test/client/client_test.dart b/test/client/client_test.dart index 60119b7..4d67cb8 100644 --- a/test/client/client_test.dart +++ b/test/client/client_test.dart @@ -59,7 +59,7 @@ void main() { const ClientCapabilities(experimental: {'feature1': true}); client = Client( clientInfo, - options: ClientOptions(capabilities: initialCapabilities), + options: McpClientOptions(capabilities: initialCapabilities), ); final additionalCapabilities = const ClientCapabilities( @@ -199,7 +199,7 @@ void main() { test('assertNotificationCapability checks client capabilities', () { final capableClient = Client( clientInfo, - options: const ClientOptions( + options: const McpClientOptions( capabilities: ClientCapabilities( roots: ClientCapabilitiesRoots(listChanged: true), ), @@ -224,7 +224,7 @@ void main() { test('assertRequestHandlerCapability checks client capabilities', () { final capableClient = Client( clientInfo, - options: const ClientOptions( + options: const McpClientOptions( capabilities: ClientCapabilities( sampling: ClientCapabilitiesSampling(), roots: ClientCapabilitiesRoots(), @@ -280,7 +280,7 @@ void main() { transport.clearSentMessages(); - final params = const CompleteRequestParams( + final params = const CompleteRequest( ref: PromptReference(name: 'test-prompt'), argument: ArgumentCompletionInfo(name: 'arg1', value: 'val'), ); @@ -325,7 +325,7 @@ void main() { transport.clearSentMessages(); - final params = const GetPromptRequestParams(name: 'test-prompt'); + final params = const GetPromptRequest(name: 'test-prompt'); await client.getPrompt(params); // Verify a getPrompt request was sent @@ -407,7 +407,7 @@ void main() { transport.clearSentMessages(); - final params = const ReadResourceRequestParams(uri: 'test://resource'); + final params = const ReadResourceRequest(uri: 'test://resource'); await client.readResource(params); // Verify a readResource request was sent @@ -428,7 +428,7 @@ void main() { transport.clearSentMessages(); - final params = const SubscribeRequestParams(uri: 'test://resource'); + final params = const SubscribeRequest(uri: 'test://resource'); await client.subscribeResource(params); // Verify a subscribeResource request was sent @@ -449,7 +449,7 @@ void main() { transport.clearSentMessages(); - final params = const UnsubscribeRequestParams(uri: 'test://resource'); + final params = const UnsubscribeRequest(uri: 'test://resource'); await client.unsubscribeResource(params); // Verify an unsubscribeResource request was sent @@ -773,7 +773,7 @@ void _addCriticalPathTests() { // Create client WITH elicitation capability client = Client( const Implementation(name: 'TestClient', version: '1.0.0'), - options: const ClientOptions( + options: const McpClientOptions( capabilities: ClientCapabilities( elicitation: ClientElicitation.formOnly(), ), @@ -796,7 +796,7 @@ void _addCriticalPathTests() { // Simulate server sending elicitation request final elicitRequest = JsonRpcElicitRequest( id: 100, - elicitParams: ElicitRequestParams( + elicitParams: ElicitRequest( message: 'Please provide input', requestedSchema: JsonSchema.string(), ), diff --git a/test/interop/dart_client_with_ts_server_features_test.dart b/test/interop/dart_client_with_ts_server_features_test.dart index 7223906..66686d9 100644 --- a/test/interop/dart_client_with_ts_server_features_test.dart +++ b/test/interop/dart_client_with_ts_server_features_test.dart @@ -29,7 +29,7 @@ void main() { } group('Stdio Transport', () { - late Client client; + late McpClient client; late StdioClientTransport transport; setUp(() async { @@ -43,9 +43,9 @@ void main() { ); // 2. Create the Client instance with capabilities for roots, sampling, elicitation - client = Client( + client = McpClient( const Implementation(name: 'dart-test-features', version: '1.0.0'), - options: const ClientOptions( + options: const McpClientOptions( capabilities: ClientCapabilities( roots: ClientCapabilitiesRoots(listChanged: true), sampling: ClientCapabilitiesSampling(), @@ -158,7 +158,7 @@ void main() { test('completion - client gets argument completions', () async { final result = await client.complete( - const CompleteRequestParams( + const CompleteRequest( ref: PromptReference(name: 'greeting'), argument: ArgumentCompletionInfo(name: 'language', value: 'En'), ), diff --git a/test/interop/dart_client_with_ts_server_task_test.dart b/test/interop/dart_client_with_ts_server_task_test.dart index 8767cdb..80d152c 100644 --- a/test/interop/dart_client_with_ts_server_task_test.dart +++ b/test/interop/dart_client_with_ts_server_task_test.dart @@ -22,7 +22,7 @@ void main() { } late StdioClientTransport transport; - late Client client; + late McpClient client; late TaskClient taskClient; setUp(() async { @@ -36,9 +36,9 @@ void main() { ); // 2. Create the Client instance - client = Client( + client = McpClient( const Implementation(name: 'dart-task-test', version: '1.0'), - options: const ClientOptions( + options: const McpClientOptions( capabilities: ClientCapabilities(), ), ); diff --git a/test/interop/dart_client_with_ts_server_test.dart b/test/interop/dart_client_with_ts_server_test.dart index 93666ae..c43a447 100644 --- a/test/interop/dart_client_with_ts_server_test.dart +++ b/test/interop/dart_client_with_ts_server_test.dart @@ -25,7 +25,7 @@ void main() { group('Stdio', () { late StdioClientTransport transport; - late Client client; + late McpClient client; setUp(() async { // 1. Create the StdioClientTransport with server parameters @@ -38,9 +38,9 @@ void main() { ); // 2. Create the Client instance, which will use this transport - client = Client( + client = McpClient( const Implementation(name: 'dart-test', version: '1.0'), - options: const ClientOptions( + options: const McpClientOptions( capabilities: ClientCapabilities(), ), ); @@ -74,7 +74,7 @@ void main() { test('resources', () async { final result = await client.readResource( - ReadResourceRequestParams( + ReadResourceRequest( uri: Uri.parse('resource://test').toString(), ), ); @@ -86,7 +86,7 @@ void main() { test('prompts', () async { final result = await client.getPrompt( - const GetPromptRequestParams(name: 'test_prompt', arguments: {}), + const GetPromptRequest(name: 'test_prompt', arguments: {}), ); expect(result.messages.first.content, isA()); expect( @@ -98,7 +98,7 @@ void main() { group('HTTP', () { late StreamableHttpClientTransport transport; - late Client client; + late McpClient client; late io.Process serverProcess; final port = 3001; @@ -119,9 +119,9 @@ void main() { ); // 3. Create the Client instance - client = Client( + client = McpClient( const Implementation(name: 'dart-test', version: '1.0'), - options: const ClientOptions( + options: const McpClientOptions( capabilities: ClientCapabilities(), ), ); diff --git a/test/interop/test_dart_server.dart b/test/interop/test_dart_server.dart index d53d151..171ece8 100644 --- a/test/interop/test_dart_server.dart +++ b/test/interop/test_dart_server.dart @@ -158,7 +158,7 @@ McpServer createServer() { try { final message = args['message'] as String; final result = await server.server.elicitInput( - ElicitRequestParams.form( + ElicitRequest.form( message: message, requestedSchema: JsonSchema.object( properties: { @@ -196,7 +196,7 @@ McpServer createServer() { try { final prompt = args['prompt'] as String; final result = await server.server.createMessage( - CreateMessageRequestParams( + CreateMessageRequest( messages: [ SamplingMessage( role: SamplingMessageRole.user, diff --git a/test/server/server_test.dart b/test/server/server_test.dart index 71eb1b2..6441c32 100644 --- a/test/server/server_test.dart +++ b/test/server/server_test.dart @@ -130,7 +130,7 @@ void main() { }, tools: ServerCapabilitiesTools(), ); - final options = ServerOptions( + final options = McpServerOptions( capabilities: capabilities, instructions: 'Test instructions', ); @@ -182,7 +182,7 @@ void main() { sampling: ClientCapabilitiesSampling(), ); - final initParams = InitializeRequestParams( + final initParams = InitializeRequest( protocolVersion: latestProtocolVersion, capabilities: clientCapabilities, clientInfo: const Implementation(name: 'TestClient', version: '1.0.0'), @@ -243,7 +243,7 @@ void main() { final clientCapabilities = const ClientCapabilities(); - final initParams = InitializeRequestParams( + final initParams = InitializeRequest( protocolVersion: "999.999", // Unsupported version capabilities: clientCapabilities, clientInfo: const Implementation(name: 'TestClient', version: '1.0.0'), @@ -295,7 +295,7 @@ void main() { await _initializeClient(transport, server, withSampling: true); // Create message params - final createParams = const CreateMessageRequestParams( + final createParams = const CreateMessageRequest( messages: [ SamplingMessage( role: SamplingMessageRole.user, @@ -383,7 +383,7 @@ void main() { resources: ServerCapabilitiesResources(listChanged: true, subscribe: true), ); - final options = ServerOptions(capabilities: capabilities); + final options = McpServerOptions(capabilities: capabilities); final resourceServer = Server(serverInfo, options: options); await resourceServer.connect(transport); @@ -392,7 +392,7 @@ void main() { await resourceServer.sendResourceListChanged(); // Send resource updated notification - final resourceParams = const ResourceUpdatedNotificationParams( + final resourceParams = const ResourceUpdatedNotification( uri: 'test-resource', ); await resourceServer.sendResourceUpdated(resourceParams); @@ -419,7 +419,7 @@ void main() { test('Server cannot send notifications when capability is not registered', () { // Create server with NO capabilities - final options = const ServerOptions(); + final options = const McpServerOptions(); final plainServer = Server(serverInfo, options: options); expect( @@ -427,7 +427,7 @@ void main() { throwsA(isA()), ); - final resourceParams = const ResourceUpdatedNotificationParams( + final resourceParams = const ResourceUpdatedNotification( uri: 'test-resource', ); expect( @@ -444,7 +444,7 @@ void main() { ); // Logging notification requires logging capability - final logParams = const LoggingMessageNotificationParams( + final logParams = const LoggingMessageNotification( level: LoggingLevel.info, data: 'Test log', ); @@ -459,7 +459,7 @@ void main() { final capabilities = const ServerCapabilities( tools: ServerCapabilitiesTools(), ); - final options = ServerOptions(capabilities: capabilities); + final options = McpServerOptions(capabilities: capabilities); final server = Server(serverInfo, options: options); // These should not throw - tools capability is registered @@ -505,7 +505,7 @@ Future _initializeClient( elicitation: withElicitation ? const ClientElicitation.formOnly() : null, ); - final initParams = InitializeRequestParams( + final initParams = InitializeRequest( protocolVersion: latestProtocolVersion, capabilities: clientCapabilities, clientInfo: const Implementation(name: 'TestClient', version: '1.0.0'), @@ -589,7 +589,7 @@ void _addCriticalPathTests() { () async { server = Server( const Implementation(name: 'TestServer', version: '1.0.0'), - options: const ServerOptions( + options: const McpServerOptions( capabilities: ServerCapabilities( resources: ServerCapabilitiesResources(), // No subscribe ), @@ -613,7 +613,7 @@ void _addCriticalPathTests() { () { server = Server( const Implementation(name: 'TestServer', version: '1.0.0'), - options: const ServerOptions( + options: const McpServerOptions( capabilities: ServerCapabilities( resources: ServerCapabilitiesResources(subscribe: true), ), @@ -631,7 +631,7 @@ void _addCriticalPathTests() { () { server = Server( const Implementation(name: 'TestServer', version: '1.0.0'), - options: const ServerOptions( + options: const McpServerOptions( capabilities: ServerCapabilities( resources: ServerCapabilitiesResources(), // No listChanged ), @@ -655,7 +655,7 @@ void _addCriticalPathTests() { test('notifications/tools/list_changed requires tools.listChanged', () { server = Server( const Implementation(name: 'TestServer', version: '1.0.0'), - options: const ServerOptions( + options: const McpServerOptions( capabilities: ServerCapabilities( tools: ServerCapabilitiesTools(), // No listChanged ), @@ -678,7 +678,7 @@ void _addCriticalPathTests() { test('notifications/prompts/list_changed requires prompts.listChanged', () { server = Server( const Implementation(name: 'TestServer', version: '1.0.0'), - options: const ServerOptions( + options: const McpServerOptions( capabilities: ServerCapabilities( prompts: ServerCapabilitiesPrompts(), // No listChanged ), From cc638999c23bb0f1bae0aae1c36c98769dd24e15 Mon Sep 17 00:00:00 2001 From: Jhin Lee Date: Tue, 23 Dec 2025 10:44:37 -0500 Subject: [PATCH 2/3] Don't update cli yet --- packages/mcp_dart_cli/lib/src/doctor_command.dart | 4 ++-- .../mcp_dart_cli/lib/src/inspect_command.dart | 15 ++++++++------- .../lib/src/utils/inspect_handlers.dart | 4 ++-- .../lib/src/utils/mcp_connection.dart | 12 ++++++------ 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/packages/mcp_dart_cli/lib/src/doctor_command.dart b/packages/mcp_dart_cli/lib/src/doctor_command.dart index e5c4a47..56bc161 100644 --- a/packages/mcp_dart_cli/lib/src/doctor_command.dart +++ b/packages/mcp_dart_cli/lib/src/doctor_command.dart @@ -121,7 +121,7 @@ class DoctorCommand extends Command { for (final resource in resources.resources) { try { await connection.client - .readResource(ReadResourceRequest(uri: resource.uri)); + .readResource(ReadResourceRequestParams(uri: resource.uri)); _logger .detail(' [✓] Resource "${resource.uri}" read successfully'); } catch (e) { @@ -140,7 +140,7 @@ class DoctorCommand extends Command { for (final prompt in prompts.prompts) { try { await connection.client - .getPrompt(GetPromptRequest(name: prompt.name)); + .getPrompt(GetPromptRequestParams(name: prompt.name)); _logger.detail( ' [✓] Prompt "${prompt.name}" retrieved successfully'); } catch (e) { diff --git a/packages/mcp_dart_cli/lib/src/inspect_command.dart b/packages/mcp_dart_cli/lib/src/inspect_command.dart index 01c0f4e..d440274 100644 --- a/packages/mcp_dart_cli/lib/src/inspect_command.dart +++ b/packages/mcp_dart_cli/lib/src/inspect_command.dart @@ -196,7 +196,7 @@ class InspectCommand extends Command { List serverArgs, Map envMap, ) async { - final clientOptions = McpClientOptions( + final clientOptions = ClientOptions( capabilities: const ClientCapabilities( sampling: ClientCapabilitiesSampling(), ), @@ -230,7 +230,7 @@ class InspectCommand extends Command { } Future _executeTool( - McpClient client, String name, Map args) async { + Client client, String name, Map args) async { _logger.info('Executing tool: $name...'); try { final result = @@ -241,10 +241,11 @@ class InspectCommand extends Command { } } - Future _readResource(McpClient client, String uri) async { + Future _readResource(Client client, String uri) async { _logger.info('Reading resource: $uri...'); try { - final result = await client.readResource(ReadResourceRequest(uri: uri)); + final result = + await client.readResource(ReadResourceRequestParams(uri: uri)); _printer.printResourceResult(result); } catch (e) { _logger.err('Resource read failed: $e'); @@ -252,19 +253,19 @@ class InspectCommand extends Command { } Future _getPrompt( - McpClient client, String name, Map args) async { + Client client, String name, Map args) async { _logger.info('Getting prompt: $name...'); try { final stringArgs = args.map((k, v) => MapEntry(k, v.toString())); final result = await client - .getPrompt(GetPromptRequest(name: name, arguments: stringArgs)); + .getPrompt(GetPromptRequestParams(name: name, arguments: stringArgs)); _printer.printPromptResult(result); } catch (e) { _logger.err('Get prompt failed: $e'); } } - Future _listCapabilities(McpClient client) async { + Future _listCapabilities(Client client) async { try { final tools = await client.listTools(); final resources = await client.listResources(); diff --git a/packages/mcp_dart_cli/lib/src/utils/inspect_handlers.dart b/packages/mcp_dart_cli/lib/src/utils/inspect_handlers.dart index 80d5ebe..d6c9ded 100644 --- a/packages/mcp_dart_cli/lib/src/utils/inspect_handlers.dart +++ b/packages/mcp_dart_cli/lib/src/utils/inspect_handlers.dart @@ -19,7 +19,7 @@ class InspectHandlers { InspectHandlers(this._logger); /// Registers all handlers with the given client. - void registerHandlers(McpClient client) { + void registerHandlers(Client client) { // Register sampling request handler client.onSamplingRequest = _handleSamplingRequest; @@ -29,7 +29,7 @@ class InspectHandlers { /// Handles sampling/createMessage requests from the server. Future _handleSamplingRequest( - CreateMessageRequest params) async { + CreateMessageRequestParams params) async { _logger.info('\n[Sampling Request]'); _logger.info('System Prompt: ${params.systemPrompt ?? "(none)"}'); _logger.info('Messages:'); diff --git a/packages/mcp_dart_cli/lib/src/utils/mcp_connection.dart b/packages/mcp_dart_cli/lib/src/utils/mcp_connection.dart index e54e2de..0d4dafa 100644 --- a/packages/mcp_dart_cli/lib/src/utils/mcp_connection.dart +++ b/packages/mcp_dart_cli/lib/src/utils/mcp_connection.dart @@ -10,7 +10,7 @@ import '../runner_script_generator.dart'; /// A wrapper around MCP Client connection lifecycle. class McpConnection { - final McpClient client; + final Client client; final Transport transport; McpConnection._(this.client, this.transport, Logger logger); @@ -19,7 +19,7 @@ class McpConnection { /// Generates the runner script if needed. static Future connectToLocalProject( Logger logger, { - McpClientOptions? options, + ClientOptions? options, }) async { final pubspecFile = File('pubspec.yaml'); if (!pubspecFile.existsSync()) { @@ -65,7 +65,7 @@ class McpConnection { String command, List args, { Map? env, - McpClientOptions? options, + ClientOptions? options, }) async { logger.detail('Connecting to server: $command ${args.join(' ')}'); @@ -77,7 +77,7 @@ class McpConnection { ); final transport = StdioClientTransport(serverParams); - final client = McpClient( + final client = Client( Implementation(name: 'mcp_dart_cli', version: '1.0.0'), options: options, ); @@ -96,12 +96,12 @@ class McpConnection { static Future connectToUrl( Logger logger, Uri url, { - McpClientOptions? options, + ClientOptions? options, }) async { logger.detail('Connecting to server: $url'); final transport = StreamableHttpClientTransport(url); - final client = McpClient( + final client = Client( Implementation(name: 'mcp_dart_cli', version: '1.0.0'), options: options, ); From 9a92e565d06bc5113ce21547c89009aab8695052 Mon Sep 17 00:00:00 2001 From: Jhin Lee Date: Tue, 23 Dec 2025 12:47:05 -0500 Subject: [PATCH 3/3] more refactorings --- CHANGELOG.md | 5 +- doc/client-guide.md | 52 +- doc/examples.md | 4 +- doc/getting-started.md | 12 +- doc/quick-reference.md | 10 +- doc/server-guide.md | 8 +- doc/transports.md | 14 +- example/example.md | 4 +- example/simple_task_interactive_server.dart | 2 +- lib/fix_data.yaml | 34 ++ lib/src/server/tasks/store.dart | 2 +- lib/src/shared/protocol.dart | 6 +- lib/src/shared/task_interfaces.dart | 4 +- lib/src/types/json_rpc.dart | 4 +- lib/src/types/misc.dart | 32 +- lib/src/types/tasks.dart | 12 +- llms.txt | 22 +- test/interop/test_dart_server.dart | 2 +- test/shared/protocol_coverage_test.dart | 415 +++++++++++++ test/types/resources_test.dart | 643 ++++++++++++++++++++ 20 files changed, 1197 insertions(+), 90 deletions(-) create mode 100644 test/shared/protocol_coverage_test.dart create mode 100644 test/types/resources_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index ed00d2c..4724cb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,10 @@ - `GetPromptRequestParams` -> `GetPromptRequest` - `ElicitRequestParams` -> `ElicitRequest` - `CreateMessageRequestParams` -> `CreateMessageRequest` - - `LoggingMessageNotificationParams` -> `LoggingMessageNotification` (typedef deprecated) + - `LoggingMessageNotificationParams` -> `LoggingMessageNotification` + - `CancelledNotificationParams` -> `CancelledNotification` + - `ProgressNotificationParams` -> `ProgressNotification` + - `TaskCreationParams` -> `TaskCreation` ## 1.1.2 diff --git a/doc/client-guide.md b/doc/client-guide.md index d22e001..65e4b9e 100644 --- a/doc/client-guide.md +++ b/doc/client-guide.md @@ -23,7 +23,7 @@ Complete guide to building MCP clients with the Dart SDK. import 'package:mcp_dart/mcp_dart.dart'; void main() async { - final client = Client( + final client = McpClient( Implementation( name: 'my-client', version: '1.0.0', @@ -49,7 +49,7 @@ void main() async { ### Client Configuration Options ```dart -final client = Client( +final client = McpClient( Implementation( name: 'my-client', version: '1.0.0', @@ -65,7 +65,7 @@ final client = Client( Declare what your client supports: ```dart -final client = Client( +final client = McpClient( Implementation( name: 'my-client', version: '1.0.0', @@ -202,7 +202,7 @@ for (final resource in response.resources) { ```dart // Read specific resource final result = await client.readResource( - ReadResourceRequestParams( + ReadResourceRequest( uri: 'file:///docs/readme.md', ), ); @@ -224,7 +224,7 @@ for (final content in result.contents) { ```dart // Subscribe to changes await client.subscribeResource( - SubscribeRequestParams( + SubscribeRequest( uri: 'file:///data/metrics.json', ), ); @@ -235,7 +235,7 @@ client.onResourceUpdated = (notification) { // Re-read the resource client.readResource( - ReadResourceRequestParams( + ReadResourceRequest( uri: notification.uri, ), ).then((result) { @@ -245,7 +245,7 @@ client.onResourceUpdated = (notification) { // Unsubscribe when done await client.unsubscribeResource( - UnsubscribeRequestParams( + UnsubscribeRequest( uri: 'file:///data/metrics.json', ), ); @@ -266,7 +266,7 @@ for (final resource in response.resources) { // Read from template final result = await client.readResource( - ReadResourceRequestParams( + ReadResourceRequest( uri: 'users://alice/profile', // Expands template ), ); @@ -299,7 +299,7 @@ for (final prompt in response.prompts) { ```dart // Get prompt without arguments final result = await client.getPrompt( - GetPromptRequestParams( + GetPromptRequest( name: 'code-review', ), ); @@ -315,7 +315,7 @@ for (final message in result.messages) { ```dart // Get prompt with arguments final result = await client.getPrompt( - GetPromptRequestParams( + GetPromptRequest( name: 'translate', arguments: { 'target_language': 'Spanish', @@ -334,7 +334,7 @@ for (final message in result.messages) { ```dart final result = await client.getPrompt( - GetPromptRequestParams( + GetPromptRequest( name: 'analyze-file', arguments: {'file_uri': 'file:///data.json'}, ), @@ -349,7 +349,7 @@ for (final message in result.messages) { // Resolve the embedded resource final resourceUri = content.resource.uri; final resourceData = await client.readResource( - ReadResourceRequestParams(uri: resourceUri), + ReadResourceRequest(uri: resourceUri), ); print('Embedded: ${resourceData.contents.first.text}'); } @@ -361,7 +361,7 @@ for (final message in result.messages) { Handle LLM sampling requests from the server (server asking client to use an LLM): ```dart -final client = Client( +final client = McpClient( Implementation( name: 'my-client', version: '1.0.0', @@ -412,7 +412,7 @@ Get argument completion suggestions: ```dart // Complete resource template variable final result = await client.complete( - CompleteRequestParams( + CompleteRequest( ref: CompletionReference( type: CompletionReferenceType.resourceRef, uri: 'users://{userId}/profile', @@ -437,7 +437,7 @@ if (result.completion.hasMore == true) { ```dart // Complete prompt argument final result = await client.complete( - CompleteRequestParams( + CompleteRequest( ref: CompletionReference( type: CompletionReferenceType.promptRef, name: 'translate', @@ -460,7 +460,7 @@ for (final lang in result.completion.values) { Roots are filesystem locations the client exposes to the server: ```dart -final client = Client( +final client = McpClient( Implementation( name: 'my-client', version: '1.0.0', @@ -499,7 +499,7 @@ await client.sendRootsListChanged(); ```dart // Set server's logging level await client.setLoggingLevel( - SetLevelRequestParams( + SetLevelRequest( level: LoggingLevel.debug, ), ); @@ -538,7 +538,7 @@ await client.close(); ### Reconnection Logic ```dart -Future connectWithRetry(Client client, Transport transport) async { +Future connectWithRetry(McpClient client, Transport transport) async { var retries = 0; const maxRetries = 3; @@ -608,7 +608,7 @@ print(' ${prompts.prompts.length} prompts'); ```dart Future callToolSafely( - Client client, + McpClient client, String toolName, Map args, ) async { @@ -645,7 +645,7 @@ Future callToolSafely( ```dart // Set up all notification handlers -void setupNotifications(Client client) { +void setupNotifications(McpClient client) { // Resource updates client.onResourceUpdated = (notification) { print('Resource updated: ${notification.uri}'); @@ -704,7 +704,7 @@ try { ```dart Future useClient() async { - final client = Client( + final client = McpClient( Implementation(name: 'client', version: '1.0.0'), ); @@ -751,14 +751,14 @@ processResult(result); ```dart // ✅ Good if (client.serverCapabilities?.resources?.subscribe == true) { - await client.subscribeResource(SubscribeRequestParams(uri: uri)); + await client.subscribeResource(SubscribeRequest(uri: uri)); } else { // Fallback: poll for changes pollResourceForChanges(uri); } // ❌ Bad - assume capability exists -await client.subscribeResource(SubscribeRequestParams(uri: uri)); +await client.subscribeResource(SubscribeRequest(uri: uri)); ``` ### 4. Use Progress for Long Operations @@ -798,14 +798,14 @@ final subscriptions = {}; Future subscribe(String uri) async { if (!subscriptions.contains(uri)) { - await client.subscribeResource(SubscribeRequestParams(uri: uri)); + await client.subscribeResource(SubscribeRequest(uri: uri)); subscriptions.add(uri); } } Future unsubscribe(String uri) async { if (subscriptions.contains(uri)) { - await client.unsubscribeResource(UnsubscribeRequestParams(uri: uri)); + await client.unsubscribeResource(UnsubscribeRequest(uri: uri)); subscriptions.remove(uri); } } @@ -814,7 +814,7 @@ Future unsubscribe(String uri) async { Future cleanUp() async { await Future.wait( subscriptions.map((uri) => - client.unsubscribeResource(UnsubscribeRequestParams(uri: uri)), + client.unsubscribeResource(UnsubscribeRequest(uri: uri)), ), ); subscriptions.clear(); diff --git a/doc/examples.md b/doc/examples.md index 65cbb6b..61c882e 100644 --- a/doc/examples.md +++ b/doc/examples.md @@ -439,7 +439,7 @@ final response = await makeAuthenticatedRequest( ```dart // Argument completion final result = await client.complete( - CompleteRequestParams( + CompleteRequest( ref: CompletionReference( type: CompletionReferenceType.resourceRef, uri: 'users://{userId}/profile', @@ -497,7 +497,7 @@ test('tool execution', () async { )); // Create client - final client = Client( + final client = McpClient( Implementation(name: 'test', version: '1.0.0'), ); diff --git a/doc/getting-started.md b/doc/getting-started.md index 80f1dc8..1f24318 100644 --- a/doc/getting-started.md +++ b/doc/getting-started.md @@ -78,7 +78,7 @@ server.registerResource( // Client reads the resource await client.readResource( - ReadResourceRequestParams( + ReadResourceRequest( uri: 'file:///docs/readme.md', ), ); @@ -114,7 +114,7 @@ server.registerPrompt( // Client gets the prompt await client.getPrompt( - GetPromptRequestParams( + GetPromptRequest( name: 'code-review', arguments: {'language': 'Dart'}, ), @@ -143,7 +143,7 @@ void main() async { name: 'my-first-server', version: '1.0.0', ), - options: ServerOptions( + options: McpServerOptions( capabilities: ServerCapabilities( tools: ServerCapabilitiesTools(), resources: ServerCapabilitiesResources(), @@ -209,7 +209,7 @@ import 'package:mcp_dart/mcp_dart.dart'; void main() async { // Create the client - final client = Client( + final client = McpClient( Implementation( name: 'my-first-client', version: '1.0.0', @@ -246,7 +246,7 @@ void main() async { // Read a resource print('\nReading server info resource...'); final resource = await client.readResource( - ReadResourceRequestParams( + ReadResourceRequest( uri: 'info://server', ), ); @@ -448,7 +448,7 @@ await client.callTool( Increase timeout for slow operations: ```dart -final client = Client( +final client = McpClient( Implementation(name: 'client', version: '1.0.0'), requestTimeout: Duration(seconds: 30), // Default is 10 seconds ); diff --git a/doc/quick-reference.md b/doc/quick-reference.md index 152d9a1..6345cd0 100644 --- a/doc/quick-reference.md +++ b/doc/quick-reference.md @@ -30,7 +30,7 @@ final server = McpServer( name: 'server-name', version: '1.0.0', ), - options: ServerOptions( + options: McpServerOptions( capabilities: ServerCapabilities( tools: ServerCapabilitiesTools(), ), @@ -175,7 +175,7 @@ await server.connect(transport); ### Create Client ```dart -final client = Client( +final client = McpClient( Implementation( name: 'client-name', version: '1.0.0', @@ -569,7 +569,7 @@ await server.sendPromptListChanged(); final server = McpServer( Implementation(name: 'server', version: '1.0.0'), // Capabilities auto-detected from registrations - options: ServerOptions( + options: McpServerOptions( capabilities: ServerCapabilities( tools: ServerCapabilitiesTools(), ), @@ -580,7 +580,7 @@ final server = McpServer( ### Client Capabilities ```dart -final client = Client( +final client = McpClient( Implementation(name: 'client', version: '1.0.0'), capabilities: ClientCapabilities( sampling: ClientCapabilitiesSampling(tools: true), @@ -720,7 +720,7 @@ test('example', () async { outputSink: s2c.sink, )); - final client = Client(...); + final client = McpClient(...); await client.connect(IOStreamTransport( inputStream: s2c.stream, outputSink: c2s.sink, diff --git a/doc/server-guide.md b/doc/server-guide.md index bac1837..4accf4a 100644 --- a/doc/server-guide.md +++ b/doc/server-guide.md @@ -27,7 +27,7 @@ void main() async { name: 'my-server', version: '1.0.0', ), - options: ServerOptions( + options: McpServerOptions( capabilities: ServerCapabilities( tools: ServerCapabilitiesTools(), resources: ServerCapabilitiesResources(), @@ -52,7 +52,7 @@ final server = McpServer( name: 'my-server', version: '1.0.0', ), - options: ServerOptions( + options: McpServerOptions( capabilities: ServerCapabilities( tools: ServerCapabilitiesTools(), resources: ServerCapabilitiesResources(), @@ -734,7 +734,7 @@ void main() async { name: 'my-server', version: '1.0.0', ), - options: ServerOptions( + options: McpServerOptions( capabilities: ServerCapabilities( tools: ServerCapabilitiesTools(), resources: ServerCapabilitiesResources(), @@ -787,7 +787,7 @@ void main() async { name: 'multi-transport-server', version: '1.0.0', ), - options: ServerOptions( + options: McpServerOptions( capabilities: ServerCapabilities( tools: ServerCapabilitiesTools(), resources: ServerCapabilitiesResources(), diff --git a/doc/transports.md b/doc/transports.md index 6f0abd9..fde5dbf 100644 --- a/doc/transports.md +++ b/doc/transports.md @@ -36,7 +36,7 @@ void main() async { name: 'stdio-server', version: '1.0.0', ), - options: ServerOptions( + options: McpServerOptions( capabilities: ServerCapabilities( tools: ServerCapabilitiesTools(), ), @@ -59,7 +59,7 @@ void main() async { #### Connect to Dart Server ```dart -final client = Client( +final client = McpClient( Implementation(name: 'client', version: '1.0.0'), ); @@ -130,7 +130,7 @@ final transport = StdioClientTransport( ```dart // ✅ Always close client to terminate server process try { - final client = Client(...); + final client = McpClient(...); final transport = StdioClientTransport(StdioServerParameters(...)); await client.connect(transport); @@ -231,7 +231,7 @@ void main() async { name: 'http-server', version: '1.0.0', ), - options: ServerOptions( + options: McpServerOptions( capabilities: ServerCapabilities( tools: ServerCapabilitiesTools(), ), @@ -262,7 +262,7 @@ void main() async { ### Client Setup ```dart -final client = Client( +final client = McpClient( Implementation(name: 'client', version: '1.0.0'), ); @@ -436,7 +436,7 @@ void main() async { await server.connect(serverTransport); // Client setup - final client = Client( + final client = McpClient( Implementation(name: 'client', version: '1.0.0'), ); @@ -501,7 +501,7 @@ void main() { )); // Create client - final client = Client( + final client = McpClient( Implementation(name: 'test-client', version: '1.0.0'), ); diff --git a/example/example.md b/example/example.md index 8d8bea4..f99cc94 100644 --- a/example/example.md +++ b/example/example.md @@ -8,7 +8,7 @@ import 'package:mcp_dart/mcp_dart.dart'; void main() async { McpServer server = McpServer( Implementation(name: "example-server", version: "1.0.0"), - options: ServerOptions( + options: McpServerOptions( capabilities: ServerCapabilities( resources: ServerCapabilitiesResources(), tools: ServerCapabilitiesTools(), @@ -62,7 +62,7 @@ import 'package:mcp_dart/mcp_dart.dart'; void main() async { final server = McpServer( Implementation(name: "example-http-server", version: "1.0.0"), - options: ServerOptions( + options: McpServerOptions( capabilities: ServerCapabilities( tools: ServerCapabilitiesTools(), ), diff --git a/example/simple_task_interactive_server.dart b/example/simple_task_interactive_server.dart index b018458..155b091 100644 --- a/example/simple_task_interactive_server.dart +++ b/example/simple_task_interactive_server.dart @@ -331,7 +331,7 @@ class SimpleToolTaskHandler implements ToolTaskHandler { RequestHandlerExtra? extra, ) async { final task = await context.store.createTask( - const TaskCreationParams(), // ttl + const TaskCreation(), // ttl extra?.requestId ?? -1, {'name': toolName, 'input': args ?? {}}, extra?.sessionId, diff --git a/lib/fix_data.yaml b/lib/fix_data.yaml index 829f44f..d435c67 100644 --- a/lib/fix_data.yaml +++ b/lib/fix_data.yaml @@ -297,6 +297,40 @@ transforms: - kind: 'rename' newName: 'TaskStatusNotification' + - title: "Rename to 'TaskCreation'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/tasks.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'TaskCreationParams' + changes: + - kind: 'rename' + newName: 'TaskCreation' + + # --- Types: Misc --- + - title: "Rename to 'CancelledNotification'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/misc.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'CancelledNotificationParams' + changes: + - kind: 'rename' + newName: 'CancelledNotification' + + - title: "Rename to 'ProgressNotification'" + date: 2024-12-23 + element: + uris: + - 'package:mcp_dart/src/types/misc.dart' + - 'package:mcp_dart/mcp_dart.dart' + class: 'ProgressNotificationParams' + changes: + - kind: 'rename' + newName: 'ProgressNotification' + # --- Methods: McpServer --- - title: "Rename to 'registerResource'" date: 2024-12-23 diff --git a/lib/src/server/tasks/store.dart b/lib/src/server/tasks/store.dart index a95c599..a060f28 100644 --- a/lib/src/server/tasks/store.dart +++ b/lib/src/server/tasks/store.dart @@ -63,7 +63,7 @@ class InMemoryTaskStore implements TaskStore { @override Future createTask( - TaskCreationParams taskParams, + TaskCreation taskParams, RequestId requestId, Map requestData, String? sessionId, diff --git a/lib/src/shared/protocol.dart b/lib/src/shared/protocol.dart index 3919fc7..2e888ac 100644 --- a/lib/src/shared/protocol.dart +++ b/lib/src/shared/protocol.dart @@ -64,7 +64,7 @@ class RequestOptions { final Duration? maxTotalTimeout; /// Augments the request with task creation parameters. - final TaskCreationParams? task; + final TaskCreation? task; /// Associates this request with a related task. final RelatedTaskMetadata? relatedTask; @@ -954,7 +954,7 @@ abstract class Protocol { final cancelReason = reason?.toString() ?? 'Request cancelled'; final notification = JsonRpcCancelledNotification( - cancelParams: CancelledNotificationParams( + cancelParams: CancelledNotification( requestId: messageId, reason: cancelReason, ), @@ -1451,7 +1451,7 @@ class _RequestTaskStoreImpl implements RequestTaskStore { ); @override - Future createTask(TaskCreationParams taskParams) { + Future createTask(TaskCreation taskParams) { return _store.createTask( taskParams, _request.id, diff --git a/lib/src/shared/task_interfaces.dart b/lib/src/shared/task_interfaces.dart index 32f300e..5d6b400 100644 --- a/lib/src/shared/task_interfaces.dart +++ b/lib/src/shared/task_interfaces.dart @@ -9,7 +9,7 @@ abstract class TaskStore { /// [requestData] - The original request method and params. /// [sessionId] - The session ID of the client. Future createTask( - TaskCreationParams taskParams, + TaskCreation taskParams, RequestId requestId, Map requestData, String? sessionId, @@ -73,7 +73,7 @@ class QueuedMessage { /// Request-scoped TaskStore interface. abstract class RequestTaskStore { - Future createTask(TaskCreationParams taskParams); + Future createTask(TaskCreation taskParams); Future getTask(String taskId); Future storeTaskResult( String taskId, diff --git a/lib/src/types/json_rpc.dart b/lib/src/types/json_rpc.dart index fdc4264..b39fdef 100644 --- a/lib/src/types/json_rpc.dart +++ b/lib/src/types/json_rpc.dart @@ -429,10 +429,10 @@ class JsonRpcCallToolRequest extends JsonRpcRequest { params?.containsKey('task') == true; } - TaskCreationParams? get taskParams { + TaskCreation? get taskParams { final taskMap = meta?['task'] ?? params?['task']; if (taskMap is Map) { - return TaskCreationParams.fromJson(taskMap); + return TaskCreation.fromJson(taskMap); } return null; } diff --git a/lib/src/types/misc.dart b/lib/src/types/misc.dart index d52b322..78e09f6 100644 --- a/lib/src/types/misc.dart +++ b/lib/src/types/misc.dart @@ -12,17 +12,17 @@ class EmptyResult implements BaseResultData { } /// Parameters for the `notifications/cancelled` notification. -class CancelledNotificationParams { +class CancelledNotification { /// The ID of the request to cancel. final RequestId requestId; /// An optional string describing the reason for the cancellation. final String? reason; - const CancelledNotificationParams({required this.requestId, this.reason}); + const CancelledNotification({required this.requestId, this.reason}); - factory CancelledNotificationParams.fromJson(Map json) => - CancelledNotificationParams( + factory CancelledNotification.fromJson(Map json) => + CancelledNotification( requestId: json['requestId'], reason: json['reason'] as String?, ); @@ -36,7 +36,7 @@ class CancelledNotificationParams { /// Notification sent by either side to indicate cancellation of a request. class JsonRpcCancelledNotification extends JsonRpcNotification { /// The parameters detailing which request is cancelled and why. - final CancelledNotificationParams cancelParams; + final CancelledNotification cancelParams; JsonRpcCancelledNotification({required this.cancelParams, super.meta}) : super( @@ -51,7 +51,7 @@ class JsonRpcCancelledNotification extends JsonRpcNotification { } final meta = paramsMap['_meta'] as Map?; return JsonRpcCancelledNotification( - cancelParams: CancelledNotificationParams.fromJson(paramsMap), + cancelParams: CancelledNotification.fromJson(paramsMap), meta: meta, ); } @@ -92,7 +92,7 @@ class Progress { } /// Parameters for the `notifications/progress` notification. -class ProgressNotificationParams implements Progress { +class ProgressNotification implements Progress { /// The token originally provided in the request's `_meta`. final ProgressToken progressToken; @@ -104,15 +104,15 @@ class ProgressNotificationParams implements Progress { @override final num? total; - const ProgressNotificationParams({ + const ProgressNotification({ required this.progressToken, required this.progress, this.total, }); - factory ProgressNotificationParams.fromJson(Map json) { + factory ProgressNotification.fromJson(Map json) { final progressData = Progress.fromJson(json); - return ProgressNotificationParams( + return ProgressNotification( progressToken: json['progressToken'], progress: progressData.progress, total: progressData.total, @@ -132,7 +132,7 @@ class ProgressNotificationParams implements Progress { /// Out-of-band notification informing the receiver of progress on a request. class JsonRpcProgressNotification extends JsonRpcNotification { /// The progress parameters. - final ProgressNotificationParams progressParams; + final ProgressNotification progressParams; /// Creates a progress notification. JsonRpcProgressNotification({required this.progressParams, super.meta}) @@ -149,8 +149,16 @@ class JsonRpcProgressNotification extends JsonRpcNotification { } final meta = paramsMap['_meta'] as Map?; return JsonRpcProgressNotification( - progressParams: ProgressNotificationParams.fromJson(paramsMap), + progressParams: ProgressNotification.fromJson(paramsMap), meta: meta, ); } } + +/// Deprecated alias for [CancelledNotification]. +@Deprecated('Use CancelledNotification instead') +typedef CancelledNotificationParams = CancelledNotification; + +/// Deprecated alias for [ProgressNotification]. +@Deprecated('Use ProgressNotification instead') +typedef ProgressNotificationParams = ProgressNotification; diff --git a/lib/src/types/tasks.dart b/lib/src/types/tasks.dart index 9d143f8..fc00c82 100644 --- a/lib/src/types/tasks.dart +++ b/lib/src/types/tasks.dart @@ -302,14 +302,14 @@ class JsonRpcTaskResultRequest extends JsonRpcRequest { } /// Parameters for task creation when augmenting requests. -class TaskCreationParams { +class TaskCreation { /// Requested duration in milliseconds to retain task from creation. final int? ttl; - const TaskCreationParams({this.ttl}); + const TaskCreation({this.ttl}); - factory TaskCreationParams.fromJson(Map json) => - TaskCreationParams(ttl: json['ttl'] as int?); + factory TaskCreation.fromJson(Map json) => + TaskCreation(ttl: json['ttl'] as int?); Map toJson() => { if (ttl != null) 'ttl': ttl, @@ -468,3 +468,7 @@ typedef TaskResultRequestParams = TaskResultRequest; /// Deprecated alias for [TaskStatusNotification]. @Deprecated('Use TaskStatusNotification instead') typedef TaskStatusNotificationParams = TaskStatusNotification; + +/// Deprecated alias for [TaskCreation]. +@Deprecated('Use TaskCreation instead') +typedef TaskCreationParams = TaskCreation; diff --git a/llms.txt b/llms.txt index 25afb8f..bf4989a 100644 --- a/llms.txt +++ b/llms.txt @@ -94,7 +94,7 @@ void main() async { // Create server instance final server = McpServer( Implementation(name: 'my-server', version: '1.0.0'), - options: ServerOptions( + options: McpServerOptions( capabilities: ServerCapabilities( tools: ServerCapabilitiesTools(), resources: ServerCapabilitiesResources(), @@ -187,7 +187,7 @@ import 'package:mcp_dart/mcp_dart.dart'; void main() async { // Create client instance - final client = Client( + final client = McpClient( Implementation(name: 'my-client', version: '1.0.0'), ); @@ -215,13 +215,13 @@ void main() async { // Read a resource final resource = await client.readResource( - ReadResourceRequestParams(uri: Uri.parse('status://server')), + ReadResourceRequest(uri: Uri.parse('status://server')), ); print('Resource: ${resource.contents.first.text}'); // Get a prompt final prompt = await client.getPrompt( - GetPromptRequestParams( + GetPromptRequest( name: 'code-review', arguments: {'language': 'Dart'}, ), @@ -371,7 +371,7 @@ server.registerTool( // Request user confirmation final result = await extra.server.elicitInput( - ElicitRequestParams( + ElicitRequest( message: 'Are you sure you want to delete $path?', schema: JsonSchema.object( properties: { @@ -418,7 +418,7 @@ NEW in 1.1.0: Enhanced `McpServer` capabilities: // 1. Error Handler final server = McpServer( implementation, - options: ServerOptions( + options: McpServerOptions( onError: (error) { print('Server error: $error'); }, @@ -490,7 +490,7 @@ server.registerTool( if (progressToken != null) { await extra.sendNotification( JsonRpcProgressNotification( - progressParams: ProgressNotificationParams( + progressParams: ProgressNotification( progress: i, total: 100, progressToken: progressToken, @@ -557,7 +557,7 @@ final server = McpServer(/* ... */); await server.connect(StdioServerTransport()); // Client -final client = Client(/* ... */); +final client = McpClient(/* ... */); await client.connect(StdioClientTransport( StdioServerParameters( command: 'dart', @@ -582,7 +582,7 @@ await server.connect(transport); // await transport.handleRequest(request); // Client -final client = Client(/* ... */); +final client = McpClient(/* ... */); await client.connect(StreamableHTTPClientTransport( Uri.parse('http://localhost:3000'), )); @@ -604,7 +604,7 @@ await server.connect(IOStreamTransport( )); // Client -final client = Client(/* ... */); +final client = McpClient(/* ... */); await client.connect(IOStreamTransport( stream: s2c.stream, sink: c2s.sink, @@ -805,7 +805,7 @@ test('tool execution', () async { sink: s2c.sink, )); - final client = Client( + final client = McpClient( Implementation(name: 'test', version: '1.0.0'), ); diff --git a/test/interop/test_dart_server.dart b/test/interop/test_dart_server.dart index 171ece8..030f1c7 100644 --- a/test/interop/test_dart_server.dart +++ b/test/interop/test_dart_server.dart @@ -246,7 +246,7 @@ McpServer createServer() { await extra.sendNotification( // Fixed to use extra.sendNotification JsonRpcProgressNotification( - progressParams: ProgressNotificationParams( + progressParams: ProgressNotification( progressToken: progressToken, progress: progress, total: 100, diff --git a/test/shared/protocol_coverage_test.dart b/test/shared/protocol_coverage_test.dart new file mode 100644 index 0000000..b095b9f --- /dev/null +++ b/test/shared/protocol_coverage_test.dart @@ -0,0 +1,415 @@ +import 'dart:async'; + +import 'package:mcp_dart/src/shared/protocol.dart'; +import 'package:mcp_dart/src/shared/task_interfaces.dart'; +import 'package:mcp_dart/src/shared/transport.dart'; +import 'package:mcp_dart/src/types.dart'; +import 'package:test/test.dart'; + +/// Mock transport implementation for testing +class MockTransportForCoverage implements Transport { + final List sentMessages = []; + bool _started = false; + bool _closed = false; + + @override + String? get sessionId => 'test-session-id'; + + @override + void Function()? onclose; + + @override + void Function(Error error)? onerror; + + @override + void Function(JsonRpcMessage message)? onmessage; + + void receiveMessage(JsonRpcMessage message) { + if (_closed) return; + onmessage?.call(message); + } + + @override + Future close() async { + if (_closed) return; + _closed = true; + onclose?.call(); + } + + @override + Future send(JsonRpcMessage message, {int? relatedRequestId}) async { + if (_closed) throw StateError('Transport is closed'); + sentMessages.add(message); + } + + @override + Future start() async { + if (_closed) throw StateError('Cannot start closed transport'); + _started = true; + } + + bool get isStarted => _started; +} + +/// Test protocol implementation for coverage +class CoverageTestProtocol extends Protocol { + CoverageTestProtocol([super.options]); + + @override + void assertCapabilityForMethod(String method) { + // Allow all methods + } + + @override + void assertNotificationCapability(String method) { + // Allow all notifications + } + + @override + void assertRequestHandlerCapability(String method) { + // Allow all request handlers + } + + @override + void assertTaskCapability(String method) { + // Mock implementation + } + + @override + void assertTaskHandlerCapability(String method) { + // Mock implementation + } +} + +/// Result implementation for testing +class CoverageTestResult implements BaseResultData { + final String value; + + @override + final Map? meta; + + CoverageTestResult({required this.value, this.meta}); + + @override + Map toJson() => {'value': value}; +} + +void main() { + group('ProtocolOptions Coverage', () { + test('ProtocolOptions with all fields set', () { + const options = ProtocolOptions( + enforceStrictCapabilities: true, + debouncedNotificationMethods: ['notifications/test'], + defaultTaskPollInterval: 1000, + maxTaskQueueSize: 100, + ); + + expect(options.enforceStrictCapabilities, isTrue); + expect(options.debouncedNotificationMethods, isNotNull); + expect(options.debouncedNotificationMethods!.length, equals(1)); + expect(options.defaultTaskPollInterval, equals(1000)); + expect(options.maxTaskQueueSize, equals(100)); + }); + + test('ProtocolOptions default values', () { + const options = ProtocolOptions(); + expect(options.enforceStrictCapabilities, isFalse); + expect(options.debouncedNotificationMethods, isNull); + expect(options.taskStore, isNull); + expect(options.taskMessageQueue, isNull); + expect(options.defaultTaskPollInterval, isNull); + expect(options.maxTaskQueueSize, isNull); + }); + }); + + group('RequestOptions Coverage', () { + test('RequestOptions with task creation params', () { + const taskParams = TaskCreationParams(ttl: 3600); + const relatedTask = RelatedTaskMetadata(taskId: 'task-123'); + + const options = RequestOptions( + task: taskParams, + relatedTask: relatedTask, + timeout: Duration(seconds: 30), + maxTotalTimeout: Duration(minutes: 5), + resetTimeoutOnProgress: true, + ); + + expect(options.task, isNotNull); + expect(options.task!.ttl, equals(3600)); + expect(options.relatedTask, isNotNull); + expect(options.relatedTask!.taskId, equals('task-123')); + expect(options.resetTimeoutOnProgress, isTrue); + }); + + test('RequestOptions with abort signal', () { + final controller = BasicAbortController(); + + final options = RequestOptions( + signal: controller.signal, + ); + + expect(options.signal, isNotNull); + expect(options.signal!.aborted, isFalse); + + controller.abort('Test abort'); + expect(options.signal!.aborted, isTrue); + }); + + test('RequestOptions with progress callback', () { + final progressUpdates = []; + + final options = RequestOptions( + onprogress: (progress) => progressUpdates.add(progress), + ); + + options.onprogress!(const Progress(progress: 50, total: 100)); + expect(progressUpdates.length, equals(1)); + expect(progressUpdates[0].progress, equals(50)); + }); + }); + + group('RequestHandlerExtra Coverage', () { + test('RequestHandlerExtra with all fields', () async { + final controller = BasicAbortController(); + + Future sendNotification( + JsonRpcNotification notification, { + RelatedTaskMetadata? relatedTask, + }) async {} + + Future sendRequest( + JsonRpcRequest request, + T Function(Map) resultFactory, + RequestOptions options, + ) async { + return resultFactory({'value': 'test'}); + } + + void closeSSE() {} + void closeStandaloneSSE() {} + + final extra = RequestHandlerExtra( + signal: controller.signal, + sessionId: 'session-abc', + requestId: 42, + meta: {'key': 'value'}, + taskId: 'task-xyz', + taskRequestedTtl: 3600, + sendNotification: sendNotification, + sendRequest: sendRequest, + closeSSEStream: closeSSE, + closeStandaloneSSEStream: closeStandaloneSSE, + ); + + expect(extra.signal, isNotNull); + expect(extra.sessionId, equals('session-abc')); + expect(extra.requestId, equals(42)); + expect(extra.meta, isNotNull); + expect(extra.meta!['key'], equals('value')); + expect(extra.taskId, equals('task-xyz')); + expect(extra.taskRequestedTtl, equals(3600)); + expect(extra.closeSSEStream, isNotNull); + expect(extra.closeStandaloneSSEStream, isNotNull); + }); + + test('RequestHandlerExtra minimal fields', () async { + final controller = BasicAbortController(); + + final extra = RequestHandlerExtra( + signal: controller.signal, + requestId: 1, + sendNotification: (notification, {relatedTask}) async {}, + sendRequest: ( + JsonRpcRequest request, + T Function(Map) resultFactory, + RequestOptions options, + ) async { + return resultFactory({}); + }, + ); + + expect(extra.sessionId, isNull); + expect(extra.meta, isNull); + expect(extra.authInfo, isNull); + expect(extra.requestInfo, isNull); + expect(extra.taskId, isNull); + expect(extra.taskStore, isNull); + expect(extra.taskRequestedTtl, isNull); + expect(extra.closeSSEStream, isNull); + expect(extra.closeStandaloneSSEStream, isNull); + }); + }); + + group('Protocol Request Handler Coverage', () { + late CoverageTestProtocol protocol; + late MockTransportForCoverage transport; + + setUp(() { + protocol = CoverageTestProtocol(); + transport = MockTransportForCoverage(); + }); + + tearDown(() async { + try { + await protocol.close(); + } catch (_) {} + try { + await transport.close(); + } catch (_) {} + }); + + test('handles incoming request with registered handler', () async { + await protocol.connect(transport); + + // Register a custom handler for a known request type + protocol.setRequestHandler( + 'ping', + (request, extra) async { + return const EmptyResult(); + }, + (id, params, meta) => JsonRpcPingRequest(id: id), + ); + + // Simulate receiving a ping request + transport.receiveMessage(const JsonRpcPingRequest(id: 1)); + + // Wait for async handling + await Future.delayed(const Duration(milliseconds: 100)); + + // Verify response was sent + expect(transport.sentMessages.length, equals(1)); + expect(transport.sentMessages[0], isA()); + }); + + test('handles incoming request returning error', () async { + await protocol.connect(transport); + + // Register a handler that throws McpError + protocol.setRequestHandler( + 'ping', + (request, extra) async { + throw McpError( + ErrorCode.internalError.value, + 'Test error message', + {'detail': 'extra data'}, + ); + }, + (id, params, meta) => JsonRpcPingRequest(id: id), + ); + + transport.receiveMessage(const JsonRpcPingRequest(id: 2)); + + await Future.delayed(const Duration(milliseconds: 100)); + + expect(transport.sentMessages.length, equals(1)); + expect(transport.sentMessages[0], isA()); + + final errorResponse = transport.sentMessages[0] as JsonRpcError; + expect(errorResponse.error.code, equals(ErrorCode.internalError.value)); + expect(errorResponse.error.message, equals('Test error message')); + }); + + test('handles request for unregistered method', () async { + await protocol.connect(transport); + + // Remove the default ping handler to simulate unregistered method + protocol.removeRequestHandler('ping'); + + transport.receiveMessage(const JsonRpcPingRequest(id: 3)); + + await Future.delayed(const Duration(milliseconds: 100)); + + expect(transport.sentMessages.length, equals(1)); + expect(transport.sentMessages[0], isA()); + + final errorResponse = transport.sentMessages[0] as JsonRpcError; + expect(errorResponse.error.code, equals(ErrorCode.methodNotFound.value)); + }); + }); + + group('Protocol Notification Handler Coverage', () { + late CoverageTestProtocol protocol; + late MockTransportForCoverage transport; + + setUp(() { + protocol = CoverageTestProtocol(); + transport = MockTransportForCoverage(); + }); + + tearDown(() async { + try { + await protocol.close(); + } catch (_) {} + try { + await transport.close(); + } catch (_) {} + }); + + test('setNotificationHandler and removeNotificationHandler', () async { + await protocol.connect(transport); + + var handlerCalled = false; + + protocol.setNotificationHandler( + 'custom/notification', + (notification) async { + handlerCalled = true; + }, + (params, meta) => JsonRpcProgressNotification( + progressParams: ProgressNotificationParams.fromJson(params ?? {}), + ), + ); + + // Remove the handler + protocol.removeNotificationHandler('custom/notification'); + + // Now the handler should not be called + expect(handlerCalled, isFalse); + }); + }); + + group('Protocol send notification Coverage', () { + late CoverageTestProtocol protocol; + late MockTransportForCoverage transport; + + setUp(() async { + protocol = CoverageTestProtocol(); + transport = MockTransportForCoverage(); + await protocol.connect(transport); + }); + + tearDown(() async { + try { + await protocol.close(); + } catch (_) {} + try { + await transport.close(); + } catch (_) {} + }); + + test('sends notification successfully', () async { + await protocol.notification( + JsonRpcProgressNotification( + progressParams: const ProgressNotificationParams( + progressToken: 1, + progress: 50, + total: 100, + ), + ), + ); + + expect(transport.sentMessages.length, equals(1)); + expect(transport.sentMessages[0], isA()); + }); + }); + + group('DefaultRequestTimeout', () { + test('defaultRequestTimeout is 60 seconds', () { + expect( + defaultRequestTimeout, + equals(const Duration(milliseconds: 60000)), + ); + }); + }); +} diff --git a/test/types/resources_test.dart b/test/types/resources_test.dart new file mode 100644 index 0000000..534df60 --- /dev/null +++ b/test/types/resources_test.dart @@ -0,0 +1,643 @@ +import 'package:mcp_dart/src/types.dart'; +import 'package:test/test.dart'; + +void main() { + group('ResourceAnnotations', () { + test('fromJson with all fields', () { + final json = { + 'title': 'Test Resource', + 'audience': ['user', 'assistant'], + 'priority': 0.8, + }; + + final annotations = ResourceAnnotations.fromJson(json); + expect(annotations.title, equals('Test Resource')); + expect(annotations.audience, equals(['user', 'assistant'])); + expect(annotations.priority, equals(0.8)); + }); + + test('fromJson with null fields', () { + final json = {}; + final annotations = ResourceAnnotations.fromJson(json); + expect(annotations.title, isNull); + expect(annotations.audience, isNull); + expect(annotations.priority, isNull); + }); + + test('toJson serializes correctly', () { + const annotations = ResourceAnnotations( + title: 'My Title', + audience: ['user'], + priority: 0.5, + ); + + final json = annotations.toJson(); + expect(json['title'], equals('My Title')); + expect(json['audience'], equals(['user'])); + expect(json['priority'], equals(0.5)); + }); + + test('toJson excludes null fields', () { + const annotations = ResourceAnnotations(title: 'Only Title'); + final json = annotations.toJson(); + expect(json.containsKey('title'), isTrue); + expect(json.containsKey('audience'), isFalse); + expect(json.containsKey('priority'), isFalse); + }); + }); + + group('Resource', () { + test('fromJson with required fields only', () { + final json = { + 'uri': 'file:///test.txt', + 'name': 'Test File', + }; + + final resource = Resource.fromJson(json); + expect(resource.uri, equals('file:///test.txt')); + expect(resource.name, equals('Test File')); + expect(resource.description, isNull); + expect(resource.mimeType, isNull); + expect(resource.icon, isNull); + expect(resource.annotations, isNull); + }); + + test('fromJson with all fields', () { + final json = { + 'uri': 'file:///test.txt', + 'name': 'Test File', + 'description': 'A test file resource', + 'mimeType': 'text/plain', + 'icon': { + 'type': 'image', + 'data': 'base64data', + 'mimeType': 'image/png', + }, + 'annotations': { + 'title': 'Alt Title', + 'priority': 0.9, + }, + }; + + final resource = Resource.fromJson(json); + expect(resource.uri, equals('file:///test.txt')); + expect(resource.name, equals('Test File')); + expect(resource.description, equals('A test file resource')); + expect(resource.mimeType, equals('text/plain')); + expect(resource.icon, isNotNull); + expect(resource.icon!.data, equals('base64data')); + expect(resource.annotations, isNotNull); + expect(resource.annotations!.priority, equals(0.9)); + }); + + test('toJson serializes correctly with all fields', () { + const resource = Resource( + uri: 'file:///example.txt', + name: 'Example', + description: 'Example description', + mimeType: 'text/plain', + annotations: ResourceAnnotations(priority: 0.7), + ); + + final json = resource.toJson(); + expect(json['uri'], equals('file:///example.txt')); + expect(json['name'], equals('Example')); + expect(json['description'], equals('Example description')); + expect(json['mimeType'], equals('text/plain')); + expect(json['annotations'], isNotNull); + }); + + test('toJson excludes null optional fields', () { + const resource = Resource( + uri: 'file:///minimal.txt', + name: 'Minimal', + ); + + final json = resource.toJson(); + expect(json.containsKey('uri'), isTrue); + expect(json.containsKey('name'), isTrue); + expect(json.containsKey('description'), isFalse); + expect(json.containsKey('mimeType'), isFalse); + expect(json.containsKey('icon'), isFalse); + expect(json.containsKey('annotations'), isFalse); + }); + }); + + group('ResourceTemplate', () { + test('fromJson with required fields only', () { + final json = { + 'uriTemplate': 'file:///{path}', + 'name': 'File Template', + }; + + final template = ResourceTemplate.fromJson(json); + expect(template.uriTemplate, equals('file:///{path}')); + expect(template.name, equals('File Template')); + expect(template.description, isNull); + expect(template.mimeType, isNull); + }); + + test('fromJson with all fields', () { + final json = { + 'uriTemplate': 'db://users/{id}', + 'name': 'User Database', + 'description': 'Access user records', + 'mimeType': 'application/json', + 'icon': { + 'type': 'image', + 'data': 'icondata', + 'mimeType': 'image/svg+xml', + }, + 'annotations': { + 'audience': ['user'], + }, + }; + + final template = ResourceTemplate.fromJson(json); + expect(template.uriTemplate, equals('db://users/{id}')); + expect(template.name, equals('User Database')); + expect(template.description, equals('Access user records')); + expect(template.mimeType, equals('application/json')); + expect(template.icon, isNotNull); + expect(template.annotations, isNotNull); + }); + + test('toJson serializes correctly', () { + const template = ResourceTemplate( + uriTemplate: 'api://v1/{resource}', + name: 'API Resource', + description: 'API endpoint', + ); + + final json = template.toJson(); + expect(json['uriTemplate'], equals('api://v1/{resource}')); + expect(json['name'], equals('API Resource')); + expect(json['description'], equals('API endpoint')); + }); + + test('toJson excludes null fields', () { + const template = ResourceTemplate( + uriTemplate: 'minimal://{x}', + name: 'Minimal', + ); + + final json = template.toJson(); + expect(json.containsKey('uriTemplate'), isTrue); + expect(json.containsKey('name'), isTrue); + expect(json.containsKey('description'), isFalse); + expect(json.containsKey('mimeType'), isFalse); + }); + }); + + group('ListResourcesRequest', () { + test('fromJson with cursor', () { + final json = {'cursor': 'abc123'}; + final request = ListResourcesRequest.fromJson(json); + expect(request.cursor, equals('abc123')); + }); + + test('fromJson without cursor', () { + final json = {}; + final request = ListResourcesRequest.fromJson(json); + expect(request.cursor, isNull); + }); + + test('toJson with cursor', () { + const request = ListResourcesRequest(cursor: 'page2'); + final json = request.toJson(); + expect(json['cursor'], equals('page2')); + }); + + test('toJson without cursor excludes field', () { + const request = ListResourcesRequest(); + final json = request.toJson(); + expect(json.containsKey('cursor'), isFalse); + }); + }); + + group('JsonRpcListResourcesRequest', () { + test('creates request with method resources/list', () { + final request = JsonRpcListResourcesRequest(id: 1); + expect(request.method, equals('resources/list')); + expect(request.id, equals(1)); + }); + + test('creates request with params', () { + final request = JsonRpcListResourcesRequest( + id: 2, + params: const ListResourcesRequest(cursor: 'next'), + ); + expect(request.listParams.cursor, equals('next')); + expect(request.params?['cursor'], equals('next')); + }); + + test('fromJson parses correctly', () { + final json = { + 'id': 3, + 'method': 'resources/list', + 'params': {'cursor': 'xyz'}, + }; + + final request = JsonRpcListResourcesRequest.fromJson(json); + expect(request.id, equals(3)); + expect(request.listParams.cursor, equals('xyz')); + }); + + test('fromJson without params', () { + final json = { + 'id': 4, + 'method': 'resources/list', + }; + + final request = JsonRpcListResourcesRequest.fromJson(json); + expect(request.id, equals(4)); + expect(request.listParams.cursor, isNull); + }); + }); + + group('ListResourcesResult', () { + test('fromJson with resources', () { + final json = { + 'resources': [ + {'uri': 'file:///a.txt', 'name': 'A'}, + {'uri': 'file:///b.txt', 'name': 'B'}, + ], + 'nextCursor': 'page2', + }; + + final result = ListResourcesResult.fromJson(json); + expect(result.resources.length, equals(2)); + expect(result.resources[0].uri, equals('file:///a.txt')); + expect(result.resources[1].name, equals('B')); + expect(result.nextCursor, equals('page2')); + }); + + test('fromJson with empty resources', () { + final json = {}; + final result = ListResourcesResult.fromJson(json); + expect(result.resources, isEmpty); + expect(result.nextCursor, isNull); + }); + + test('fromJson with meta', () { + final json = { + 'resources': [], + '_meta': {'customKey': 'customValue'}, + }; + + final result = ListResourcesResult.fromJson(json); + expect(result.meta, isNotNull); + expect(result.meta!['customKey'], equals('customValue')); + }); + + test('toJson serializes correctly', () { + const result = ListResourcesResult( + resources: [ + Resource(uri: 'file:///x.txt', name: 'X'), + ], + nextCursor: 'more', + ); + + final json = result.toJson(); + expect(json['resources'], isA()); + expect((json['resources'] as List).length, equals(1)); + expect(json['nextCursor'], equals('more')); + }); + }); + + group('ListResourceTemplatesRequest', () { + test('fromJson with cursor', () { + final json = {'cursor': 'tmpl_cursor'}; + final request = ListResourceTemplatesRequest.fromJson(json); + expect(request.cursor, equals('tmpl_cursor')); + }); + + test('toJson serializes correctly', () { + const request = ListResourceTemplatesRequest(cursor: 'next_tmpl'); + final json = request.toJson(); + expect(json['cursor'], equals('next_tmpl')); + }); + }); + + group('JsonRpcListResourceTemplatesRequest', () { + test('creates request with correct method', () { + final request = JsonRpcListResourceTemplatesRequest(id: 10); + expect(request.method, equals('resources/templates/list')); + }); + + test('fromJson parses correctly', () { + final json = { + 'id': 11, + 'method': 'resources/templates/list', + 'params': {'cursor': 'tmpl_page'}, + }; + + final request = JsonRpcListResourceTemplatesRequest.fromJson(json); + expect(request.id, equals(11)); + expect(request.listParams.cursor, equals('tmpl_page')); + }); + }); + + group('ListResourceTemplatesResult', () { + test('fromJson with templates', () { + final json = { + 'resourceTemplates': [ + {'uriTemplate': 'file:///{name}', 'name': 'File'}, + ], + 'nextCursor': 'tmpl_next', + }; + + final result = ListResourceTemplatesResult.fromJson(json); + expect(result.resourceTemplates.length, equals(1)); + expect(result.resourceTemplates[0].uriTemplate, equals('file:///{name}')); + expect(result.nextCursor, equals('tmpl_next')); + }); + + test('fromJson with empty templates', () { + final json = {}; + final result = ListResourceTemplatesResult.fromJson(json); + expect(result.resourceTemplates, isEmpty); + }); + + test('toJson serializes correctly', () { + const result = ListResourceTemplatesResult( + resourceTemplates: [ + ResourceTemplate(uriTemplate: 'db://{id}', name: 'DB'), + ], + ); + + final json = result.toJson(); + expect(json['resourceTemplates'], isA()); + expect((json['resourceTemplates'] as List).length, equals(1)); + }); + }); + + group('ReadResourceRequest', () { + test('fromJson parses uri', () { + final json = {'uri': 'file:///data.json'}; + final request = ReadResourceRequest.fromJson(json); + expect(request.uri, equals('file:///data.json')); + }); + + test('toJson serializes correctly', () { + const request = ReadResourceRequest(uri: 'file:///output.txt'); + final json = request.toJson(); + expect(json['uri'], equals('file:///output.txt')); + }); + }); + + group('JsonRpcReadResourceRequest', () { + test('creates request with correct method', () { + final request = JsonRpcReadResourceRequest( + id: 20, + readParams: const ReadResourceRequest(uri: 'file:///read.txt'), + ); + expect(request.method, equals('resources/read')); + expect(request.readParams.uri, equals('file:///read.txt')); + }); + + test('fromJson parses correctly', () { + final json = { + 'id': 21, + 'method': 'resources/read', + 'params': {'uri': 'file:///parsed.txt'}, + }; + + final request = JsonRpcReadResourceRequest.fromJson(json); + expect(request.id, equals(21)); + expect(request.readParams.uri, equals('file:///parsed.txt')); + }); + + test('fromJson throws on missing params', () { + final json = { + 'id': 22, + 'method': 'resources/read', + }; + + expect( + () => JsonRpcReadResourceRequest.fromJson(json), + throwsA(isA()), + ); + }); + }); + + group('ReadResourceResult', () { + test('fromJson with contents', () { + final json = { + 'contents': [ + { + 'uri': 'file:///content.txt', + 'text': 'Hello World', + }, + ], + }; + + final result = ReadResourceResult.fromJson(json); + expect(result.contents.length, equals(1)); + expect(result.contents[0].uri, equals('file:///content.txt')); + }); + + test('fromJson with empty contents', () { + final json = {}; + final result = ReadResourceResult.fromJson(json); + expect(result.contents, isEmpty); + }); + + test('toJson serializes correctly', () { + final result = const ReadResourceResult( + contents: [ + TextResourceContents(uri: 'file:///out.txt', text: 'Content'), + ], + ); + + final json = result.toJson(); + expect(json['contents'], isA()); + }); + }); + + group('JsonRpcResourceListChangedNotification', () { + test('creates notification with correct method', () { + const notification = JsonRpcResourceListChangedNotification(); + expect( + notification.method, + equals('notifications/resources/list_changed'), + ); + }); + + test('fromJson creates notification', () { + final json = { + 'method': 'notifications/resources/list_changed', + }; + + final notification = + JsonRpcResourceListChangedNotification.fromJson(json); + expect( + notification.method, + equals('notifications/resources/list_changed'), + ); + }); + }); + + group('SubscribeRequest', () { + test('fromJson parses uri', () { + final json = {'uri': 'file:///watch.txt'}; + final request = SubscribeRequest.fromJson(json); + expect(request.uri, equals('file:///watch.txt')); + }); + + test('toJson serializes correctly', () { + const request = SubscribeRequest(uri: 'file:///subscribe.txt'); + final json = request.toJson(); + expect(json['uri'], equals('file:///subscribe.txt')); + }); + }); + + group('JsonRpcSubscribeRequest', () { + test('creates request with correct method', () { + final request = JsonRpcSubscribeRequest( + id: 30, + subParams: const SubscribeRequest(uri: 'file:///sub.txt'), + ); + expect(request.method, equals('resources/subscribe')); + }); + + test('fromJson parses correctly', () { + final json = { + 'id': 31, + 'method': 'resources/subscribe', + 'params': {'uri': 'file:///subscribed.txt'}, + }; + + final request = JsonRpcSubscribeRequest.fromJson(json); + expect(request.id, equals(31)); + expect(request.subParams.uri, equals('file:///subscribed.txt')); + }); + + test('fromJson throws on missing params', () { + final json = { + 'id': 32, + 'method': 'resources/subscribe', + }; + + expect( + () => JsonRpcSubscribeRequest.fromJson(json), + throwsA(isA()), + ); + }); + }); + + group('UnsubscribeRequest', () { + test('fromJson parses uri', () { + final json = {'uri': 'file:///unwatch.txt'}; + final request = UnsubscribeRequest.fromJson(json); + expect(request.uri, equals('file:///unwatch.txt')); + }); + + test('toJson serializes correctly', () { + const request = UnsubscribeRequest(uri: 'file:///unsub.txt'); + final json = request.toJson(); + expect(json['uri'], equals('file:///unsub.txt')); + }); + }); + + group('JsonRpcUnsubscribeRequest', () { + test('creates request with correct method', () { + final request = JsonRpcUnsubscribeRequest( + id: 40, + unsubParams: const UnsubscribeRequest(uri: 'file:///unsub.txt'), + ); + expect(request.method, equals('resources/unsubscribe')); + }); + + test('fromJson parses correctly', () { + final json = { + 'id': 41, + 'method': 'resources/unsubscribe', + 'params': {'uri': 'file:///unsubscribed.txt'}, + }; + + final request = JsonRpcUnsubscribeRequest.fromJson(json); + expect(request.id, equals(41)); + expect(request.unsubParams.uri, equals('file:///unsubscribed.txt')); + }); + + test('fromJson throws on missing params', () { + final json = { + 'id': 42, + 'method': 'resources/unsubscribe', + }; + + expect( + () => JsonRpcUnsubscribeRequest.fromJson(json), + throwsA(isA()), + ); + }); + }); + + group('ResourceUpdatedNotification', () { + test('fromJson parses uri', () { + final json = {'uri': 'file:///updated.txt'}; + final notification = ResourceUpdatedNotification.fromJson(json); + expect(notification.uri, equals('file:///updated.txt')); + }); + + test('toJson serializes correctly', () { + const notification = + ResourceUpdatedNotification(uri: 'file:///changed.txt'); + final json = notification.toJson(); + expect(json['uri'], equals('file:///changed.txt')); + }); + }); + + group('JsonRpcResourceUpdatedNotification', () { + test('creates notification with correct method', () { + final notification = JsonRpcResourceUpdatedNotification( + updatedParams: + const ResourceUpdatedNotification(uri: 'file:///notify.txt'), + ); + expect( + notification.method, + equals('notifications/resources/updated'), + ); + expect(notification.updatedParams.uri, equals('file:///notify.txt')); + }); + + test('fromJson parses correctly', () { + final json = { + 'method': 'notifications/resources/updated', + 'params': {'uri': 'file:///parsed_notify.txt'}, + }; + + final notification = JsonRpcResourceUpdatedNotification.fromJson(json); + expect( + notification.updatedParams.uri, + equals('file:///parsed_notify.txt'), + ); + }); + + test('fromJson throws on missing params', () { + final json = { + 'method': 'notifications/resources/updated', + }; + + expect( + () => JsonRpcResourceUpdatedNotification.fromJson(json), + throwsA(isA()), + ); + }); + + test('fromJson with meta', () { + final json = { + 'method': 'notifications/resources/updated', + 'params': { + 'uri': 'file:///with_meta.txt', + '_meta': {'key': 'value'}, + }, + }; + + final notification = JsonRpcResourceUpdatedNotification.fromJson(json); + expect(notification.meta, isNotNull); + expect(notification.meta!['key'], equals('value')); + }); + }); +}