Skip to content

Commit e239767

Browse files
authored
add logging support to the dash client example and save server capabilites per connection (#64)
1 parent 4f44fbd commit e239767

File tree

4 files changed

+73
-22
lines changed

4 files changed

+73
-22
lines changed

pkgs/dart_mcp/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.1.1-wip
2+
3+
- Save the `ServerCapabilities` object on the `ServerConnection` class to make
4+
it easier to check the capabilities of the server.
5+
16
## 0.1.0
27

38
- Initial release, supports all major MCP functionality for both clients and

pkgs/dart_mcp/example/dash_client.dart

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,25 @@ void main(List<String> args) {
2525

2626
final parsedArgs = argParser.parse(args);
2727
final serverCommands = parsedArgs['server'] as List<String>;
28-
DashClient(serverCommands, geminiApiKey: geminiApiKey);
28+
DashClient(
29+
serverCommands,
30+
geminiApiKey: geminiApiKey,
31+
verbose: parsedArgs['verbose'] == true,
32+
);
2933
}
3034

3135
final argParser =
32-
ArgParser()..addMultiOption(
33-
'server',
34-
abbr: 's',
35-
help: 'A command to run to start an MCP server',
36-
);
36+
ArgParser()
37+
..addMultiOption(
38+
'server',
39+
abbr: 's',
40+
help: 'A command to run to start an MCP server',
41+
)
42+
..addOption(
43+
'verbose',
44+
abbr: 'v',
45+
help: 'Enables verbose logging for logs from servers.',
46+
);
3747

3848
final class DashClient extends MCPClient with RootsSupport {
3949
final StreamQueue<String> stdinQueue;
@@ -42,20 +52,24 @@ final class DashClient extends MCPClient with RootsSupport {
4252
final Map<String, ServerConnection> connectionForFunction = {};
4353
final List<gemini.Content> chatHistory = [];
4454
final gemini.GenerativeModel model;
55+
final bool verbose;
4556

46-
DashClient(this.serverCommands, {required String geminiApiKey})
47-
: model = gemini.GenerativeModel(
48-
// model: 'gemini-2.5-pro-exp-03-25',
49-
model: 'gemini-2.0-flash',
50-
apiKey: geminiApiKey,
51-
systemInstruction: systemInstructions,
52-
),
53-
stdinQueue = StreamQueue(
54-
stdin.transform(utf8.decoder).transform(const LineSplitter()),
55-
),
56-
super(
57-
ClientImplementation(name: 'Example gemini client', version: '0.1.0'),
58-
) {
57+
DashClient(
58+
this.serverCommands, {
59+
required String geminiApiKey,
60+
this.verbose = false,
61+
}) : model = gemini.GenerativeModel(
62+
// model: 'gemini-2.5-pro-exp-03-25',
63+
model: 'gemini-2.0-flash',
64+
apiKey: geminiApiKey,
65+
systemInstruction: systemInstructions,
66+
),
67+
stdinQueue = StreamQueue(
68+
stdin.transform(utf8.decoder).transform(const LineSplitter()),
69+
),
70+
super(
71+
ClientImplementation(name: 'Example gemini client', version: '0.1.0'),
72+
) {
5973
addRoot(
6074
Root(
6175
uri: Directory.current.absolute.uri.toString(),
@@ -71,6 +85,7 @@ final class DashClient extends MCPClient with RootsSupport {
7185
await _connectToServers();
7286
}
7387
await _initializeServers();
88+
_listenToLogs();
7489
final serverTools = await _listServerCapabilities();
7590

7691
// If assigned then it is used as the next input from the user
@@ -144,7 +159,7 @@ final class DashClient extends MCPClient with RootsSupport {
144159
response.writeln(content.text);
145160
case final ImageContent content when content.isImage:
146161
chatHistory.add(
147-
gemini.Content.data('image/png', base64Decode(content.data)),
162+
gemini.Content.data(content.mimeType, base64Decode(content.data)),
148163
);
149164
response.writeln('Image added to context');
150165
default:
@@ -227,6 +242,27 @@ final class DashClient extends MCPClient with RootsSupport {
227242
}
228243
}
229244

245+
/// Listens for log messages on all [serverConnections] that support logging.
246+
void _listenToLogs() {
247+
for (var connection in serverConnections) {
248+
if (connection.serverCapabilities.logging == null) {
249+
continue;
250+
}
251+
252+
connection.setLogLevel(
253+
SetLevelRequest(
254+
level: verbose ? LoggingLevel.debug : LoggingLevel.warning,
255+
),
256+
);
257+
connection.onLog.listen((event) {
258+
print(
259+
'Server Log(${event.level.name}): '
260+
'${event.logger != null ? '[${event.logger}] ' : ''}${event.data}',
261+
);
262+
});
263+
}
264+
}
265+
230266
/// Lists all the tools available the [serverConnections].
231267
Future<List<gemini.Tool>> _listServerCapabilities() async {
232268
final functions = <gemini.FunctionDeclaration>[];
@@ -321,7 +357,11 @@ final class DashChatBotServer extends MCPServer with ToolsSupport {
321357

322358
registerTool(removeImagesTool, (_) async {
323359
final oldLength = client.chatHistory.length;
324-
client.chatHistory.removeWhere((content) => content is ImageContent);
360+
// TODO: Something more robust than this, maybe just remove them by object
361+
// reference.
362+
client.chatHistory.removeWhere(
363+
(content) => content.parts.first is gemini.DataPart,
364+
);
325365
return CallToolResult(
326366
content: [
327367
TextContent(

pkgs/dart_mcp/lib/src/client/client.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ base class ServerConnection extends MCPBase {
112112
/// Only assigned after [initialize] has successfully completed.
113113
late ServerImplementation serverInfo;
114114

115+
/// The [ServerCapabilities] returned from the [initialize] request.
116+
///
117+
/// Only assigned after [initialize] has successfully completed.
118+
late ServerCapabilities serverCapabilities;
119+
115120
/// Emits an event any time the server notifies us of a change to the list of
116121
/// prompts it supports.
117122
///
@@ -240,6 +245,7 @@ base class ServerConnection extends MCPBase {
240245
request,
241246
);
242247
serverInfo = response.serverInfo;
248+
serverCapabilities = response.capabilities;
243249
return response;
244250
}
245251

pkgs/dart_mcp/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: dart_mcp
22
description: A package for making MCP servers and clients.
33
repository: https://github.com/dart-lang/ai/tree/main/pkgs/dart_mcp
4-
version: 0.1.0
4+
version: 0.1.1-wip
55
environment:
66
sdk: ^3.7.0
77
dependencies:

0 commit comments

Comments
 (0)