@myvillage/cli 1.22.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myvillage/cli",
3
- "version": "1.22.0",
3
+ "version": "1.23.0",
4
4
  "description": "MyVillageOS CLI for community developers",
5
5
  "type": "module",
6
6
  "bin": {
@@ -66,11 +66,27 @@ export async function agentLoop(agentName, { signal }) {
66
66
  // Initialize MCP tools
67
67
  let tools;
68
68
  try {
69
- tools = await getMCPTools(agentDir, config);
69
+ const result = await getMCPTools(agentDir, config);
70
+ tools = result.tools;
71
+ const servers = result.servers;
72
+ const totalTools = Object.keys(tools).length;
73
+ const failed = servers.filter(s => s.status === 'failed');
74
+
70
75
  logActivity(agentDir, {
71
- type: 'info',
72
- message: `Agent started. Model: ${modelId}, Tools: ${Object.keys(tools).join(', ') || 'none'}`,
76
+ type: 'loaded_tools',
77
+ model: modelId,
78
+ totalTools,
79
+ servers,
73
80
  });
81
+
82
+ // Surface failed MCP connections as an error event too, so they show up
83
+ // in the activity panel's error filter — easy to miss in the success log.
84
+ if (failed.length > 0) {
85
+ logActivity(agentDir, {
86
+ type: 'error',
87
+ error: `Failed to load ${failed.length} MCP server(s): ${failed.map(s => `${s.name} (${s.error})`).join('; ')}`,
88
+ });
89
+ }
74
90
  } catch (err) {
75
91
  logActivity(agentDir, { type: 'error', error: `Failed to initialize tools: ${err.message}` });
76
92
  throw err;
@@ -20,13 +20,21 @@ export async function getMCPTools(agentDir, agentConfig) {
20
20
  }
21
21
 
22
22
  const allTools = {};
23
+ // Per-server connection status. Returned alongside `tools` so the agent
24
+ // loop can surface failed MCP connections in the activity log — without
25
+ // this, a developer whose `filesystem` MCP fails to spawn sees a silent
26
+ // agent that "refuses" file tasks and has no way to know why.
27
+ const servers = [];
23
28
 
24
29
  for (const [name, server] of Object.entries(toolsConfig.servers || {})) {
25
30
  if (server.command === 'internal') {
26
31
  // Legacy internal tools — skip (replaced by MCP server)
32
+ servers.push({ name, status: 'skipped', reason: 'legacy internal' });
27
33
  continue;
28
34
  }
29
35
 
36
+ const transport = server.url ? 'sse' : 'stdio';
37
+
30
38
  try {
31
39
  const { experimental_createMCPClient: createMCPClient } = await import('ai');
32
40
  let client;
@@ -61,14 +69,29 @@ export async function getMCPTools(agentDir, agentConfig) {
61
69
 
62
70
  activeClients.push(client);
63
71
  const tools = await client.tools();
72
+ const toolNames = Object.keys(tools);
64
73
  Object.assign(allTools, tools);
74
+ servers.push({
75
+ name,
76
+ transport,
77
+ status: 'connected',
78
+ toolCount: toolNames.length,
79
+ toolNames,
80
+ });
65
81
  } catch (err) {
66
82
  // Log but don't fail — agent can still work with other tools
67
- console.error(`[mcp-client] Failed to connect to ${name}: ${err.message}`);
83
+ const message = err?.message || String(err);
84
+ console.error(`[mcp-client] Failed to connect to ${name}: ${message}`);
85
+ servers.push({
86
+ name,
87
+ transport,
88
+ status: 'failed',
89
+ error: message,
90
+ });
68
91
  }
69
92
  }
70
93
 
71
- return allTools;
94
+ return { tools: allTools, servers };
72
95
  }
73
96
 
74
97
  export async function cleanupMCPClients() {