|
| 1 | +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file |
| 2 | +// for details. All rights reserved. Use of this source code is governed by a |
| 3 | +// BSD-style license that can be found in the LICENSE file. |
| 4 | + |
| 5 | +import 'dart:async'; |
| 6 | + |
| 7 | +import '../core.dart'; |
| 8 | +import '../sdk.dart'; |
| 9 | +import '../vm_interop_handler.dart'; |
| 10 | + |
| 11 | +class DartMCPServerCommand extends DartdevCommand { |
| 12 | + static const String cmdName = 'mcp-server'; |
| 13 | + |
| 14 | + static const String cmdDescription = ''' |
| 15 | +A stdio based Model Context Protocol (MCP) server to aid in Dart and Flutter development. |
| 16 | +
|
| 17 | +EXPERIMENTAL: This tool may change dramatically or disappear at any time.'''; |
| 18 | + |
| 19 | + static const _forceRootsFallbackFlag = 'force-roots-fallback'; |
| 20 | + static const _experimentFlag = 'experimental-mcp-server'; |
| 21 | + |
| 22 | + DartMCPServerCommand({bool verbose = false}) |
| 23 | + : super(cmdName, cmdDescription, verbose, hidden: true) { |
| 24 | + argParser |
| 25 | + ..addFlag( |
| 26 | + _forceRootsFallbackFlag, |
| 27 | + negatable: true, |
| 28 | + defaultsTo: false, |
| 29 | + help: |
| 30 | + 'Forces a behavior for project roots which uses MCP tools instead ' |
| 31 | + 'of the native MCP roots. This can be helpful for clients like ' |
| 32 | + 'Cursor which claim to have roots support but do not actually ' |
| 33 | + 'support it.', |
| 34 | + ) |
| 35 | + ..addFlag(_experimentFlag, |
| 36 | + defaultsTo: false, |
| 37 | + help: 'A required flag in order to use this command. Passing this ' |
| 38 | + 'flag is an acknowledgement that you understand it is an ' |
| 39 | + 'experimental feature with no stability guarantees.'); |
| 40 | + } |
| 41 | + |
| 42 | + @override |
| 43 | + Future<int> run() async { |
| 44 | + final args = argResults!; |
| 45 | + if (!args.flag(_experimentFlag)) { |
| 46 | + log.stderr('Missing required flag --$_experimentFlag\n\n$usage'); |
| 47 | + return 64; |
| 48 | + } |
| 49 | + try { |
| 50 | + VmInteropHandler.run( |
| 51 | + sdk.dartAotRuntime, |
| 52 | + [ |
| 53 | + sdk.dartMCPServerAotSnapshot, |
| 54 | + if (args.flag(_forceRootsFallbackFlag)) '--$_forceRootsFallbackFlag' |
| 55 | + ], |
| 56 | + useExecProcess: true, |
| 57 | + ); |
| 58 | + return 0; |
| 59 | + } catch (e, st) { |
| 60 | + log.stderr('Error: launching Dart MCP server failed'); |
| 61 | + log.stderr(e.toString()); |
| 62 | + if (verbose) { |
| 63 | + log.stderr(st.toString()); |
| 64 | + } |
| 65 | + return 255; |
| 66 | + } |
| 67 | + } |
| 68 | +} |
0 commit comments