Add a dart mcp-server command per go/dart-mcp-server-release-plan.

- Adds `dart_mcp` and `dart_mcp_server` as DEPS
- Build an AOT snapshot for the dart_mcp_server executable
- Add top level `mcp-server` command to dartdev (hidden).
- I also did add an `--experimental-mcp-server` flag which is required for this command to actually work. We had initially discussed not doing this due to complexity but I was able to keep it completely scoped to just this command. I can remove it if there are strong opinions though.

Change-Id: I737a5625507f69a904ccd1012682764eb360a2c2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/430900
Reviewed-by: Siva Annamalai <asiva@google.com>
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Jake Macdonald <jakemac@google.com>
This commit is contained in:
Jake Macdonald
2025-05-27 10:14:26 -07:00
committed by Commit Queue
parent f3a4e5bc54
commit d828c36cec
7 changed files with 121 additions and 0 deletions
+3
View File
@@ -129,6 +129,7 @@ vars = {
### /third_party/pkg dependencies
# 'tools/rev_sdk_deps.dart' will rev pkg dependencies to their latest; put an
# EOL comment after a dependency to instead pin at the current revision.
"ai_rev": "93a9191b6eed79d24fc5d3ec9b514f71c888fc41",
"core_rev": "635dfa32c261ba078438b74de397f2207904ca78", # https://github.com/dart-lang/core/pull/734
"dartdoc_rev": "e38f392163a4738a21024acd370d104e0efe72f0",
"ecosystem_rev": "815d4ba2e7d11f8695a26f6cbe1262e3b8ff8d0d",
@@ -327,6 +328,8 @@ deps = {
Var('chromium_git') + '/external/github.com/mdn/browser-compat-data' +
"@" + Var("browser-compat-data_tag"),
Var("dart_root") + "/third_party/pkg/ai":
Var("dart_git") + "ai.git" + "@" + Var("ai_rev"),
Var("dart_root") + "/third_party/pkg/core":
Var("dart_git") + "core.git" + "@" + Var("core_rev"),
Var("dart_root") + "/third_party/pkg/dart_style":
+2
View File
@@ -20,6 +20,7 @@ import 'src/commands/build.dart';
import 'src/commands/compilation_server.dart';
import 'src/commands/compile.dart';
import 'src/commands/create.dart';
import 'src/commands/dart_mcp_server.dart';
import 'src/commands/debug_adapter.dart';
import 'src/commands/development_service.dart';
import 'src/commands/devtools.dart';
@@ -118,6 +119,7 @@ class DartdevRunner extends CommandRunner<int> {
addCommand(FormatCommand(verbose: verbose));
addCommand(InfoCommand(verbose: verbose));
addCommand(LanguageServerCommand(verbose: verbose));
addCommand(DartMCPServerCommand(verbose: verbose));
addCommand(pubCommand(isVerbose: () => verbose));
addCommand(RunCommand(
verbose: verbose,
@@ -0,0 +1,68 @@
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import '../core.dart';
import '../sdk.dart';
import '../vm_interop_handler.dart';
class DartMCPServerCommand extends DartdevCommand {
static const String cmdName = 'mcp-server';
static const String cmdDescription = '''
A stdio based Model Context Protocol (MCP) server to aid in Dart and Flutter development.
EXPERIMENTAL: This tool may change dramatically or disappear at any time.''';
static const _forceRootsFallbackFlag = 'force-roots-fallback';
static const _experimentFlag = 'experimental-mcp-server';
DartMCPServerCommand({bool verbose = false})
: super(cmdName, cmdDescription, verbose, hidden: true) {
argParser
..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.',
)
..addFlag(_experimentFlag,
defaultsTo: false,
help: 'A required flag in order to use this command. Passing this '
'flag is an acknowledgement that you understand it is an '
'experimental feature with no stability guarantees.');
}
@override
Future<int> run() async {
final args = argResults!;
if (!args.flag(_experimentFlag)) {
log.stderr('Missing required flag --$_experimentFlag\n\n$usage');
return 64;
}
try {
VmInteropHandler.run(
sdk.dartAotRuntime,
[
sdk.dartMCPServerAotSnapshot,
if (args.flag(_forceRootsFallbackFlag)) '--$_forceRootsFallbackFlag'
],
useExecProcess: true,
);
return 0;
} catch (e, st) {
log.stderr('Error: launching Dart MCP server failed');
log.stderr(e.toString());
if (verbose) {
log.stderr(st.toString());
}
return 255;
}
}
}
+4
View File
@@ -102,6 +102,10 @@ class Sdk {
'dart2wasm_product.snapshot',
);
String get dartMCPServerAotSnapshot => _snapshotPathFor(
'dart_mcp_server_aot.dart.snapshot',
);
String get ddsSnapshot => _snapshotPathFor(
'dds.dart.snapshot',
);
+8
View File
@@ -143,6 +143,10 @@ dependency_overrides:
path: third_party/pkg/tools/pkgs/csslib
dart_flutter_team_lints:
path: third_party/pkg/ecosystem/pkgs/dart_flutter_team_lints
dart_mcp:
path: third_party/pkg/ai/pkgs/dart_mcp
dart_mcp_server:
path: third_party/pkg/ai/pkgs/dart_mcp_server
dart_style:
path: third_party/pkg/dart_style
dartdoc:
@@ -221,6 +225,8 @@ dependency_overrides:
path: third_party/pkg/tools/pkgs/pool
protobuf:
path: third_party/pkg/protobuf/protobuf
process:
path: third_party/pkg/tools/pkgs/process
protobuf_benchmarks:
path: third_party/pkg/protobuf/benchmarks
protoc_plugin:
@@ -257,6 +263,8 @@ dependency_overrides:
path: third_party/pkg/tools/pkgs/stack_trace
stream_channel:
path: third_party/pkg/tools/pkgs/stream_channel
stream_transform:
path: third_party/pkg/tools/pkgs/stream_transform
string_scanner:
path: third_party/pkg/tools/pkgs/string_scanner
swift2objc:
+5
View File
@@ -151,6 +151,11 @@ if (dart_target_arch != "ia32" && dart_target_arch != "x86") {
"../utils/dtd:dtd_aot",
"dart_tooling_daemon_aot",
],
[
"dart_mcp_server_aot_product",
"../utils/dart_mcp_server:dart_mcp_server_aot",
"dart_mcp_server_aot",
],
]
} else {
_platform_sdk_snapshots += [
+31
View File
@@ -0,0 +1,31 @@
# Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
import("../../runtime/runtime_args.gni")
import("../aot_snapshot.gni")
group("dart_mcp_server_aot") {
public_deps = [
":dart_mcp_server_aot_product_snapshot",
":dart_mcp_server_aot_snapshot",
]
}
aot_snapshot("dart_mcp_server_aot_snapshot") {
main_dart = "../../third_party/pkg/ai/pkgs/dart_mcp_server/bin/main.dart"
output = "$root_gen_dir/dart_mcp_server_aot.dart.snapshot"
}
aot_snapshot("dart_mcp_server_aot_product_snapshot") {
main_dart = "../../third_party/pkg/ai/pkgs/dart_mcp_server/bin/main.dart"
output = "$root_gen_dir/dart_mcp_server_aot_product.dart.snapshot"
# dartaotruntime has dart_product_config applied to it,
# so it is built in product mode in both release and
# product builds, and is only built in debug mode in debug
# builds. The following line ensures that the dartaotruntime
# and dart_mcp_server_aot snapshot in an SDK build are
# always compatible with each other.
force_product_mode = !dart_debug
}