@@ -107,10 +107,41 @@ void main() {
107107 return (responseContent['text' ] as String ).split ('\n ' );
108108 }
109109
110+ Future <String > getSamplingServiceName (
111+ DartToolingDaemon dtdClient,
112+ ) async {
113+ final services = await dtdClient.getRegisteredServices ();
114+ final samplingService = services.clientServices.firstWhere (
115+ (s) => s.name.startsWith (McpServiceConstants .serviceName),
116+ );
117+ return samplingService.name;
118+ }
119+
120+ test ('is registered with correct name format' , () async {
121+ final dtdClient = testHarness.fakeEditorExtension.dtd;
122+ final services = await dtdClient.getRegisteredServices ();
123+ final samplingService = services.clientServices.first;
124+ final sanitizedClientName =
125+ 'test_client_for_the_dart_tooling_mcp_server' ;
126+ expect (
127+ samplingService.name,
128+ startsWith (
129+ '${McpServiceConstants .serviceName }_${sanitizedClientName }_' ,
130+ ),
131+ );
132+ // Check that the service name ends with an 8-character ID.
133+ expect (samplingService.name, matches (RegExp (r'[a-f0-9]{8}$' )));
134+ expect (
135+ samplingService.methods,
136+ contains (McpServiceConstants .samplingRequest),
137+ );
138+ });
139+
110140 test ('can make a sampling request with text' , () async {
111141 final dtdClient = testHarness.fakeEditorExtension.dtd;
142+ final samplingServiceName = await getSamplingServiceName (dtdClient);
112143 final response = await dtdClient.call (
113- McpServiceConstants .serviceName ,
144+ samplingServiceName ,
114145 McpServiceConstants .samplingRequest,
115146 params: {
116147 'messages' : [
@@ -130,8 +161,9 @@ void main() {
130161
131162 test ('can make a sampling request with an image' , () async {
132163 final dtdClient = testHarness.fakeEditorExtension.dtd;
164+ final samplingServiceName = await getSamplingServiceName (dtdClient);
133165 final response = await dtdClient.call (
134- McpServiceConstants .serviceName ,
166+ samplingServiceName ,
135167 McpServiceConstants .samplingRequest,
136168 params: {
137169 'messages' : [
@@ -155,8 +187,9 @@ void main() {
155187
156188 test ('can make a sampling request with audio' , () async {
157189 final dtdClient = testHarness.fakeEditorExtension.dtd;
190+ final samplingServiceName = await getSamplingServiceName (dtdClient);
158191 final response = await dtdClient.call (
159- McpServiceConstants .serviceName ,
192+ samplingServiceName ,
160193 McpServiceConstants .samplingRequest,
161194 params: {
162195 'messages' : [
@@ -177,8 +210,9 @@ void main() {
177210
178211 test ('can make a sampling request with an embedded resource' , () async {
179212 final dtdClient = testHarness.fakeEditorExtension.dtd;
213+ final samplingServiceName = await getSamplingServiceName (dtdClient);
180214 final response = await dtdClient.call (
181- McpServiceConstants .serviceName ,
215+ samplingServiceName ,
182216 McpServiceConstants .samplingRequest,
183217 params: {
184218 'messages' : [
@@ -201,8 +235,9 @@ void main() {
201235
202236 test ('can make a sampling request with mixed content' , () async {
203237 final dtdClient = testHarness.fakeEditorExtension.dtd;
238+ final samplingServiceName = await getSamplingServiceName (dtdClient);
204239 final response = await dtdClient.call (
205- McpServiceConstants .serviceName ,
240+ samplingServiceName ,
206241 McpServiceConstants .samplingRequest,
207242 params: {
208243 'messages' : [
@@ -231,8 +266,9 @@ void main() {
231266
232267 test ('can handle user and assistant messages' , () async {
233268 final dtdClient = testHarness.fakeEditorExtension.dtd;
269+ final samplingServiceName = await getSamplingServiceName (dtdClient);
234270 final response = await dtdClient.call (
235- McpServiceConstants .serviceName ,
271+ samplingServiceName ,
236272 McpServiceConstants .samplingRequest,
237273 params: {
238274 'messages' : [
@@ -262,8 +298,9 @@ void main() {
262298
263299 test ('forwards all messages, even those with unknown types' , () async {
264300 final dtdClient = testHarness.fakeEditorExtension.dtd;
301+ final samplingServiceName = await getSamplingServiceName (dtdClient);
265302 final response = await dtdClient.call (
266- McpServiceConstants .serviceName ,
303+ samplingServiceName ,
267304 McpServiceConstants .samplingRequest,
268305 params: {
269306 'messages' : [
@@ -285,9 +322,10 @@ void main() {
285322
286323 test ('throws for invalid requests' , () async {
287324 final dtdClient = testHarness.fakeEditorExtension.dtd;
325+ final samplingServiceName = await getSamplingServiceName (dtdClient);
288326 try {
289327 await dtdClient.call (
290- McpServiceConstants .serviceName ,
328+ samplingServiceName ,
291329 McpServiceConstants .samplingRequest,
292330 params: {
293331 'messages' : [
@@ -378,6 +416,65 @@ void main() {
378416 await testHarness.connectToDtd ();
379417 });
380418
419+ group ('generateClientId creates ID from client name' , () {
420+ test ('removes whitespaces' , () {
421+ // Single whitespace character.
422+ expect (
423+ server.generateClientId ('Example Name' ),
424+ startsWith ('example_name_' ),
425+ );
426+ // Multiple whitespace characters.
427+ expect (
428+ server.generateClientId ('Example Name' ),
429+ startsWith ('example_name_' ),
430+ );
431+ // Newline and other whitespace.
432+ expect (
433+ server.generateClientId ('Example\n\t Name' ),
434+ startsWith ('example_name_' ),
435+ );
436+ // Whitespace at the end.
437+ expect (
438+ server.generateClientId ('Example Name\n ' ),
439+ startsWith ('example_name_' ),
440+ );
441+ });
442+
443+ test ('replaces periods and dashes with underscores' , () {
444+ // Replaces periods.
445+ expect (
446+ server.generateClientId ('Example.Client.Name' ),
447+ startsWith ('example_client_name_' ),
448+ );
449+ // Replaces dashes.
450+ expect (
451+ server.generateClientId ('example-client-name' ),
452+ startsWith ('example_client_name_' ),
453+ );
454+ });
455+
456+ test ('removes special characters' , () {
457+ expect (
458+ server.generateClientId ('Example!@#Client\$ %^Name' ),
459+ startsWith ('exampleclientname_' ),
460+ );
461+ });
462+
463+ test ('handles a mix of sanitization rules' , () {
464+ expect (
465+ server.generateClientId (' Example Client.Name!@# ' ),
466+ startsWith ('example_client_name_' ),
467+ );
468+ });
469+
470+ test ('ends with an 8-character uuid' , () {
471+ expect (
472+ server.generateClientId ('Example name' ),
473+ matches (RegExp (r'[a-f0-9]{8}$' )),
474+ );
475+ });
476+ });
477+
381478 group ('$VmService management' , () {
382479 late Directory appDir;
383480 final appPath = 'bin/main.dart' ;
0 commit comments