Update mcp-server command to be an alias for 'run dart_mcp_server@'
Strips the dart-lang/ai dependency from the SDK entirely, as well as the snapshot. Bug: https://github.com/dart-lang/ai/issues/479 Change-Id: Id919c6a8fbf5fedeffb37e5181bc2fbd85adf986 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/507220 Reviewed-by: Ben Konyi <bkonyi@google.com> Commit-Queue: Ben Konyi <bkonyi@google.com> Auto-Submit: Jake Macdonald <jakemac@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
527d529493
commit
06bdbd777f
@@ -134,7 +134,6 @@ 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": "9c96bfe5f091c9451eff5b59c9bffeb2e806b875",
|
||||
"core_rev": "be0b1531c445a185d3e93887b8d0355fc766c314",
|
||||
"dartdoc_rev": "77a52b6125ce8cc8a88a8a399d80701254e43838",
|
||||
"ecosystem_rev": "319ff812d463fc194999a0d4b682097450279332",
|
||||
@@ -338,8 +337,6 @@ 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":
|
||||
|
||||
@@ -90,10 +90,6 @@ class Sdk {
|
||||
'dart2wasm_product.snapshot',
|
||||
);
|
||||
|
||||
String get dartMCPServerAotSnapshot => _snapshotPathFor(
|
||||
'dart_mcp_server_aot.dart.snapshot',
|
||||
);
|
||||
|
||||
String get ddsAotSnapshot => _snapshotPathFor(
|
||||
'dds_aot.dart.snapshot',
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@ import 'package:args/args.dart';
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:cli_util/cli_logging.dart';
|
||||
import 'package:dart_style/src/cli/format_command.dart';
|
||||
import 'package:dartdev/src/commands/dart_mcp_server.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:pub/pub.dart';
|
||||
import 'package:unified_analytics/unified_analytics.dart';
|
||||
@@ -20,7 +21,6 @@ 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';
|
||||
|
||||
@@ -4,14 +4,11 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:args/args.dart';
|
||||
import 'package:dart_mcp_server/arg_parser.dart' as dart_mcp_server;
|
||||
import 'package:dartdev/src/utils.dart';
|
||||
import 'package:dartdev/src/commands/run.dart';
|
||||
|
||||
import '../core.dart';
|
||||
import '../sdk.dart';
|
||||
import '../vm_interop_handler.dart';
|
||||
|
||||
/// This command is now just an alias for `dart run dart_mcp_server@`.
|
||||
class DartMCPServerCommand extends DartdevCommand {
|
||||
static const String cmdName = 'mcp-server';
|
||||
|
||||
@@ -20,12 +17,6 @@ A stdio based Model Context Protocol (MCP) server to aid in Dart and Flutter dev
|
||||
|
||||
static const _experimentFlag = 'experimental-mcp-server';
|
||||
|
||||
@override
|
||||
ArgParser createArgParser() => dart_mcp_server.createArgParser(
|
||||
usageLineLength: dartdevUsageLineLength,
|
||||
includeHelp: false,
|
||||
);
|
||||
|
||||
DartMCPServerCommand({bool verbose = false})
|
||||
: super(cmdName, cmdDescription, verbose, hidden: true) {
|
||||
argParser.addFlag(
|
||||
@@ -46,26 +37,33 @@ A stdio based Model Context Protocol (MCP) server to aid in Dart and Flutter dev
|
||||
|
||||
@override
|
||||
Future<int> run() async {
|
||||
final parsedArgs = argResults!;
|
||||
// We want the global arguments as we will be delegating back to the
|
||||
// command runner to run the new command.
|
||||
final forwardedArgs = globalResults!.arguments.toList();
|
||||
|
||||
// Strip out the experiment flag before forwarding on the args, this flag
|
||||
// isn't supported by the actual binary.
|
||||
final forwardedArgs = argResults!.arguments.toList();
|
||||
if (parsedArgs.wasParsed(_experimentFlag)) {
|
||||
// isn't supported by the actual package.
|
||||
//
|
||||
// Have to check the local arg results here, as this flag only exists on the
|
||||
// command arg parser and not the global one.
|
||||
if (argResults!.wasParsed(_experimentFlag)) {
|
||||
forwardedArgs.removeWhere((arg) => arg.endsWith(_experimentFlag));
|
||||
}
|
||||
try {
|
||||
VmInteropHandler.run(sdk.dartMCPServerAotSnapshot, [
|
||||
...forwardedArgs,
|
||||
], useExecProcess: false);
|
||||
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;
|
||||
|
||||
// Find the index of the original command argument and replace it with
|
||||
// `run dart_mcp_server@`.
|
||||
final commandIndex = forwardedArgs.indexOf(cmdName);
|
||||
if (commandIndex == -1) {
|
||||
throw StateError(
|
||||
'Reached mcp-server command without `mcp-server` in arguments.',
|
||||
);
|
||||
}
|
||||
forwardedArgs.replaceRange(commandIndex, commandIndex + 1, [
|
||||
RunCommand.cmdName,
|
||||
'dart_mcp_server@',
|
||||
]);
|
||||
|
||||
// Finally, run the new command.
|
||||
return await runner!.run(forwardedArgs) ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ dependencies:
|
||||
collection: any
|
||||
dart2native: any
|
||||
dart_data_home: any
|
||||
dart_mcp_server: any
|
||||
dart_style: any
|
||||
dartdoc: any
|
||||
data_assets: any
|
||||
@@ -47,7 +46,6 @@ dependencies:
|
||||
|
||||
# Use 'any' constraints here; we get our versions from the DEPS file.
|
||||
dev_dependencies:
|
||||
dart_mcp: any
|
||||
expect: any
|
||||
lints: any
|
||||
pub_semver: any
|
||||
|
||||
@@ -2,52 +2,70 @@
|
||||
// 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:io';
|
||||
|
||||
import 'package:dart_mcp/client.dart';
|
||||
import 'package:dart_mcp/stdio.dart';
|
||||
import 'dart:async';
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:dartdev/src/commands/dart_mcp_server.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('dart mcp-server', () {
|
||||
for (var withExperiment in const [true, false]) {
|
||||
test(
|
||||
'can be connected with a client with${withExperiment ? '' : 'out'} the experiment flag',
|
||||
() async {
|
||||
final client = TestMCPClient();
|
||||
addTearDown(client.shutdown);
|
||||
final process = await Process.start(Platform.resolvedExecutable, [
|
||||
'mcp-server',
|
||||
if (withExperiment) '--experimental-mcp-server',
|
||||
]);
|
||||
group('DartMCPServerCommand', () {
|
||||
late FakeRunner runner;
|
||||
late DartMCPServerCommand command;
|
||||
|
||||
final connection = client.connectServer(
|
||||
stdioChannel(input: process.stdout, output: process.stdin),
|
||||
);
|
||||
connection.done.then((_) => process.kill());
|
||||
setUp(() {
|
||||
runner = FakeRunner();
|
||||
command = DartMCPServerCommand();
|
||||
runner.addCommand(command);
|
||||
});
|
||||
|
||||
final initializeResult = await connection.initialize(
|
||||
InitializeRequest(
|
||||
protocolVersion: ProtocolVersion.latestSupported,
|
||||
capabilities: client.capabilities,
|
||||
clientInfo: client.implementation,
|
||||
),
|
||||
);
|
||||
test('delegates to `run dart_mcp_server@`', () async {
|
||||
await runner.run(['mcp-server']);
|
||||
expect(runner.capturedArgs, equals(['run', 'dart_mcp_server@']));
|
||||
});
|
||||
|
||||
expect(
|
||||
initializeResult.protocolVersion,
|
||||
ProtocolVersion.latestSupported,
|
||||
);
|
||||
connection.notifyInitialized();
|
||||
|
||||
expect(await connection.listTools(ListToolsRequest()), isNotEmpty);
|
||||
},
|
||||
test('forwards command arguments', () async {
|
||||
await runner.run(['mcp-server', 'foo', 'bar']);
|
||||
expect(
|
||||
runner.capturedArgs,
|
||||
equals(['run', 'dart_mcp_server@', 'foo', 'bar']),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('strips experimental flag', () async {
|
||||
await runner.run(['mcp-server', '--experimental-mcp-server']);
|
||||
expect(runner.capturedArgs, equals(['run', 'dart_mcp_server@']));
|
||||
});
|
||||
|
||||
test('strips experimental flag and keeps other args', () async {
|
||||
await runner.run(['mcp-server', '--experimental-mcp-server', 'foo']);
|
||||
expect(runner.capturedArgs, equals(['run', 'dart_mcp_server@', 'foo']));
|
||||
});
|
||||
|
||||
test('forwards global arguments', () async {
|
||||
runner.argParser.addFlag('global-flag', negatable: false);
|
||||
await runner.run(['--global-flag', 'mcp-server']);
|
||||
expect(
|
||||
runner.capturedArgs,
|
||||
equals(['--global-flag', 'run', 'dart_mcp_server@']),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
base class TestMCPClient extends MCPClient {
|
||||
TestMCPClient()
|
||||
: super(Implementation(name: 'test client', version: '0.1.0'));
|
||||
class FakeRunner extends CommandRunner<int> {
|
||||
List<String>? capturedArgs;
|
||||
bool isFirstCall = true;
|
||||
|
||||
FakeRunner() : super('dart', 'dart command runner');
|
||||
|
||||
@override
|
||||
Future<int?> run(Iterable<String> args) async {
|
||||
if (isFirstCall) {
|
||||
isFirstCall = false;
|
||||
return await super.run(args);
|
||||
} else {
|
||||
capturedArgs = args.toList();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,10 +140,6 @@ 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:
|
||||
|
||||
@@ -150,11 +150,6 @@ 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",
|
||||
],
|
||||
]
|
||||
if (include_experimental_vm_service) {
|
||||
_platform_sdk_snapshots += [ [
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
# 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 = "dart_mcp_server.dart"
|
||||
output = "$root_gen_dir/dart_mcp_server_aot.dart.snapshot"
|
||||
}
|
||||
|
||||
aot_snapshot("dart_mcp_server_aot_product_snapshot") {
|
||||
main_dart = "dart_mcp_server.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
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// 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.
|
||||
|
||||
/// A custom entrypoint used by `dart mcp-server`. Injects an analytics instance
|
||||
/// using the [DashTool.dartTool] tool.
|
||||
library;
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dart_mcp_server/dart_mcp_server.dart';
|
||||
import 'package:unified_analytics/unified_analytics.dart';
|
||||
|
||||
void main(List<String> args) async {
|
||||
DashTool? tool;
|
||||
if (Platform.environment['DASH__TOOL'] case final toolEnv?) {
|
||||
try {
|
||||
tool = DashTool.fromLabel(toolEnv);
|
||||
} catch (e) {
|
||||
// Ignore errors, but don't track analytics for unrecognized tools.
|
||||
}
|
||||
} else {
|
||||
// We default to the `dart` tool if none specified.
|
||||
tool = DashTool.dartTool;
|
||||
}
|
||||
|
||||
final analytics = tool != null
|
||||
? Analytics(
|
||||
tool: tool,
|
||||
// The actual version is the part up to the first space.
|
||||
dartVersion: Platform.version.split(' ').first,
|
||||
)
|
||||
: null;
|
||||
|
||||
exitCode = await DartMCPServer.run(args, analytics: analytics);
|
||||
}
|
||||
Reference in New Issue
Block a user