Skip to content

Commit e09e469

Browse files
authored
add prompt for using flutter driver to write a test for a user journey (#243)
For clients that have prompts support, this prompt allows a user to provide a user journey and it will instruct the LLM to: - Try to accomplish the user journey in the live app using flutter driver - If successful, write a flutter driver test with the same instructions used to accomplish the journey. TODO: Add support for running flutter driver tests in the MCP server and add that to the prompt.
1 parent 88d7a4d commit e09e469

File tree

7 files changed

+119
-12
lines changed

7 files changed

+119
-12
lines changed

pkgs/dart_mcp/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
- This package still allows `reject` and treats it as an alias for`decline`.
88
- The old `reject` enum value was replaced with a static constant equal
99
exactly to `decline`, so switches are not affected.
10-
10+
- Add `title` parameter to `Prompt` constructor.
1111

1212
## 0.3.2
1313

pkgs/dart_mcp/lib/src/api/api.dart

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -503,15 +503,6 @@ extension type ResourceLink.fromMap(Map<String, Object?> _value)
503503
return type;
504504
}
505505

506-
/// The name of the resource.
507-
String get name {
508-
final name = _value['name'] as String?;
509-
if (name == null) {
510-
throw ArgumentError('Missing name field in $ResourceLink.');
511-
}
512-
return name;
513-
}
514-
515506
/// The description of the resource.
516507
String get description {
517508
final description = _value['description'] as String?;

pkgs/dart_mcp/lib/src/api/prompts.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,12 @@ extension type Prompt.fromMap(Map<String, Object?> _value)
9090
implements BaseMetadata {
9191
factory Prompt({
9292
required String name,
93+
String? title,
9394
String? description,
9495
List<PromptArgument>? arguments,
9596
}) => Prompt.fromMap({
9697
'name': name,
98+
if (title != null) 'title': title,
9799
if (description != null) 'description': description,
98100
if (arguments != null) 'arguments': arguments,
99101
});
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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 'package:dart_mcp/server.dart';
8+
import 'package:meta/meta.dart';
9+
10+
/// A mixin which adds support for various dart and flutter specific prompts.
11+
base mixin DashPrompts on PromptsSupport {
12+
@override
13+
FutureOr<InitializeResult> initialize(InitializeRequest request) {
14+
addPrompt(flutterDriverUserJourneyTest, _flutterDriverUserJourneyPrompt);
15+
return super.initialize(request);
16+
}
17+
18+
/// Creates the flutter driver user journey prompt based on a request.
19+
GetPromptResult _flutterDriverUserJourneyPrompt(GetPromptRequest request) {
20+
return GetPromptResult(
21+
messages: [
22+
PromptMessage(
23+
role: Role.user,
24+
content: flutterDriverUserJourneyPromptContent,
25+
),
26+
],
27+
);
28+
}
29+
30+
@visibleForTesting
31+
static final flutterDriverUserJourneyTest = Prompt(
32+
name: 'flutter_driver_user_journey_test',
33+
title: 'User journey flutter driver test',
34+
description: '''
35+
Prompts the LLM to attempt to accomplish a user journey in the running app using
36+
flutter driver. If successful, it will then translate the steps it followed into
37+
a flutter driver test and write that to disk.
38+
''',
39+
);
40+
41+
@visibleForTesting
42+
static final flutterDriverUserJourneyPromptContent = Content.text(
43+
text: '''
44+
Perform the following tasks in order:
45+
46+
- Prompt the user to navigate to the home page of the app.
47+
- Prompt the user for a user journey that they would like to write a test for.
48+
- Attempt to complete the given user journey using flutter driver to inspect the
49+
widget tree and interact with the application. Only durable interactions
50+
should be performed, do not use temporary IDs to select or interact with
51+
widgets, but instead select them based on text, type, tooltip, etc. Avoid
52+
reading in files to accomplish this task, just inspect the live state of the
53+
app and widget tree. If you get stuck, feel free to ask the user for help.
54+
- If you are able to successfully complete the journey, then create a flutter
55+
driver based test with an appropriate name, which performs all the same
56+
actions that you performed. Include the original user journey as a comment
57+
in the test file.
58+
''',
59+
);
60+
}

pkgs/dart_mcp_server/lib/src/server.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import 'arg_parser.dart';
1919
import 'mixins/analyzer.dart';
2020
import 'mixins/dash_cli.dart';
2121
import 'mixins/dtd.dart';
22+
import 'mixins/prompts.dart';
2223
import 'mixins/pub.dart';
2324
import 'mixins/pub_dev_search.dart';
2425
import 'mixins/roots_fallback_support.dart';
@@ -39,7 +40,9 @@ final class DartMCPServer extends MCPServer
3940
DashCliSupport,
4041
PubSupport,
4142
PubDevSupport,
42-
DartToolingDaemonSupport
43+
DartToolingDaemonSupport,
44+
PromptsSupport,
45+
DashPrompts
4346
implements
4447
AnalyticsSupport,
4548
ProcessManagerSupport,

pkgs/dart_mcp_server/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ dependencies:
1313
args: ^2.7.0
1414
async: ^2.13.0
1515
collection: ^1.19.1
16-
dart_mcp: ^0.3.2
16+
dart_mcp: ^0.3.3
1717
dds_service_extensions: ^2.0.1
1818
devtools_shared: ^12.0.0
1919
dtd: ^4.0.0
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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 'package:dart_mcp/server.dart';
6+
import 'package:dart_mcp_server/src/mixins/prompts.dart';
7+
import 'package:test/test.dart';
8+
9+
import '../test_harness.dart';
10+
11+
void main() {
12+
late TestHarness testHarness;
13+
14+
// TODO: Use setUpAll, currently this fails due to an apparent TestProcess
15+
// issue.
16+
setUp(() async {
17+
testHarness = await TestHarness.start();
18+
});
19+
20+
test('can list prompts', () async {
21+
final server = testHarness.mcpServerConnection;
22+
final promptsResult = await server.listPrompts(ListPromptsRequest());
23+
expect(
24+
promptsResult.prompts,
25+
equals([
26+
isA<GetPromptRequest>().having(
27+
(p) => p.name,
28+
'name',
29+
DashPrompts.flutterDriverUserJourneyTest.name,
30+
),
31+
]),
32+
);
33+
});
34+
35+
test('can get the flutter driver user journey prompt', () async {
36+
final server = testHarness.mcpServerConnection;
37+
final prompt = await server.getPrompt(
38+
GetPromptRequest(name: DashPrompts.flutterDriverUserJourneyTest.name),
39+
);
40+
expect(
41+
prompt.messages.single,
42+
isA<PromptMessage>()
43+
.having((m) => m.role, 'role', Role.user)
44+
.having(
45+
(m) => m.content,
46+
'content',
47+
equals(DashPrompts.flutterDriverUserJourneyPromptContent),
48+
),
49+
);
50+
});
51+
}

0 commit comments

Comments
 (0)