agent-comm-hub 0.1.6
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/LICENSE +21 -0
- package/README.md +353 -0
- package/README.zh.md +243 -0
- package/agents/README.md +49 -0
- package/agents/SKILL.md +62 -0
- package/agents/claude-code/.mcp.json +8 -0
- package/agents/codex/config.toml +3 -0
- package/agents/dsh/cordis.patch.yml +7 -0
- package/agents/gemini-cli/settings.json +8 -0
- package/agents/install-all.ps1 +177 -0
- package/agents/kimi-code/mcp-entry.json +10 -0
- package/agents/minimax-code/SKILL.md +62 -0
- package/agents/minimax-code/install-mcode.ps1 +121 -0
- package/agents/minimax-code/mcp-entry.json +10 -0
- package/agents/opencode/opencode.json +9 -0
- package/assets/agent-hub-banner-cn.png +0 -0
- package/assets/agent-hub-banner.png +0 -0
- package/lib/cli.js +1239 -0
- package/lib/index.js +798 -0
- package/lib/setup.js +168 -0
- package/package.json +46 -0
package/agents/SKILL.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-comm-hub
|
|
3
|
+
description:
|
|
4
|
+
Real-time two-way communication with other AI agents connected to the local
|
|
5
|
+
agent-comm-hub. Use when the user mentions another agent, the hub, group
|
|
6
|
+
chat, sending messages or tasks to another agent, waiting for another
|
|
7
|
+
agent's reply, or forwarding results between agents. Tools:
|
|
8
|
+
bridge_register / bridge_chat / bridge_task / bridge_ack / bridge_wait /
|
|
9
|
+
bridge_poll / bridge_status / bridge_peers / bridge_history.
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# agent-comm-hub usage
|
|
13
|
+
|
|
14
|
+
A local hub (`agent-comm-hub` on 127.0.0.1:18764) connects this agent with
|
|
15
|
+
every other MCP-capable agent on this machine (MiniMax Code, opencode, Kimi
|
|
16
|
+
Code, Claude Code, DeepSeek Harness, …).
|
|
17
|
+
|
|
18
|
+
**You are already registered**: connecting to the hub auto-registers you at
|
|
19
|
+
the MCP handshake using your client name — no manual step needed. Same-name
|
|
20
|
+
connections share one peer id, so your identity is stable across sessions.
|
|
21
|
+
Optional: call `bridge_register(peerId)` to claim a readable id
|
|
22
|
+
(`tool:project`, e.g. `claude-code:myproject`; errors when taken).
|
|
23
|
+
|
|
24
|
+
## Tools
|
|
25
|
+
|
|
26
|
+
- `bridge_chat(to, message)` — send a chat message to a peer; `to: "all"`
|
|
27
|
+
broadcasts.
|
|
28
|
+
- `bridge_task(to, prompt, context?, deliverable?)` — delegate a structured
|
|
29
|
+
task.
|
|
30
|
+
- `bridge_ack(ref, status, note?)` — acknowledge a task
|
|
31
|
+
(`accepted`/`rejected`/`done`/`failed`), auto-routed back to the original
|
|
32
|
+
sender.
|
|
33
|
+
- `bridge_wait(from?, timeoutMs?)` — long-poll for the next message (default
|
|
34
|
+
30 s; loop it to hold a real-time conversation).
|
|
35
|
+
- `bridge_poll(from?)` — non-blocking drain of every queued message.
|
|
36
|
+
- `bridge_status()` / `bridge_peers()` — hub health and who is online.
|
|
37
|
+
- `bridge_history(peer?, limit?)` — recent messages (newest first).
|
|
38
|
+
|
|
39
|
+
## When to use
|
|
40
|
+
|
|
41
|
+
1. The user mentions "another agent / the hub / over there" pointing at a
|
|
42
|
+
different agent — use the bridge tools.
|
|
43
|
+
2. **Before messaging a specific agent, call `bridge_peers()` first and use
|
|
44
|
+
its exact peerId.** If the target is not listed, it is not connected yet —
|
|
45
|
+
do NOT guess a peerId or send blindly; tell the user the other agent needs
|
|
46
|
+
to be running (it registers automatically on connect).
|
|
47
|
+
3. Receiving: try `bridge_poll()` first; if empty, loop `bridge_wait()` until
|
|
48
|
+
a message arrives or you give up.
|
|
49
|
+
4. On receiving a `task` (content is `{prompt, context?, deliverable?}`):
|
|
50
|
+
acknowledge with `bridge_ack(ref, "accepted")` when you take it on, then
|
|
51
|
+
`bridge_ack(ref, "done"[, note])` when finished; use `"rejected"` to
|
|
52
|
+
decline and `"failed"` when it could not be completed (always with a note).
|
|
53
|
+
5. Unsure whether the peer is online: check `bridge_peers()` first.
|
|
54
|
+
|
|
55
|
+
## Notes
|
|
56
|
+
|
|
57
|
+
- Messages travel on loopback only (127.0.0.1:18764); never put credentials
|
|
58
|
+
in bridge messages.
|
|
59
|
+
- A timeout is not a failure: `bridge_wait` returning `{type:"timeout"}` just
|
|
60
|
+
means nothing arrived — try again.
|
|
61
|
+
- Cadence: use 10–30 s short polls when the peer is active; check
|
|
62
|
+
`bridge_peers()` when unsure.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Sync the agent-comm-hub MCP entry into every installed agent's own config —
|
|
4
|
+
incrementally. Only the "agent-hub" server key is added/updated; all other
|
|
5
|
+
content is preserved byte-for-byte semantically, each file is backed up first,
|
|
6
|
+
and re-running is a no-op. -Remove undoes everything.
|
|
7
|
+
|
|
8
|
+
Covered agents (auto-skipped when not installed):
|
|
9
|
+
- MiniMax Code (mcode) ~/.minimax/mcp.json + ~/.minimax/mcp/mcp.json
|
|
10
|
+
- opencode ~/.config/opencode/opencode.json
|
|
11
|
+
- Kimi Code ~/.kimi-code/mcp.json
|
|
12
|
+
- Gemini CLI ~/.gemini/settings.json
|
|
13
|
+
- Codex ~/.codex/config.toml (appends the section if missing)
|
|
14
|
+
|
|
15
|
+
Not covered (manual, documented in agents/README.md):
|
|
16
|
+
- Claude Code -> project-level .mcp.json (copy agents/claude-code/.mcp.json)
|
|
17
|
+
(~/.claude.json is not touched: it carries credentials and
|
|
18
|
+
cannot be round-tripped safely)
|
|
19
|
+
- DSH -> merge agents/dsh/cordis.patch.yml into the profile patch
|
|
20
|
+
|
|
21
|
+
.EXAMPLE
|
|
22
|
+
powershell -ExecutionPolicy Bypass -File install-all.ps1
|
|
23
|
+
powershell -ExecutionPolicy Bypass -File install-all.ps1 -Remove
|
|
24
|
+
#>
|
|
25
|
+
param(
|
|
26
|
+
[string]$Url = 'http://127.0.0.1:18764/mcp',
|
|
27
|
+
[string]$ServerName = 'agent-hub',
|
|
28
|
+
[switch]$Remove
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
$ErrorActionPreference = 'Stop'
|
|
32
|
+
$userHome = $env:USERPROFILE
|
|
33
|
+
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
|
|
34
|
+
$skillSrc = Join-Path $PSScriptRoot 'SKILL.md'
|
|
35
|
+
|
|
36
|
+
function Write-Step($text) { Write-Host "[agent-comm-hub] $text" -ForegroundColor Cyan }
|
|
37
|
+
|
|
38
|
+
function Read-Json($path) {
|
|
39
|
+
if (-not (Test-Path $path)) { return $null }
|
|
40
|
+
try { return [System.IO.File]::ReadAllText($path, [System.Text.Encoding]::UTF8) | ConvertFrom-Json }
|
|
41
|
+
catch { throw "cannot parse JSON: $path ($($_.Exception.Message))" }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function Write-JsonNoBom($path, $value) {
|
|
45
|
+
$dir = Split-Path $path
|
|
46
|
+
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
|
|
47
|
+
[System.IO.File]::WriteAllText($path, ($value | ConvertTo-Json -Depth 50), $utf8NoBom)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function Backup($path) {
|
|
51
|
+
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
|
52
|
+
Copy-Item $path "$path.bak-$stamp" -Force -ErrorAction SilentlyContinue
|
|
53
|
+
return "$(Split-Path $path -Leaf).bak-$stamp"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function Sync-Skill($agentName, $skillDir) {
|
|
57
|
+
if ($Remove) {
|
|
58
|
+
if (Test-Path $skillDir) { Remove-Item $skillDir -Recurse -Force; Write-Step " ${agentName}: removed skill $skillDir" }
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
if (-not (Test-Path $skillSrc)) { Write-Step " ${agentName}: SKILL.md source missing (skipped)"; return }
|
|
62
|
+
New-Item -ItemType Directory -Path $skillDir -Force | Out-Null
|
|
63
|
+
Copy-Item $skillSrc (Join-Path $skillDir 'SKILL.md') -Force
|
|
64
|
+
Write-Step " ${agentName}: skill -> $skillDir\SKILL.md"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function Merge-JsonServer($label, $file, $sectionName, $entry) {
|
|
68
|
+
if (-not (Test-Path $file)) { Write-Step " ${label}: not installed ($file missing, skipped)"; return }
|
|
69
|
+
try {
|
|
70
|
+
$doc = Read-Json $file
|
|
71
|
+
if ($null -eq $doc) { Write-Step " ${label}: empty config (skipped)"; return }
|
|
72
|
+
$servers = $doc.$sectionName
|
|
73
|
+
if ($null -eq $servers) {
|
|
74
|
+
# Incremental: create only the missing section, keep the rest untouched.
|
|
75
|
+
$servers = [ordered]@{}
|
|
76
|
+
$doc | Add-Member -NotePropertyName $sectionName -NotePropertyValue $servers -Force
|
|
77
|
+
}
|
|
78
|
+
$changed = $false
|
|
79
|
+
if ($servers.PSObject.Properties.Name -contains $ServerName) {
|
|
80
|
+
$existing = $servers.$ServerName
|
|
81
|
+
$changed = ($existing.url -ne ${Url})
|
|
82
|
+
} else {
|
|
83
|
+
$changed = $true
|
|
84
|
+
}
|
|
85
|
+
if ($Remove) {
|
|
86
|
+
if ($servers.PSObject.Properties.Name -contains $ServerName) {
|
|
87
|
+
$servers.PSObject.Properties.Remove($ServerName)
|
|
88
|
+
$bak = Backup $file
|
|
89
|
+
Write-JsonNoBom $file $doc
|
|
90
|
+
Write-Step " ${label}: removed '$ServerName' from $file (backup: $bak)"
|
|
91
|
+
} else {
|
|
92
|
+
Write-Step " ${label}: '$ServerName' not present in $file"
|
|
93
|
+
}
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
if (-not $changed) { Write-Step " ${label}: '$ServerName' already set -> ${Url} ($file unchanged)"; return }
|
|
97
|
+
$bak = Backup $file
|
|
98
|
+
$servers | Add-Member -NotePropertyName $ServerName -NotePropertyValue $entry -Force
|
|
99
|
+
Write-JsonNoBom $file $doc
|
|
100
|
+
Write-Step " ${label}: merged '$ServerName' -> ${Url} into $file (backup: $bak)"
|
|
101
|
+
} catch {
|
|
102
|
+
Write-Step " ${label}: SKIPPED — $($_.Exception.Message)"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if ($Remove) { Write-Step 'uninstalling from all agents...' } else { Write-Step "syncing '$ServerName' -> $Url to all agents..." }
|
|
107
|
+
|
|
108
|
+
# ---------- MiniMax Code (mcode): mcpServers at root of ~/.minimax/mcp.json + ~/.minimax/mcp/mcp.json
|
|
109
|
+
$mcodeEntry = [ordered]@{
|
|
110
|
+
url = $Url; type = 'streamable-http'; enabled = $true; configured = $true; timeout = 120000
|
|
111
|
+
description = 'agent-comm-hub: talk to every other agent connected to the hub (bridge_register auto, bridge_chat/task/ack/wait/poll/status/peers/history).'
|
|
112
|
+
}
|
|
113
|
+
Write-Step '- mcode'
|
|
114
|
+
foreach ($f in @((Join-Path $userHome '.minimax\mcp.json'), (Join-Path $userHome '.minimax\mcp\mcp.json'))) {
|
|
115
|
+
Merge-JsonServer 'mcode' $f 'mcpServers' $mcodeEntry
|
|
116
|
+
}
|
|
117
|
+
Sync-Skill 'mcode' (Join-Path $userHome '.minimax\skills\agent-comm-hub')
|
|
118
|
+
|
|
119
|
+
# ---------- opencode: mcp.<name> in ~/.config/opencode/opencode.json
|
|
120
|
+
$opencodeEntry = [ordered]@{ type = 'remote'; url = $Url; enabled = $true }
|
|
121
|
+
Write-Step '- opencode'
|
|
122
|
+
Merge-JsonServer 'opencode' (Join-Path $userHome '.config\opencode\opencode.json') 'mcp' $opencodeEntry
|
|
123
|
+
Sync-Skill 'opencode' (Join-Path $userHome '.config\opencode\skills\agent-comm-hub')
|
|
124
|
+
|
|
125
|
+
# ---------- Kimi Code: mcpServers at root of ~/.kimi-code/mcp.json
|
|
126
|
+
$kimiEntry = [ordered]@{ transport = 'http'; url = $Url; startupTimeoutMs = 30000; toolTimeoutMs = 120000 }
|
|
127
|
+
Write-Step '- kimi-code'
|
|
128
|
+
Merge-JsonServer 'kimi-code' (Join-Path $userHome '.kimi-code\mcp.json') 'mcpServers' $kimiEntry
|
|
129
|
+
Sync-Skill 'kimi-code' (Join-Path $userHome '.kimi-code\skills\agent-comm-hub')
|
|
130
|
+
|
|
131
|
+
# ---------- Gemini CLI: mcpServers in ~/.gemini/settings.json
|
|
132
|
+
$geminiEntry = [ordered]@{ type = 'http'; url = $Url }
|
|
133
|
+
Write-Step '- gemini-cli'
|
|
134
|
+
Merge-JsonServer 'gemini-cli' (Join-Path $userHome '.gemini\settings.json') 'mcpServers' $geminiEntry
|
|
135
|
+
Sync-Skill 'gemini-cli' (Join-Path $userHome '.gemini\skills\agent-comm-hub')
|
|
136
|
+
|
|
137
|
+
# ---------- Codex: append [mcp_servers.<name>] to ~/.codex/config.toml (incremental append only)
|
|
138
|
+
$codexFile = Join-Path $userHome '.codex\config.toml'
|
|
139
|
+
Write-Step '- codex'
|
|
140
|
+
if (Test-Path $codexFile) {
|
|
141
|
+
$codexText = [System.IO.File]::ReadAllText($codexFile, [System.Text.Encoding]::UTF8)
|
|
142
|
+
$section = "[mcp_servers.$ServerName]"
|
|
143
|
+
if ($Remove) {
|
|
144
|
+
if ($codexText -match "(?m)^\[mcp_servers\.$([regex]::Escape($ServerName))\]") {
|
|
145
|
+
$bak = Backup $codexFile
|
|
146
|
+
$clean = [regex]::Replace($codexText, "(?m)^\[mcp_servers\.$([regex]::Escape($ServerName))\][^\r\n]*(\r?\n(?!\[).*)*(\r?\n)?", '')
|
|
147
|
+
[System.IO.File]::WriteAllText($codexFile, $clean, $utf8NoBom)
|
|
148
|
+
Write-Step " codex: removed '$ServerName' section from $codexFile (backup: $bak)"
|
|
149
|
+
} else {
|
|
150
|
+
Write-Step " codex: '$ServerName' section not present in $codexFile"
|
|
151
|
+
}
|
|
152
|
+
} elseif ($codexText -match "(?m)^\[mcp_servers\.$([regex]::Escape($ServerName))\]") {
|
|
153
|
+
Write-Step " codex: '$ServerName' section already present ($codexFile unchanged)"
|
|
154
|
+
} else {
|
|
155
|
+
$bak = Backup $codexFile
|
|
156
|
+
$block = "`n[mcp_servers.$ServerName]`ntype = `"streamable-http`"`nurl = `"$Url`"`n"
|
|
157
|
+
[System.IO.File]::WriteAllText($codexFile, $codexText.TrimEnd() + $block, $utf8NoBom)
|
|
158
|
+
Write-Step " codex: appended '$ServerName' section to $codexFile (backup: $bak)"
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
Write-Step " codex: not installed ($codexFile missing, skipped)"
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
# ---------- skills: cross-agent standard location + each agent's private dir
|
|
165
|
+
$skillDirs = @(
|
|
166
|
+
(Join-Path $userHome ".agents\skills\$ServerName"), # cross-agent standard
|
|
167
|
+
(Join-Path $userHome ".minimax\skills\$ServerName"),
|
|
168
|
+
(Join-Path $userHome ".config\opencode\skills\$ServerName"),
|
|
169
|
+
(Join-Path $userHome ".kimi-code\skills\$ServerName"),
|
|
170
|
+
(Join-Path $userHome ".gemini\skills\$ServerName"),
|
|
171
|
+
(Join-Path $userHome ".codex\skills\$ServerName"),
|
|
172
|
+
(Join-Path $userHome ".claude\skills\$ServerName") # config is manual; skill still useful
|
|
173
|
+
)
|
|
174
|
+
foreach ($dir in $skillDirs) { Sync-Skill 'skill' $dir }
|
|
175
|
+
|
|
176
|
+
Write-Step 'done. Manual targets (see agents/README.md): Claude Code (project .mcp.json), DSH (cordis.patch.yml).'
|
|
177
|
+
Write-Step 'Restart agent sessions to pick up the new MCP server.'
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-comm-hub
|
|
3
|
+
description:
|
|
4
|
+
Real-time two-way communication with other AI agents connected to the local
|
|
5
|
+
agent-comm-hub. Use when the user mentions another agent, the hub, group
|
|
6
|
+
chat, sending messages or tasks to another agent, waiting for another
|
|
7
|
+
agent's reply, or forwarding results between agents. Tools:
|
|
8
|
+
bridge_register / bridge_chat / bridge_task / bridge_ack / bridge_wait /
|
|
9
|
+
bridge_poll / bridge_status / bridge_peers / bridge_history.
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# agent-comm-hub usage
|
|
13
|
+
|
|
14
|
+
A local hub (`agent-comm-hub` on 127.0.0.1:18764) connects this agent with
|
|
15
|
+
every other MCP-capable agent on this machine (MiniMax Code, opencode, Kimi
|
|
16
|
+
Code, Claude Code, DeepSeek Harness, …).
|
|
17
|
+
|
|
18
|
+
**You are already registered**: connecting to the hub auto-registers you at
|
|
19
|
+
the MCP handshake using your client name — no manual step needed. Same-name
|
|
20
|
+
connections share one peer id, so your identity is stable across sessions.
|
|
21
|
+
Optional: call `bridge_register(peerId)` to claim a readable id
|
|
22
|
+
(`tool:project`, e.g. `claude-code:myproject`; errors when taken).
|
|
23
|
+
|
|
24
|
+
## Tools
|
|
25
|
+
|
|
26
|
+
- `bridge_chat(to, message)` — send a chat message to a peer; `to: "all"`
|
|
27
|
+
broadcasts.
|
|
28
|
+
- `bridge_task(to, prompt, context?, deliverable?)` — delegate a structured
|
|
29
|
+
task.
|
|
30
|
+
- `bridge_ack(ref, status, note?)` — acknowledge a task
|
|
31
|
+
(`accepted`/`rejected`/`done`/`failed`), auto-routed back to the original
|
|
32
|
+
sender.
|
|
33
|
+
- `bridge_wait(from?, timeoutMs?)` — long-poll for the next message (default
|
|
34
|
+
30 s; loop it to hold a real-time conversation).
|
|
35
|
+
- `bridge_poll(from?)` — non-blocking drain of every queued message.
|
|
36
|
+
- `bridge_status()` / `bridge_peers()` — hub health and who is online.
|
|
37
|
+
- `bridge_history(peer?, limit?)` — recent messages (newest first).
|
|
38
|
+
|
|
39
|
+
## When to use
|
|
40
|
+
|
|
41
|
+
1. The user mentions "another agent / the hub / over there" pointing at a
|
|
42
|
+
different agent — use the bridge tools.
|
|
43
|
+
2. **Before messaging a specific agent, call `bridge_peers()` first and use
|
|
44
|
+
its exact peerId.** If the target is not listed, it is not connected yet —
|
|
45
|
+
do NOT guess a peerId or send blindly; tell the user the other agent needs
|
|
46
|
+
to be running (it registers automatically on connect).
|
|
47
|
+
3. Receiving: try `bridge_poll()` first; if empty, loop `bridge_wait()` until
|
|
48
|
+
a message arrives or you give up.
|
|
49
|
+
4. On receiving a `task` (content is `{prompt, context?, deliverable?}`):
|
|
50
|
+
acknowledge with `bridge_ack(ref, "accepted")` when you take it on, then
|
|
51
|
+
`bridge_ack(ref, "done"[, note])` when finished; use `"rejected"` to
|
|
52
|
+
decline and `"failed"` when it could not be completed (always with a note).
|
|
53
|
+
5. Unsure whether the peer is online: check `bridge_peers()` first.
|
|
54
|
+
|
|
55
|
+
## Notes
|
|
56
|
+
|
|
57
|
+
- Messages travel on loopback only (127.0.0.1:18764); never put credentials
|
|
58
|
+
in bridge messages.
|
|
59
|
+
- A timeout is not a failure: `bridge_wait` returning `{type:"timeout"}` just
|
|
60
|
+
means nothing arrived — try again.
|
|
61
|
+
- Cadence: use 10–30 s short polls when the peer is active; check
|
|
62
|
+
`bridge_peers()` when unsure.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Install the agent-comm-hub client into MiniMax Code (mcode): register the hub
|
|
4
|
+
MCP endpoint and install the hub skill. Run as the same user that runs mcode.
|
|
5
|
+
|
|
6
|
+
.DESCRIPTION
|
|
7
|
+
Writes the agent-hub MCP server into BOTH config files:
|
|
8
|
+
- ~/.minimax/mcp.json — read by the mcode CLI runtime (connections)
|
|
9
|
+
- ~/.minimax/mcp/mcp.json — the MiniMax Code desktop app config
|
|
10
|
+
Both are backed up before touching. Files are written as UTF-8 WITHOUT BOM
|
|
11
|
+
(Node's JSON.parse rejects a BOM). Idempotent. Use -Remove to uninstall.
|
|
12
|
+
|
|
13
|
+
The hub must be running first: `npx agent-comm-hub` (default port 18764).
|
|
14
|
+
|
|
15
|
+
.PARAMETER Url
|
|
16
|
+
Hub MCP endpoint URL. Default http://127.0.0.1:18764/mcp.
|
|
17
|
+
|
|
18
|
+
.PARAMETER ServerName
|
|
19
|
+
Key of the mcp.json entries. Default agent-hub.
|
|
20
|
+
|
|
21
|
+
.PARAMETER Remove
|
|
22
|
+
Uninstall: remove the entries and the skill directory.
|
|
23
|
+
|
|
24
|
+
.EXAMPLE
|
|
25
|
+
powershell -ExecutionPolicy Bypass -File install-mcode.ps1
|
|
26
|
+
#>
|
|
27
|
+
param(
|
|
28
|
+
[string]$Url = 'http://127.0.0.1:18764/mcp',
|
|
29
|
+
[string]$ServerName = 'agent-hub',
|
|
30
|
+
[switch]$Remove
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
$ErrorActionPreference = 'Stop'
|
|
34
|
+
$userHome = $env:USERPROFILE
|
|
35
|
+
$minimaxDir = Join-Path $userHome '.minimax'
|
|
36
|
+
$mcpTargets = @(
|
|
37
|
+
(Join-Path $minimaxDir 'mcp.json'),
|
|
38
|
+
(Join-Path $minimaxDir 'mcp\mcp.json')
|
|
39
|
+
)
|
|
40
|
+
$skillDir = Join-Path $minimaxDir 'skills\agent-comm-hub'
|
|
41
|
+
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
|
|
42
|
+
|
|
43
|
+
function Write-Step($text) { Write-Host "[agent-comm-hub] $text" -ForegroundColor Cyan }
|
|
44
|
+
|
|
45
|
+
function Read-JsonFile($path) {
|
|
46
|
+
if (-not (Test-Path $path)) { return $null }
|
|
47
|
+
try { return [System.IO.File]::ReadAllText($path, [System.Text.Encoding]::UTF8) | ConvertFrom-Json }
|
|
48
|
+
catch { return $null }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function Write-JsonFile($path, $value) {
|
|
52
|
+
$dir = Split-Path $path
|
|
53
|
+
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
|
|
54
|
+
[System.IO.File]::WriteAllText($path, ($value | ConvertTo-Json -Depth 20), $utf8NoBom)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (-not (Test-Path $minimaxDir)) {
|
|
58
|
+
throw "mcode config home not found: $minimaxDir — is mcode installed?"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
$entry = [ordered]@{
|
|
62
|
+
url = $Url
|
|
63
|
+
type = 'streamable-http'
|
|
64
|
+
enabled = $true
|
|
65
|
+
configured = $true
|
|
66
|
+
timeout = 120000
|
|
67
|
+
description = 'agent-comm-hub: talk to every other agent connected to the hub. Call bridge_register(peerId) first, then bridge_chat / bridge_task / bridge_ack / bridge_wait / bridge_poll / bridge_status / bridge_peers / bridge_history.'
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
foreach ($mcpFile in $mcpTargets) {
|
|
71
|
+
$mcp = Read-JsonFile $mcpFile
|
|
72
|
+
if ($null -eq $mcp -or $null -eq $mcp.mcpServers) {
|
|
73
|
+
$mcp = [pscustomobject]@{ mcpServers = [ordered]@{} }
|
|
74
|
+
}
|
|
75
|
+
if ($Remove) {
|
|
76
|
+
if ($mcp.mcpServers.PSObject.Properties.Name -contains $ServerName) {
|
|
77
|
+
$mcp.mcpServers.PSObject.Properties.Remove($ServerName)
|
|
78
|
+
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
|
79
|
+
Copy-Item $mcpFile "$mcpFile.bak-$stamp" -Force -ErrorAction SilentlyContinue
|
|
80
|
+
Write-JsonFile $mcpFile $mcp
|
|
81
|
+
Write-Step "removed '$ServerName' from $mcpFile (backup: $(Split-Path $mcpFile -Leaf).bak-$stamp)"
|
|
82
|
+
} else {
|
|
83
|
+
Write-Step "'$ServerName' not present in $mcpFile — nothing to remove"
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
$changed = $true
|
|
87
|
+
if ($mcp.mcpServers.PSObject.Properties.Name -contains $ServerName) {
|
|
88
|
+
$existing = $mcp.mcpServers.$ServerName
|
|
89
|
+
$changed = ($existing.url -ne $Url) -or (-not $existing.enabled) -or ($existing.description -ne $entry.description)
|
|
90
|
+
}
|
|
91
|
+
if ($changed) {
|
|
92
|
+
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
|
93
|
+
Copy-Item $mcpFile "$mcpFile.bak-$stamp" -Force -ErrorAction SilentlyContinue
|
|
94
|
+
$mcp.mcpServers | Add-Member -NotePropertyName $ServerName -NotePropertyValue $entry -Force
|
|
95
|
+
Write-JsonFile $mcpFile $mcp
|
|
96
|
+
Write-Step "registered '$ServerName' -> $Url in $mcpFile (backup: $(Split-Path $mcpFile -Leaf).bak-$stamp)"
|
|
97
|
+
} else {
|
|
98
|
+
Write-Step "'$ServerName' already registered and enabled in $mcpFile — unchanged"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
$skillSrc = Join-Path $PSScriptRoot 'SKILL.md'
|
|
104
|
+
if ($Remove) {
|
|
105
|
+
if (Test-Path $skillDir) {
|
|
106
|
+
Remove-Item $skillDir -Recurse -Force
|
|
107
|
+
Write-Step "removed skill $skillDir"
|
|
108
|
+
} else {
|
|
109
|
+
Write-Step "skill $skillDir not present — nothing to remove"
|
|
110
|
+
}
|
|
111
|
+
} elseif (Test-Path $skillSrc) {
|
|
112
|
+
New-Item -ItemType Directory -Path $skillDir -Force | Out-Null
|
|
113
|
+
Copy-Item $skillSrc (Join-Path $skillDir 'SKILL.md') -Force
|
|
114
|
+
Write-Step "installed skill -> $skillDir\SKILL.md"
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (-not $Remove) {
|
|
118
|
+
Write-Step 'done. Restart your mcode session, then verify with:'
|
|
119
|
+
Write-Step ' mcode exec "你有哪些 bridge 工具?先 bridge_register 注册一下"'
|
|
120
|
+
Write-Step 'Make sure the hub is running: npx agent-comm-hub'
|
|
121
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"agent-hub": {
|
|
3
|
+
"url": "http://127.0.0.1:18764/mcp",
|
|
4
|
+
"type": "streamable-http",
|
|
5
|
+
"enabled": true,
|
|
6
|
+
"configured": true,
|
|
7
|
+
"timeout": 120000,
|
|
8
|
+
"description": "agent-comm-hub: talk to every other agent connected to the hub. Call bridge_register(peerId) first, then bridge_chat / bridge_task / bridge_ack / bridge_wait / bridge_poll / bridge_status / bridge_peers / bridge_history."
|
|
9
|
+
}
|
|
10
|
+
}
|
|
Binary file
|
|
Binary file
|