Skip to content

Commit b63d5c0

Browse files
PabloTortosaLopezryzizubRuiMiguel
authored
feat: add custom MCP (#1416)
* feat: init mcp * refactor: refactored MCP server to use VeryGoodCommandRunner and minor label fixes * chore: expand tool descriptions and input schema details * feat: fixed create tool description and arguments * feat: fixed test tool description and arguments * fix: changed some create arguments descriptions * fix: improved some descriptions * fix: doc and fix tests * fix: test coverage for mcp_command * fix: test coverage for mcp_command * fix: tests and coverage for mcp_server * fix: exclude-covereage fix and test coverage * fix: fixed exclude_coverage schema * chore: removed unreachable exception blocks in each handle command * refactor: extract cliArgs to improve readability * chore: rename packages_check tool to packages_check_licenses and minor improvements * chore: remove unnecessary comments in mcp_server.dart * chore: remove unnecessary comments about stream_channel dependency * chore: update MCP tool names and links in README * chore: added experimental warning for mcp at README * fix: added experimental warning message to cli help --------- Co-authored-by: Dominik Simonik <[email protected]> Co-authored-by: RuiAlonso <[email protected]>
1 parent 84b4d14 commit b63d5c0

File tree

11 files changed

+1433
-0
lines changed

11 files changed

+1433
-0
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,26 @@ very_good packages check licenses --forbidden="unknown"
177177
very_good packages check licenses --dependency-type="direct-main,transitive"
178178
```
179179

180+
### [`very_good mcp`](https://cli.vgv.dev/docs/commands/mcp)
181+
182+
Start the MCP (Model Context Protocol) server for AI assistant integration.
183+
184+
> ℹ️ **Experimental**
185+
> This command relies on the [Dart MCP Server](https://docs.flutter.dev/ai/mcp-server). This is an experimental package and may change or become unstable without notice. Use it with caution at your own risk.
186+
187+
```sh
188+
# Start the MCP server
189+
very_good mcp
190+
```
191+
192+
The MCP server exposes Very Good CLI functionality through the Model Context Protocol, allowing AI assistants to interact with the CLI programmatically. This enables automated project creation, testing, and package management through MCP-compatible tools.
193+
194+
**Available MCP Tools:**
195+
- `create`: Create new Dart/Flutter projects (https://cli.vgv.dev/docs/category/templates)
196+
- `tests`: Run tests with optional coverage and optimization (https://cli.vgv.dev/docs/commands/test)
197+
- `packages_check_licenses`: Check packages for issues and licenses (https://cli.vgv.dev/docs/commands/check_licenses)
198+
- `packages_get`: Get package information and dependencies (https://cli.vgv.dev/docs/commands/get_pkgs)
199+
180200
### [`very_good --help`](https://cli.vgv.dev/docs/overview)
181201

182202
See the complete list of commands and usage information.
@@ -194,6 +214,7 @@ Global options:
194214
Available commands:
195215
create very_good create <subcommand> <project-name> [arguments]
196216
Creates a new very good project in the specified directory.
217+
mcp Start the MCP (Model Context Protocol) server. WARNING: This is an experimental package and may change or become unstable without notice. Use it with caution at your own risk.
197218
packages Command for managing packages.
198219
test Run tests in a Dart or Flutter project.
199220
update Update Very Good CLI.

bin/very_good.dart

100644100755
File mode changed.

lib/src/command_runner.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:pub_updater/pub_updater.dart';
88
import 'package:universal_io/io.dart';
99
import 'package:very_good_cli/src/commands/commands.dart';
1010
import 'package:very_good_cli/src/logger_extension.dart';
11+
import 'package:very_good_cli/src/mcp/mcp.dart';
1112
import 'package:very_good_cli/src/version.dart';
1213

1314
/// The package name.
@@ -37,6 +38,7 @@ class VeryGoodCommandRunner extends CompletionCommandRunner<int> {
3738
addCommand(TestCommand(logger: _logger));
3839
addCommand(UpdateCommand(logger: _logger, pubUpdater: pubUpdater));
3940
addCommand(DartCommand(logger: _logger));
41+
addCommand(MCPCommand(logger: _logger));
4042
}
4143

4244
/// Standard timeout duration for the CLI.

lib/src/mcp/mcp.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export 'mcp_command.dart';
2+
export 'mcp_server.dart';

lib/src/mcp/mcp_command.dart

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import 'dart:async';
2+
import 'dart:io';
3+
4+
import 'package:args/command_runner.dart';
5+
import 'package:dart_mcp/server.dart';
6+
import 'package:dart_mcp/stdio.dart';
7+
import 'package:mason/mason.dart';
8+
import 'package:stream_channel/stream_channel.dart';
9+
import 'package:very_good_cli/src/mcp/mcp_server.dart';
10+
11+
/// Type definition for a factory that creates a [VeryGoodMCPServer].
12+
typedef ServerFactory =
13+
MCPServer Function({
14+
required StreamChannel<String> channel,
15+
required Logger logger,
16+
});
17+
18+
/// Factory function to create a [StreamChannel] from input and output streams.
19+
typedef ChannelFactory = StreamChannel<String> Function();
20+
21+
// Private default implementation for the channel factory
22+
StreamChannel<String> _defaultChannelFactory() {
23+
return stdioChannel(input: stdin, output: stdout);
24+
}
25+
26+
/// {@template mcp_command}
27+
/// `very_good mcp` command starts the MCP (Model Context Protocol) server.
28+
/// {@endtemplate}
29+
class MCPCommand extends Command<int> {
30+
/// {@macro mcp_command}
31+
MCPCommand({
32+
Logger? logger,
33+
ChannelFactory? channelFactory,
34+
ServerFactory? serverFactory,
35+
}) : _logger = logger ?? Logger(),
36+
_channelFactory = channelFactory ?? _defaultChannelFactory,
37+
_serverFactory = serverFactory ?? VeryGoodMCPServer.new;
38+
39+
/// The [name] of the command. But static.
40+
static const String commandName = 'mcp';
41+
42+
@override
43+
String get description => '''
44+
Start the MCP (Model Context Protocol) server. WARNING: This is an experimental package and may change or become unstable without notice. Use it with caution at your own risk.''';
45+
46+
@override
47+
String get name => commandName;
48+
49+
final Logger _logger;
50+
51+
final ChannelFactory _channelFactory;
52+
53+
final ServerFactory _serverFactory;
54+
55+
@override
56+
Future<int> run() async {
57+
try {
58+
_logger
59+
..info('Starting Very Good CLI MCP Server...')
60+
..info(
61+
'Server will listen on stdin/stdout for MCP protocol messages',
62+
);
63+
64+
// Create a channel from stdin/stdout using the stdio helper
65+
final channel = _channelFactory();
66+
67+
// Create and start the MCP server
68+
final server = _serverFactory(
69+
channel: channel,
70+
logger: _logger,
71+
);
72+
73+
_logger
74+
..info('MCP Server started successfully')
75+
..info('Available tools:')
76+
..info('''
77+
- create: Create a very good Dart or Flutter project in seconds based on the provided template. Each template has a corresponding sub-command.''')
78+
..info(' - test: Run tests in a Dart or Flutter project.')
79+
..info(
80+
'''
81+
- packages_get: Install or update Dart/Flutter package dependencies.
82+
Use after creating a project or modifying pubspec.yaml.
83+
Supports recursive installation and package exclusion.''',
84+
)
85+
..info(
86+
'''
87+
- packages_check_licenses: Verify package licenses for compliance and validation in a Dart or Flutter project.
88+
Identifies license types (MIT, BSD, Apache, etc.) for all
89+
dependencies. Use to ensure license compatibility.''',
90+
);
91+
92+
// Wait for the server to complete
93+
// (this will block until the connection is closed)
94+
await server.done;
95+
96+
return ExitCode.success.code;
97+
} on Exception catch (e, stackTrace) {
98+
_logger
99+
..err('Failed to start MCP server: $e')
100+
..err('Stack trace: $stackTrace');
101+
return ExitCode.software.code;
102+
}
103+
}
104+
}

0 commit comments

Comments
 (0)