tascan-mcp 3.0.1 → 3.1.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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/tools.cjs +20 -20
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "tascan-mcp",
3
- "version": "3.0.1",
3
+ "version": "3.1.0",
4
4
  "mcpName": "io.github.snowbikemike/tascan-mcp",
5
- "description": "TaScan MCP Server — Closed-loop autonomous operations protocol. 36 tools for projects, tasks, workers, QR codes, NFC tag registry, scan verification, AI issue analysis, and autonomous remediation dispatch. 12 patents filed (335+ claims). Task. Scan. Done.",
5
+ "description": "TaScan MCP Server — Closed-loop autonomous operations protocol. 36 tools for projects, tasks, workers, QR codes, NFC tag registry, scan verification, AI issue analysis, and autonomous remediation dispatch. 14 patents filed (435+ claims). Task. Scan. Done.",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "bin": {
package/tools.cjs CHANGED
@@ -282,7 +282,9 @@ const TOOLS = [
282
282
  },
283
283
  annotations: { title: 'Dispatch to AI Agent', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
284
284
  handler: async (args, api) => {
285
- const allAgents = [...AGENT_REGISTRY, ...dynamicAgents];
285
+ let registered = [];
286
+ try { registered = (await api('GET', '/agents')).data || []; } catch (e) { /* registry unreachable — fall back to seeds */ }
287
+ const allAgents = [...AGENT_REGISTRY, ...dynamicAgents, ...registered.filter(r => !AGENT_REGISTRY.some(s => s.id === r.id))];
286
288
  const agentQuery = (args.agent || 'claude-code-local').toLowerCase();
287
289
  const agent = allAgents.find(a => a.id === agentQuery || a.name.toLowerCase() === agentQuery) || allAgents[0];
288
290
  const title = args.priority === 'urgent' ? `🔴 ${args.task}` : args.task;
@@ -299,8 +301,10 @@ const TOOLS = [
299
301
  required: []
300
302
  },
301
303
  annotations: { title: 'List AI Agents', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
302
- handler: async () => {
303
- const allAgents = [...AGENT_REGISTRY, ...dynamicAgents];
304
+ handler: async (args, api) => {
305
+ let registered = [];
306
+ try { registered = (await api('GET', '/agents')).data || []; } catch (e) { /* registry unreachable — fall back to seeds */ }
307
+ const allAgents = [...AGENT_REGISTRY, ...dynamicAgents, ...registered.filter(r => !AGENT_REGISTRY.some(s => s.id === r.id))];
304
308
  const summary = allAgents.map(a =>
305
309
  `${a.name} (${a.id})\n Type: ${a.type} | Model: ${a.model}\n Worker ID: ${a.worker_id}\n Inbox: ${a.inbox_id}\n Capabilities: ${a.capabilities.join(', ')}\n Location: ${a.location}\n Status: ${a.status}\n ${a.description}`
306
310
  ).join('\n\n');
@@ -326,26 +330,22 @@ const TOOLS = [
326
330
  required: ['id', 'name', 'type', 'inbox_id', 'capabilities']
327
331
  },
328
332
  annotations: { title: 'Register AI Agent', readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
329
- handler: async (args) => {
330
- const existing = [...AGENT_REGISTRY, ...dynamicAgents].find(a => a.id === args.id);
331
- if (existing) {
332
- Object.assign(existing, args, { status: 'active' });
333
- return `Agent "${args.name}" (${args.id}) updated in registry.\n\n${JSON.stringify(existing, null, 2)}`;
334
- }
335
- const agent = {
333
+ handler: async (args, api) => {
334
+ // Durable registration (Patent 10 Cl. 2): persists to the agent_registry
335
+ // table via the API — survives cold starts and spans both transports
336
+ const result = await api('POST', '/agents', {
336
337
  id: args.id,
337
338
  name: args.name,
338
339
  type: args.type,
339
- model: args.model || 'unknown',
340
- worker_id: args.worker_id || 'unassigned',
340
+ model: args.model,
341
+ worker_id: args.worker_id,
341
342
  inbox_id: args.inbox_id,
342
- capabilities: args.capabilities || ['DEFAULT'],
343
- location: args.location || 'unknown',
344
- status: 'active',
345
- description: args.description || `${args.name} agent`
346
- };
347
- dynamicAgents.push(agent);
348
- return `Agent "${args.name}" registered!\n\nID: ${agent.id}\nInbox: ${agent.inbox_id}\nCapabilities: ${agent.capabilities.join(', ')}\nStatus: active\n\nUse tascan_dispatch_to_agent with agent="${agent.id}" to send tasks.\n\n${JSON.stringify(agent, null, 2)}`;
343
+ capabilities: args.capabilities,
344
+ location: args.location,
345
+ description: args.description
346
+ });
347
+ const agent = result.data;
348
+ return `Agent "${agent.name}" registered (durable)!\n\nID: ${agent.id}\nInbox: ${agent.inbox_id}\nCapabilities: ${agent.capabilities.join(', ')}\nStatus: ${agent.status}\n\nUse tascan_dispatch_to_agent with agent="${agent.id}" to send tasks.\n\n${JSON.stringify(agent, null, 2)}`;
349
349
  }
350
350
  },
351
351
  {
@@ -776,7 +776,7 @@ const TOOLS = [
776
776
  text += `--- ANALYSIS ---\n`;
777
777
  text += `Summary: ${d.analysis?.summary || 'N/A'}\n`;
778
778
  text += `Classification: ${d.analysis?.classification?.type || 'N/A'} (${d.analysis?.classification?.severity || 'N/A'})\n`;
779
- text += `Urgency: ${d.analysis?.urgency_score || 'N/A'}/10\n`;
779
+ text += `Urgency: ${d.analysis?.urgency_score ?? 'N/A'}/100\n`;
780
780
  if (d.analysis?.root_cause_hypotheses?.length) {
781
781
  text += `Root Causes:\n`;
782
782
  d.analysis.root_cause_hypotheses.forEach((h, i) => {