@myvillage/cli 1.21.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.21.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;
@@ -152,8 +168,18 @@ export async function agentLoop(agentName, { signal }) {
152
168
  mentionsFound = contextResult.mentionsCount;
153
169
 
154
170
  if (activeTask) {
155
- const taskLine = `TASK ${activeTask.id} (${activeTask.taskType}): ${activeTask.instruction || JSON.stringify(activeTask.input || {})}`;
156
- context = `${taskLine}\n\n${context}`;
171
+ // A claimed task takes over the iteration. The default monitoring
172
+ // context becomes secondary background; the instruction is the
173
+ // primary user prompt and the system prompt switches to a
174
+ // task-execution framing so the LLM doesn't drift back into
175
+ // "report on the feed" mode.
176
+ const instructionText = activeTask.instruction
177
+ || (activeTask.input ? JSON.stringify(activeTask.input, null, 2) : '');
178
+
179
+ systemPrompt = `${systemPrompt}\n\n## ACTIVE TASK MODE\nA client has assigned you a task. Your job this iteration is to execute the instruction below using your available tools. The feed context is provided only for situational awareness — do not let "no new feed activity" prevent you from carrying out the task.`;
180
+
181
+ context = `## TASK (id=${activeTask.id}, type=${activeTask.taskType})\n${instructionText}\n\n---\n\n## FEED CONTEXT (for awareness only)\n${context}`;
182
+
157
183
  logActivity(agentDir, { type: 'task_claimed', taskId: activeTask.id, taskType: activeTask.taskType });
158
184
  }
159
185
 
@@ -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() {