mcp-coordinator 0.5.0 → 0.6.1

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.
@@ -54,15 +54,15 @@ export class ImpactScorer {
54
54
  if (params.target_symbols && params.target_symbols.length > 0 && params.target_files.length > 0) {
55
55
  const db = getDb();
56
56
  const placeholders = params.target_files.map(() => "?").join(",");
57
- const rows = db.prepare(`SELECT agent_id, file_path, symbols_touched
58
- FROM file_activity
59
- WHERE file_path IN (${placeholders})
60
- AND symbols_touched IS NOT NULL
61
- AND id IN (
62
- SELECT MAX(id) FROM file_activity
63
- WHERE file_path IN (${placeholders})
64
- AND symbols_touched IS NOT NULL
65
- GROUP BY agent_id, file_path
57
+ const rows = db.prepare(`SELECT agent_id, file_path, symbols_touched
58
+ FROM file_activity
59
+ WHERE file_path IN (${placeholders})
60
+ AND symbols_touched IS NOT NULL
61
+ AND id IN (
62
+ SELECT MAX(id) FROM file_activity
63
+ WHERE file_path IN (${placeholders})
64
+ AND symbols_touched IS NOT NULL
65
+ GROUP BY agent_id, file_path
66
66
  )`).all(...params.target_files, ...params.target_files);
67
67
  symbolsByFileAgent = new Map();
68
68
  for (const r of rows) {
@@ -182,7 +182,7 @@ export class ImpactScorer {
182
182
  // touched the partner file, apply the co-change score.
183
183
  const db = getDb();
184
184
  for (const targetFile of params.target_files) {
185
- const rows = db.prepare(`SELECT file_a, file_b, count, total_commits FROM git_cochange
185
+ const rows = db.prepare(`SELECT file_a, file_b, count, total_commits FROM git_cochange
186
186
  WHERE file_a = ? OR file_b = ?`).all(targetFile, targetFile);
187
187
  for (const r of rows) {
188
188
  const partner = r.file_a === targetFile ? r.file_b : r.file_a;
@@ -195,9 +195,9 @@ export class ImpactScorer {
195
195
  if (layer4Score === 0)
196
196
  continue;
197
197
  // Did the OTHER agent touch the partner file recently?
198
- const partnerActivity = db.prepare(`SELECT 1 FROM file_activity
199
- WHERE file_path = ? AND agent_id = ?
200
- AND created_at > datetime('now', '-60 minutes')
198
+ const partnerActivity = db.prepare(`SELECT 1 FROM file_activity
199
+ WHERE file_path = ? AND agent_id = ?
200
+ AND created_at > datetime('now', '-60 minutes')
201
201
  LIMIT 1`).get(partner, agent.id);
202
202
  if (partnerActivity) {
203
203
  maxScore = Math.max(maxScore, layer4Score);
@@ -224,8 +224,8 @@ export class ImpactScorer {
224
224
  }
225
225
  getRecentSymbolsForFile(filePath, agentId) {
226
226
  const db = getDb();
227
- const row = db.prepare(`SELECT symbols_touched FROM file_activity
228
- WHERE agent_id = ? AND file_path = ? AND symbols_touched IS NOT NULL
227
+ const row = db.prepare(`SELECT symbols_touched FROM file_activity
228
+ WHERE agent_id = ? AND file_path = ? AND symbols_touched IS NOT NULL
229
229
  ORDER BY id DESC LIMIT 1`).get(agentId, filePath);
230
230
  if (!row || !row.symbols_touched)
231
231
  return null;
@@ -4,7 +4,7 @@ export class IntrospectionManager {
4
4
  create(params) {
5
5
  const db = getDb();
6
6
  const id = randomUUID();
7
- db.prepare(`INSERT INTO introspections (id, thread_id, agent_id, score, reasons)
7
+ db.prepare(`INSERT INTO introspections (id, thread_id, agent_id, score, reasons)
8
8
  VALUES (?, ?, ?, ?, ?)`).run(id, params.thread_id, params.agent_id, params.score, JSON.stringify(params.reasons));
9
9
  return this.get(id);
10
10
  }
@@ -25,9 +25,9 @@ export function registerConsultationTools(server, services, mcpLog) {
25
25
  subject: z.string(),
26
26
  plan: z.string().optional(),
27
27
  target_modules: z.array(z.string()),
28
- target_files: z.array(z.string()),
29
- depends_on_files: z.array(z.string()).optional(),
30
- exports_affected: z.array(z.string()).optional(),
28
+ target_files: z.array(z.string()).describe("Repo-relative file paths (forward-slash, e.g. 'src/foo.ts'). Absolute paths are not accepted in team-mode."),
29
+ depends_on_files: z.array(z.string()).optional().describe("Repo-relative file paths your work depends on."),
30
+ exports_affected: z.array(z.string()).optional().describe("Repo-relative file paths whose exports your work modifies."),
31
31
  keep_open: z.boolean().optional().describe("Keep thread open even if no agents are concerned (for manual coordination like games or debates)"),
32
32
  assigned_to: z.string().optional().describe("Directed-dispatch: only this agent_id will be allowed to claim the thread. Use for lead→worker handoffs in maitre/chaine/relais presets. Implies keep_open=true."),
33
33
  target_symbols: z.array(z.string().max(256)).max(200).optional()
@@ -162,7 +162,7 @@ export function registerConsultationTools(server, services, mcpLog) {
162
162
  server.tool("log_action_summary", "Log a one-liner summary of an action", {
163
163
  session_id: z.string(),
164
164
  agent_id: z.string(),
165
- file_path: z.string().optional(),
165
+ file_path: z.string().optional().describe("Repo-relative file path."),
166
166
  summary: z.string(),
167
167
  }, async ({ session_id, agent_id, file_path, summary }) => {
168
168
  const result = consultation.logActionSummary({ session_id, agent_id, file_path, summary });
@@ -18,7 +18,7 @@ export function registerFilesTools(server, services, _mcpLog) {
18
18
  return { content: [{ type: "text", text: JSON.stringify(files) }] };
19
19
  });
20
20
  server.tool("check_file_conflict", "Check if another agent is editing a file", {
21
- file_path: z.string(),
21
+ file_path: z.string().describe("Repo-relative file path."),
22
22
  agent_id: z.string(),
23
23
  within_minutes: z.number().optional(),
24
24
  }, async ({ file_path, agent_id, within_minutes }) => {
@@ -28,10 +28,10 @@ export class WorkingFilesTracker {
28
28
  const db = getDb();
29
29
  const existing = db.prepare("SELECT 1 FROM working_files WHERE agent_id = ? AND file_path = ?")
30
30
  .get(agentId, filePath);
31
- db.prepare(`INSERT INTO working_files (agent_id, file_path, started_at, last_activity_at, claim_until)
32
- VALUES (?, ?, strftime('%Y-%m-%dT%H:%M:%SZ', 'now'), strftime('%Y-%m-%dT%H:%M:%SZ', 'now'), strftime('%Y-%m-%dT%H:%M:%SZ', 'now', '+' || CAST(? AS TEXT) || ' minutes'))
33
- ON CONFLICT(agent_id, file_path) DO UPDATE SET
34
- last_activity_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now'),
31
+ db.prepare(`INSERT INTO working_files (agent_id, file_path, started_at, last_activity_at, claim_until)
32
+ VALUES (?, ?, strftime('%Y-%m-%dT%H:%M:%SZ', 'now'), strftime('%Y-%m-%dT%H:%M:%SZ', 'now'), strftime('%Y-%m-%dT%H:%M:%SZ', 'now', '+' || CAST(? AS TEXT) || ' minutes'))
33
+ ON CONFLICT(agent_id, file_path) DO UPDATE SET
34
+ last_activity_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now'),
35
35
  claim_until = strftime('%Y-%m-%dT%H:%M:%SZ', 'now', '+' || CAST(? AS TEXT) || ' minutes')`).run(agentId, filePath, ttlMinutes, ttlMinutes);
36
36
  this.metrics?.workingFilesStarts.inc({ result: existing ? "updated" : "inserted" });
37
37
  }
@@ -94,9 +94,9 @@ export class WorkingFilesTracker {
94
94
  return index;
95
95
  const db = getDb();
96
96
  const placeholders = filePaths.map(() => "?").join(",");
97
- const rows = db.prepare(`SELECT DISTINCT file_path, agent_id FROM working_files
98
- WHERE file_path IN (${placeholders})
99
- AND agent_id != ?
97
+ const rows = db.prepare(`SELECT DISTINCT file_path, agent_id FROM working_files
98
+ WHERE file_path IN (${placeholders})
99
+ AND agent_id != ?
100
100
  AND claim_until > strftime('%Y-%m-%dT%H:%M:%SZ', 'now')`).all(...filePaths, excludeAgentId);
101
101
  for (const r of rows) {
102
102
  let set = index.get(r.file_path);
package/package.json CHANGED
@@ -1,100 +1,103 @@
1
- {
2
- "name": "mcp-coordinator",
3
- "version": "0.5.0",
4
- "mcpName": "io.github.swoofer/mcp-coordinator",
5
- "description": "Embedded MQTT broker + MCP server for multi-agent coordination",
6
- "type": "module",
7
- "license": "MIT",
8
- "author": "Maxime Gagnon",
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/swoofer/mcp-coordinator.git"
12
- },
13
- "homepage": "https://swoofer.github.io/mcp-coordinator",
14
- "bugs": {
15
- "url": "https://github.com/swoofer/mcp-coordinator/issues"
16
- },
17
- "keywords": [
18
- "mcp",
19
- "mqtt",
20
- "broker",
21
- "multi-agent",
22
- "coordination",
23
- "claude",
24
- "anthropic"
25
- ],
26
- "main": "./dist/src/index.js",
27
- "types": "./dist/src/index.d.ts",
28
- "exports": {
29
- ".": {
30
- "types": "./dist/src/index.d.ts",
31
- "default": "./dist/src/index.js"
32
- },
33
- "./types": {
34
- "types": "./dist/src/types.d.ts",
35
- "default": "./dist/src/types.js"
36
- }
37
- },
38
- "bin": {
39
- "mcp-coordinator": "./dist/cli/index.js"
40
- },
41
- "files": [
42
- "dist/src/",
43
- "dist/cli/",
44
- "dashboard/",
45
- "LICENSE",
46
- "README.md"
47
- ],
48
- "scripts": {
49
- "build": "tsc",
50
- "test": "vitest run",
51
- "test:watch": "vitest",
52
- "cli": "tsx cli/index.ts",
53
- "start": "node dist/src/serve-http.js",
54
- "dev": "tsx src/serve-http.ts",
55
- "dev:stdio": "tsx src/index.ts",
56
- "prepublishOnly": "npm run build && npm test"
57
- },
58
- "dependencies": {
59
- "@modelcontextprotocol/sdk": "^1.12.0",
60
- "aedes": "^1.0.2",
61
- "better-sqlite3": "^12.8.0",
62
- "commander": "^14.0.3",
63
- "jose": "^6.2.2",
64
- "mqtt": "^5.15.0",
65
- "pino": "^10.3.1",
66
- "prom-client": "^15.1.3",
67
- "tar": "^7.4.3",
68
- "ws": "^8.20.0",
69
- "zod": "^3.23.0"
70
- },
71
- "devDependencies": {
72
- "@types/better-sqlite3": "^7.6.13",
73
- "@types/node": "^22.0.0",
74
- "@types/ws": "^8.18.1",
75
- "pino-pretty": "^13.1.3",
76
- "tsx": "^4.19.0",
77
- "typescript": "^5.7.0",
78
- "vitest": "^4.1.0"
79
- },
80
- "optionalDependencies": {
81
- "tree-sitter": "^0.21.1",
82
- "tree-sitter-typescript": "^0.21.2",
83
- "tree-sitter-javascript": "^0.21.4",
84
- "tree-sitter-python": "^0.21.0",
85
- "tree-sitter-go": "^0.21.0",
86
- "tree-sitter-rust": "^0.21.2",
87
- "tree-sitter-java": "^0.21.0",
88
- "tree-sitter-c-sharp": "^0.21.3",
89
- "tree-sitter-c": "^0.21.0",
90
- "tree-sitter-cpp": "^0.22.0",
91
- "tree-sitter-ruby": "^0.21.0",
92
- "tree-sitter-php": "^0.22.0",
93
- "tree-sitter-kotlin": "^0.3.0",
94
- "tree-sitter-swift": "^0.6.0",
95
- "tree-sitter-bash": "^0.21.0"
96
- },
97
- "engines": {
98
- "node": ">=20"
99
- }
100
- }
1
+ {
2
+ "name": "mcp-coordinator",
3
+ "version": "0.6.1",
4
+ "mcpName": "io.github.swoofer/mcp-coordinator",
5
+ "description": "Embedded MQTT broker + MCP server for multi-agent coordination",
6
+ "type": "module",
7
+ "license": "MIT",
8
+ "author": "Maxime Gagnon",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/swoofer/mcp-coordinator.git"
12
+ },
13
+ "homepage": "https://swoofer.github.io/mcp-coordinator",
14
+ "bugs": {
15
+ "url": "https://github.com/swoofer/mcp-coordinator/issues"
16
+ },
17
+ "keywords": [
18
+ "mcp",
19
+ "mqtt",
20
+ "broker",
21
+ "multi-agent",
22
+ "coordination",
23
+ "claude",
24
+ "anthropic"
25
+ ],
26
+ "main": "./dist/src/index.js",
27
+ "types": "./dist/src/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/src/index.d.ts",
31
+ "default": "./dist/src/index.js"
32
+ },
33
+ "./types": {
34
+ "types": "./dist/src/types.d.ts",
35
+ "default": "./dist/src/types.js"
36
+ }
37
+ },
38
+ "bin": {
39
+ "mcp-coordinator": "./dist/cli/index.js"
40
+ },
41
+ "files": [
42
+ "dist/src/",
43
+ "dist/cli/",
44
+ "dashboard/",
45
+ "LICENSE",
46
+ "README.md"
47
+ ],
48
+ "scripts": {
49
+ "build": "tsc",
50
+ "test": "vitest run",
51
+ "test:watch": "vitest",
52
+ "cli": "tsx cli/index.ts",
53
+ "start": "node dist/src/serve-http.js",
54
+ "dev": "tsx src/serve-http.ts",
55
+ "dev:stdio": "tsx src/index.ts",
56
+ "prepublishOnly": "npm run build && npm test"
57
+ },
58
+ "dependencies": {
59
+ "@modelcontextprotocol/sdk": "^1.12.0",
60
+ "aedes": "^1.0.2",
61
+ "better-sqlite3": "^12.8.0",
62
+ "commander": "^14.0.3",
63
+ "jose": "^6.2.2",
64
+ "mqtt": "^5.15.0",
65
+ "pino": "^10.3.1",
66
+ "prom-client": "^15.1.3",
67
+ "tar": "^7.4.3",
68
+ "ws": "^8.20.0",
69
+ "zod": "^3.23.0"
70
+ },
71
+ "devDependencies": {
72
+ "@types/better-sqlite3": "^7.6.13",
73
+ "@types/node": "^22.0.0",
74
+ "@types/ws": "^8.18.1",
75
+ "pino-pretty": "^13.1.3",
76
+ "tsx": "^4.19.0",
77
+ "typescript": "^5.7.0",
78
+ "vitest": "^4.1.0"
79
+ },
80
+ "optionalDependencies": {
81
+ "tree-sitter": "^0.21.1",
82
+ "tree-sitter-typescript": "^0.21.2",
83
+ "tree-sitter-javascript": "^0.21.4",
84
+ "tree-sitter-python": "^0.21.0",
85
+ "tree-sitter-go": "^0.21.0",
86
+ "tree-sitter-rust": "^0.21.2",
87
+ "tree-sitter-java": "^0.21.0",
88
+ "tree-sitter-c-sharp": "^0.21.3",
89
+ "tree-sitter-c": "^0.21.0",
90
+ "tree-sitter-cpp": "^0.22.0",
91
+ "tree-sitter-ruby": "^0.21.0",
92
+ "tree-sitter-php": "^0.22.0",
93
+ "tree-sitter-kotlin": "^0.3.0",
94
+ "tree-sitter-swift": "^0.6.0",
95
+ "tree-sitter-bash": "^0.21.0"
96
+ },
97
+ "overrides": {
98
+ "ip-address": "^10.2.0"
99
+ },
100
+ "engines": {
101
+ "node": ">=20"
102
+ }
103
+ }