Skip to content

Migrate to the connected app service #208

New issue

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

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

Already on GitHub? Sign in to your account

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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dart_mcp_server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
fail-fast: false
matrix:
flutterSdk:
- stable
- beta
- master
os:
- ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions pkgs/dart_mcp_server/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
* Add `--log-file` argument to log all protocol traffic to a file.
* Improve error text for failed DTD connections as well as the tool description.
* Add support for injecting an `Analytics` instance to track usage.
* Listen to the new DTD `ConnectedApp` service instead of the `Editor.DebugSessions`
service, when available.
* Screenshot tool disabled until
https://github.com/flutter/flutter/issues/170357 is resolved.
* Add `arg_parser.dart` public library with minimal deps to be used by the dart tool.
63 changes: 31 additions & 32 deletions pkgs/dart_mcp_server/lib/src/arg_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,37 @@

import 'package:args/args.dart';

final argParser =
ArgParser(allowTrailingOptions: false)
..addOption(
dartSdkOption,
help:
'The path to the root of the desired Dart SDK. Defaults to the '
'DART_SDK environment variable.',
)
..addOption(
flutterSdkOption,
help:
'The path to the root of the desired Flutter SDK. Defaults to '
'the FLUTTER_SDK environment variable, then searching up from '
'the Dart SDK.',
)
..addFlag(
forceRootsFallbackFlag,
negatable: true,
defaultsTo: false,
help:
'Forces a behavior for project roots which uses MCP tools '
'instead of the native MCP roots. This can be helpful for '
'clients like cursor which claim to have roots support but do '
'not actually support it.',
)
..addOption(
logFileOption,
help:
'Path to a file to log all MPC protocol traffic to. File will be '
'overwritten if it exists.',
)
..addFlag(helpFlag, abbr: 'h', help: 'Show usage text');
final argParser = ArgParser(allowTrailingOptions: false)
..addOption(
dartSdkOption,
help:
'The path to the root of the desired Dart SDK. Defaults to the '
'DART_SDK environment variable.',
)
..addOption(
flutterSdkOption,
help:
'The path to the root of the desired Flutter SDK. Defaults to '
'the FLUTTER_SDK environment variable, then searching up from '
'the Dart SDK.',
)
..addFlag(
forceRootsFallbackFlag,
negatable: true,
defaultsTo: false,
help:
'Forces a behavior for project roots which uses MCP tools '
'instead of the native MCP roots. This can be helpful for '
'clients like cursor which claim to have roots support but do '
'not actually support it.',
)
..addOption(
logFileOption,
help:
'Path to a file to log all MPC protocol traffic to. File will be '
'overwritten if it exists.',
)
..addFlag(helpFlag, abbr: 'h', help: 'Show usage text');

const dartSdkOption = 'dart-sdk';
const flutterSdkOption = 'flutter-sdk';
Expand Down
44 changes: 23 additions & 21 deletions pkgs/dart_mcp_server/lib/src/mixins/analyzer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -110,19 +110,18 @@ base mixin DartAnalyzerSupport
log(LoggingLevel.warning, line, logger: 'DartLanguageServer');
});

final lspConnection =
Peer(lspChannel(lspServer.stdout, lspServer.stdin))
..registerMethod(
lsp.Method.textDocument_publishDiagnostics.toString(),
_handleDiagnostics,
)
..registerMethod(r'$/analyzerStatus', _handleAnalyzerStatus)
..registerFallback((Parameters params) {
log(
LoggingLevel.debug,
() => 'Unhandled LSP message: ${params.method} - ${params.asMap}',
);
});
final lspConnection = Peer(lspChannel(lspServer.stdout, lspServer.stdin))
..registerMethod(
lsp.Method.textDocument_publishDiagnostics.toString(),
_handleDiagnostics,
)
..registerMethod(r'$/analyzerStatus', _handleAnalyzerStatus)
..registerFallback((Parameters params) {
log(
LoggingLevel.debug,
() => 'Unhandled LSP message: ${params.method} - ${params.asMap}',
);
});
_lspConnection = lspConnection;

unawaited(lspConnection.listen());
Expand Down Expand Up @@ -357,8 +356,9 @@ base mixin DartAnalyzerSupport
diagnostics[diagnosticParams.uri] = diagnosticParams.diagnostics;
log(LoggingLevel.debug, {
ParameterNames.uri: diagnosticParams.uri,
'diagnostics':
diagnosticParams.diagnostics.map((d) => d.toJson()).toList(),
'diagnostics': diagnosticParams.diagnostics
.map((d) => d.toJson())
.toList(),
});
}

Expand All @@ -370,16 +370,18 @@ base mixin DartAnalyzerSupport
final newRoots = await roots;

final oldWorkspaceFolders = _currentWorkspaceFolders;
final newWorkspaceFolders =
_currentWorkspaceFolders = HashSet<lsp.WorkspaceFolder>(
final newWorkspaceFolders = _currentWorkspaceFolders =
HashSet<lsp.WorkspaceFolder>(
equals: (a, b) => a.uri == b.uri,
hashCode: (a) => a.uri.hashCode,
)..addAll(newRoots.map((r) => r.asWorkspaceFolder));

final added =
newWorkspaceFolders.difference(oldWorkspaceFolders).toList();
final removed =
oldWorkspaceFolders.difference(newWorkspaceFolders).toList();
final added = newWorkspaceFolders
.difference(oldWorkspaceFolders)
.toList();
final removed = oldWorkspaceFolders
.difference(newWorkspaceFolders)
.toList();

// This can happen in the case of multiple notifications in quick
// succession, the `roots` future will complete only after the state has
Expand Down
22 changes: 10 additions & 12 deletions pkgs/dart_mcp_server/lib/src/mixins/dash_cli.dart
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,9 @@ base mixin DashCliSupport on ToolsSupport, LoggingSupport, RootsTrackingSupport
// Platforms are ignored for Dart, so no need to validate them.
final invalidPlatforms = platforms.difference(_allowedFlutterPlatforms);
if (invalidPlatforms.isNotEmpty) {
final plural =
invalidPlatforms.length > 1
? 'are not valid platforms'
: 'is not a valid platform';
final plural = invalidPlatforms.length > 1
? 'are not valid platforms'
: 'is not a valid platform';
errors.add(
ValidationError(
ValidationErrorType.custom,
Expand Down Expand Up @@ -163,14 +162,13 @@ base mixin DashCliSupport on ToolsSupport, LoggingSupport, RootsTrackingSupport
return runCommandInRoot(
request,
arguments: commandArgs,
commandForRoot:
(_, _, sdk) =>
switch (projectType) {
'dart' => sdk.dartExecutablePath,
'flutter' => sdk.flutterExecutablePath,
_ => StateError('Unknown project type: $projectType'),
}
as String,
commandForRoot: (_, _, sdk) =>
switch (projectType) {
'dart' => sdk.dartExecutablePath,
'flutter' => sdk.flutterExecutablePath,
_ => StateError('Unknown project type: $projectType'),
}
as String,
commandDescription: '$projectType create',
fileSystem: fileSystem,
processManager: processManager,
Expand Down
Loading