Skip to content

add a CI check that the readme file is up-to-date #192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jul 15, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/dart_mcp_server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,16 @@ jobs:
if: ${{ matrix.flutterSdk == 'master' }}

- run: dart test

readme:
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c

- run: dart pub get
- run: dart tool/update_readme.dart
# If this fails, you need to run 'dart tool/update_readme.dart'.
- run: git diff --exit-code
47 changes: 27 additions & 20 deletions pkgs/dart_mcp_server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,34 @@ WIP. This package is still experimental and is likely to evolve quickly.

## Tools

| Tool Name | Feature Group | Description |
<!-- run 'dart tool/update_readme.dart' to update -->

<!-- generated -->

| Name | Title | Description |
| --- | --- | --- |
| `analyze_files` | `static analysis` | Analyzes the entire project for errors. |
| `signature_help` | `static_analysis` | Gets signature information for usage at a given cursor position. |
| `hover` | `static_analysis` | Gets the hover information for a given cursor position. |
| `resolve_workspace_symbol` | `static analysis` | Look up a symbol or symbols in all workspaces by name. |
| `dart_fix` | `static tool` | Runs `dart fix --apply` for the given project roots. |
| `dart_format` | `static tool` | Runs `dart format .` for the given project roots. |
| `pub` | `static tool` | Runs a `dart pub` command for the given project roots. |
| `pub_dev_search` | `package search` | Searches pub.dev for packages relevant to a given search query. |
| `get_runtime_errors` | `runtime analysis` | Retrieves the list of runtime errors that have occurred in the active Dart or Flutter application. |
| `take_screenshot` | `runtime analysis` | Takes a screenshot of the active Flutter application in its current state. |
| `get_widget_tree` | `runtime analysis` | Retrieves the widget tree from the active Flutter application. |
| `get_selected_widget` | `runtime analysis` | Retrieves the selected widget from the active Flutter application. |
| `hot_reload` | `runtime tool` | Performs a hot reload of the active Flutter application. |
| `connect_dart_tooling_daemon`* | `configuration` | Connects to the locally running Dart Tooling Daemon. |
| `get_active_location` | `editor` | Gets the active cursor position in the connected editor (if available). |
| `run_tests` | `static tool` | Runs tests for the given project roots. |
| `create_project` | `static tool` | Creates a new Dart or Flutter project. |

> *Experimental: may be removed.
| `connect_dart_tooling_daemon` | Connect to DTD | Connects to the Dart Tooling Daemon. You should get the uri either from available tools or the user, do not just make up a random URI to pass. When asking the user for the uri, you should suggest the "Copy DTD Uri to clipboard" action. When reconnecting after losing a connection, always request a new uri first. |
| `get_runtime_errors` | Get runtime errors | Retrieves the most recent runtime errors that have occurred in the active Dart or Flutter application. Requires "connect_dart_tooling_daemon" to be successfully called first. |
| `take_screenshot` | Take screenshot | Takes a screenshot of the active Flutter application in its current state. Requires "connect_dart_tooling_daemon" to be successfully called first. |
| `hot_reload` | Hot reload | Performs a hot reload of the active Flutter application. This is to apply the latest code changes to the running application. Requires "connect_dart_tooling_daemon" to be successfully called first. |
| `get_widget_tree` | Get widget tree | Retrieves the widget tree from the active Flutter application. Requires "connect_dart_tooling_daemon" to be successfully called first. |
| `get_selected_widget` | Get selected widget | Retrieves the selected widget from the active Flutter application. Requires "connect_dart_tooling_daemon" to be successfully called first. |
| `set_widget_selection_mode` | Set Widget Selection Mode | Enables or disables widget selection mode in the active Flutter application. Requires "connect_dart_tooling_daemon" to be successfully called first. |
| `get_active_location` | Get Active Editor Location | Retrieves the current active location (e.g., cursor position) in the connected editor. Requires "connect_dart_tooling_daemon" to be successfully called first. |
| `pub_dev_search` | pub.dev search | Searches pub.dev for packages relevant to a given search query. The response will describe each result with its download count, package description, topics, license, and publisher. |
| `remove_roots` | Remove roots | Removes one or more project roots previously added via the add_roots tool. |
| `add_roots` | Add roots | Adds one or more project roots. Tools are only allowed to run under these roots, so you must call this function before passing any roots to any other tools. |
| `dart_fix` | Dart fix | Runs `dart fix --apply` for the given project roots. |
| `dart_format` | Dart format | Runs `dart format .` for the given project roots. |
| `run_tests` | Run tests | Run Dart or Flutter tests with an agent centric UX. ALWAYS use instead of `dart test` or `flutter test` shell commands. |
| `create_project` | Create project | Creates a new Dart or Flutter project. |
| `pub` | pub | Runs a pub command for the given project roots, like `dart pub get` or `flutter pub add`. |
| `analyze_files` | Analyze projects | Analyzes the entire project for errors. |
| `resolve_workspace_symbol` | Project search | Look up a symbol or symbols in all workspaces by name. Can be used to validate that a symbol exists or discover small spelling mistakes, since the search is fuzzy. |
| `signature_help` | Signature help | Get signature help for an API being used at a given cursor position in a file. |
| `hover` | Hover information | Get hover information at a given cursor position in a file. This can include documentation, type information, etc for the text at that position. |

<!-- generated -->

## Usage

Expand Down
66 changes: 66 additions & 0 deletions pkgs/dart_mcp_server/tool/update_readme.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// 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:io';

import 'package:dart_mcp/client.dart';

void main(List<String> args) async {
print('Getting registered tools...');

final tools = await _retrieveRegisteredTools();

final buf = StringBuffer('''
| Name | Title | Description |
| --- | --- | --- |
''');
for (final tool in tools) {
buf.writeln('| `${tool.name}` | ${tool.title} | ${tool.description} |');
}

final readmeFile = File('README.md');
final updated = _insertBetween(
readmeFile.readAsStringSync(),
buf.toString(),
'<!-- generated -->',
);
readmeFile.writeAsStringSync(updated);

print('Wrote update tool list to ${readmeFile.path}.');
}

String _insertBetween(String original, String insertion, String marker) {
final startIndex = original.indexOf(marker) + marker.length;
final endIndex = original.lastIndexOf(marker);

return '${original.substring(0, startIndex)}\n\n'
'$insertion\n${original.substring(endIndex)}';
}

Future<List<Tool>> _retrieveRegisteredTools() async {
final client = MCPClient(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fwiw, the tools registered can vary based on the client features that are supported.

Probably, this client should claim to support all features so that all the tools show up.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at creating a subclass of an MCPClient in order to override initialize() so I could create specific client capabilities, but for whatever reason, two of the tools dropped out of the list of supported tools. For now, I kept the implementation as is - not providing an explcit list of capabilities.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What likely happened there is we swapped out some tools for their preferred alternatives (resources), due to the client indicating it has resource support.

We can land this as is though and I can eventually take a look at improving it.

Implementation(name: 'list tools client', version: '1.0.0'),
);
final server = await client.connectStdioServer('dart', [
'run',
'bin/main.dart',
]);

await server.initialize(
InitializeRequest(
protocolVersion: ProtocolVersion.latestSupported,
capabilities: client.capabilities,
clientInfo: client.implementation,
),
);
server.notifyInitialized(InitializedNotification());

final toolsResult = await server.listTools(ListToolsRequest());
await client.shutdown();
return toolsResult.tools;
}

extension on Tool {
String get title => toolAnnotations?.title ?? '';
}