don't bail early when running in multiple roots (#218)

Previously if a tool was ran in multiple roots and one of them failed, it would immediately return with just that failure output.
diff --git a/pkgs/dart_mcp_server/CHANGELOG.md b/pkgs/dart_mcp_server/CHANGELOG.md
index 4b9e419..9ae564a 100644
--- a/pkgs/dart_mcp_server/CHANGELOG.md
+++ b/pkgs/dart_mcp_server/CHANGELOG.md
@@ -1,4 +1,9 @@
-# 0.1.0 (Dart SDK 3.8.0) - WP
+# 0.1.1 (Dart SDK 3.10.0) - WIP
+
+* Change tools that accept multiple roots to not return immediately on the first
+  failure.
+
+# 0.1.0 (Dart SDK 3.9.0)
 
 * Add documentation/homepage/repository links to pub results.
 * Handle relative paths under roots without trailing slashes.
diff --git a/pkgs/dart_mcp_server/lib/src/server.dart b/pkgs/dart_mcp_server/lib/src/server.dart
index b874182..27374ed 100644
--- a/pkgs/dart_mcp_server/lib/src/server.dart
+++ b/pkgs/dart_mcp_server/lib/src/server.dart
@@ -58,7 +58,7 @@
   }) : super.fromStreamChannel(
          implementation: Implementation(
            name: 'dart and flutter tooling',
-           version: '0.1.0',
+           version: '0.1.1',
          ),
          instructions:
              'This server helps to connect Dart and Flutter developers to '
diff --git a/pkgs/dart_mcp_server/lib/src/utils/cli_utils.dart b/pkgs/dart_mcp_server/lib/src/utils/cli_utils.dart
index 593627d..af74733 100644
--- a/pkgs/dart_mcp_server/lib/src/utils/cli_utils.dart
+++ b/pkgs/dart_mcp_server/lib/src/utils/cli_utils.dart
@@ -96,6 +96,7 @@
   }
 
   final outputs = <Content>[];
+  var isError = false;
   for (var rootConfig in rootConfigs) {
     final result = await runCommandInRoot(
       request,
@@ -109,10 +110,10 @@
       defaultPaths: defaultPaths,
       sdk: sdk,
     );
-    if (result.isError == true) return result;
+    isError = isError || result.isError == true;
     outputs.addAll(result.content);
   }
-  return CallToolResult(content: outputs);
+  return CallToolResult(content: outputs, isError: isError);
 }
 
 /// Runs [commandForRoot] in a single project root specified in the
@@ -233,7 +234,7 @@
         TextContent(
           text:
               '$commandDescription failed in ${projectRoot.path}:\n'
-              '$output\n\nErrors\n$errors',
+              '$output${errors.isEmpty ? '' : '\nErrors:\n$errors'}',
         ),
       ],
       isError: true,
diff --git a/pkgs/dart_mcp_server/test/utils/cli_utils_test.dart b/pkgs/dart_mcp_server/test/utils/cli_utils_test.dart
index 0ee5168..b38f092 100644
--- a/pkgs/dart_mcp_server/test/utils/cli_utils_test.dart
+++ b/pkgs/dart_mcp_server/test/utils/cli_utils_test.dart
@@ -195,39 +195,49 @@
   });
 
   group('cannot run commands', () {
-    final processManager = FakeProcessManager();
-
     test('with roots outside of known roots', () async {
-      for (var invalidRoot in ['file:///bar/', 'file:///foo/../bar/']) {
-        final result = await runCommandInRoots(
-          CallToolRequest(
-            name: 'foo',
-            arguments: {
-              ParameterNames.roots: [
-                {ParameterNames.root: invalidRoot},
-              ],
-            },
-          ),
-          commandForRoot: (_, _, _) => 'fake',
-          commandDescription: '',
-          processManager: processManager,
-          knownRoots: [Root(uri: 'file:///foo/')],
-          fileSystem: fileSystem,
-          sdk: Sdk(),
-        );
-        expect(result.isError, isTrue);
-        expect(
-          result.content.single,
-          isA<TextContent>().having(
-            (t) => t.text,
-            'text',
-            allOf(contains('Invalid root $invalidRoot')),
-          ),
-        );
-      }
+      final processManager = TestProcessManager();
+      final invalidRoots = ['file:///bar/', 'file:///foo/../bar/'];
+      final allRoots = ['file:///foo/', ...invalidRoots];
+      final result = await runCommandInRoots(
+        CallToolRequest(
+          name: 'foo',
+          arguments: {
+            ParameterNames.roots: [
+              for (var root in allRoots) {ParameterNames.root: root},
+            ],
+          },
+        ),
+        commandForRoot: (_, _, _) => 'testProcess',
+        commandDescription: 'Test process',
+        processManager: processManager,
+        knownRoots: [Root(uri: 'file:///foo/')],
+        fileSystem: fileSystem,
+        sdk: Sdk(),
+      );
+      expect(result.isError, isTrue);
+      expect(
+        result.content,
+        unorderedEquals([
+          for (var root in invalidRoots)
+            isA<TextContent>().having(
+              (t) => t.text,
+              'text',
+              contains('Invalid root $root'),
+            ),
+          for (var root in allRoots)
+            if (!invalidRoots.contains(root))
+              isA<TextContent>().having(
+                (t) => t.text,
+                'text',
+                allOf(contains('Test process'), contains(Uri.parse(root).path)),
+              ),
+        ]),
+      );
     });
 
     test('with paths outside of known roots', () async {
+      final processManager = FakeProcessManager();
       final result = await runCommandInRoots(
         CallToolRequest(
           name: 'foo',