@rackbops/plugin-mcp 0.3.3 → 0.5.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/README.md +14 -1
- package/dist/plugin.js +26 -4
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -4,7 +4,8 @@ The bridge plugin for the Discord delivery MCP ([`Rackbops/discord-mcp`](https:/
|
|
|
4
4
|
[Rackbops/Tooling#742](https://github.com/Rackbops/Tooling/issues/742)). It implements the service
|
|
5
5
|
side of that repo's `docs/bridge-protocol.md` under `/mcp/` on the bot's own HTTP listener
|
|
6
6
|
(rackbops-discord-bot's host-owned router, ADR-0007) -- `GET /capabilities`,
|
|
7
|
-
`POST /deliveries`, `GET /deliveries/{request_id}
|
|
7
|
+
`POST /deliveries`, `GET /deliveries/{request_id}`, `GET /recipients` and
|
|
8
|
+
`GET /recipients/{user_id}` -- so the MCP service can
|
|
8
9
|
hand it a message and get one Discord post, DM or edit out of it: a retry of a request that is
|
|
9
10
|
delivered or in flight never delivers again (a retry of a failed or unknown one, and the restart
|
|
10
11
|
re-drive, deliver at least once -- see below). It also owns Discord-side agent identity ([Rackbops/Tooling#743](https://github.com/Rackbops/Tooling/issues/743)):
|
|
@@ -90,6 +91,17 @@ most 100, each `display_name` truncated to 100 characters (same bearer auth; any
|
|
|
90
91
|
200: {"items":[]}
|
|
91
92
|
```
|
|
92
93
|
|
|
94
|
+
`GET /recipients/{user_id}` -- one registered user, in the same shape as a `GET /recipients` item
|
|
95
|
+
and with the same display-name truncation, but with no cap: a user registered after the first 100
|
|
96
|
+
still finds their own entry here. `user_id` must be a snowflake (`[1-9][0-9]{16,19}`); a malformed
|
|
97
|
+
one falls through to the generic `404 {"error":"not found"}`. Same bearer auth; any other method is
|
|
98
|
+
`405`:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
200: {"user_id":"123456789012345678","display_name":"Roshne"}
|
|
102
|
+
404: {"error":"not registered"}
|
|
103
|
+
```
|
|
104
|
+
|
|
93
105
|
`GET /capabilities` now reflects the host's real `dm`/`edit` support:
|
|
94
106
|
|
|
95
107
|
```
|
|
@@ -143,6 +155,7 @@ Declared so the operator can map each to a channel per server in the admin panel
|
|
|
143
155
|
| `deals` | Notable deals or opportunities |
|
|
144
156
|
| `digest` | Periodic summaries |
|
|
145
157
|
| `ops` | Operational status and infrastructure notices |
|
|
158
|
+
| `agent-chat` | Agent-to-agent conversation: list it under `conversations` in discord-mcp's config so posts carry the sender's name and agents can read them back with `read_messages` |
|
|
146
159
|
|
|
147
160
|
## Operator steps (not done by this plugin)
|
|
148
161
|
|
package/dist/plugin.js
CHANGED
|
@@ -108,7 +108,8 @@ var DESTINATIONS = [
|
|
|
108
108
|
{ name: "alerts", description: "Time-sensitive findings and warnings" },
|
|
109
109
|
{ name: "deals", description: "Notable deals or opportunities" },
|
|
110
110
|
{ name: "digest", description: "Periodic summaries" },
|
|
111
|
-
{ name: "ops", description: "Operational status and infrastructure notices" }
|
|
111
|
+
{ name: "ops", description: "Operational status and infrastructure notices" },
|
|
112
|
+
{ name: "agent-chat", description: "Agent-to-agent conversation (read back with discord-mcp's read_messages)" }
|
|
112
113
|
];
|
|
113
114
|
var DESTINATION_NAMES = DESTINATIONS.map((d) => d.name);
|
|
114
115
|
function isPostTarget(target) {
|
|
@@ -257,9 +258,10 @@ function toWireState(stored) {
|
|
|
257
258
|
}
|
|
258
259
|
function recipientsResponse(entries) {
|
|
259
260
|
const sorted = [...entries].sort((a, b) => a.registeredAt.localeCompare(b.registeredAt) || a.userId.localeCompare(b.userId));
|
|
260
|
-
return {
|
|
261
|
-
|
|
262
|
-
|
|
261
|
+
return { items: sorted.slice(0, RECIPIENTS_MAX).map(recipientResponse) };
|
|
262
|
+
}
|
|
263
|
+
function recipientResponse(entry) {
|
|
264
|
+
return { user_id: entry.userId, display_name: entry.displayName.slice(0, DISPLAY_NAME_MAX) };
|
|
263
265
|
}
|
|
264
266
|
|
|
265
267
|
// plugins/mcp/src/drain.ts
|
|
@@ -549,8 +551,15 @@ async function handleGetRecipients(deps) {
|
|
|
549
551
|
const entries = await deps.registry.listRecipients();
|
|
550
552
|
return json(200, recipientsResponse(entries));
|
|
551
553
|
}
|
|
554
|
+
async function handleGetRecipient(userId, deps) {
|
|
555
|
+
const entry = await deps.registry.recipientOf(userId);
|
|
556
|
+
if (entry === undefined)
|
|
557
|
+
return json(404, { error: "not registered" });
|
|
558
|
+
return json(200, recipientResponse(entry));
|
|
559
|
+
}
|
|
552
560
|
var DELIVERY_ID_RE = /^\/deliveries\/([0-9a-f]{64})$/;
|
|
553
561
|
var REGISTRATION_ID_RE = /^\/registration\/([1-9][0-9]{16,19})$/;
|
|
562
|
+
var RECIPIENT_ID_RE = /^\/recipients\/([1-9][0-9]{16,19})$/;
|
|
554
563
|
async function handleMcpHttp(request, info, deps) {
|
|
555
564
|
if (deps.token === undefined)
|
|
556
565
|
return json(503, { error: "bridge not configured" });
|
|
@@ -593,6 +602,12 @@ async function handleMcpHttp(request, info, deps) {
|
|
|
593
602
|
return json(405, { error: "method not allowed" });
|
|
594
603
|
return handleGetRecipients(deps);
|
|
595
604
|
}
|
|
605
|
+
const recipientMatch = RECIPIENT_ID_RE.exec(info.path);
|
|
606
|
+
if (recipientMatch) {
|
|
607
|
+
if (request.method !== "GET")
|
|
608
|
+
return json(405, { error: "method not allowed" });
|
|
609
|
+
return handleGetRecipient(recipientMatch[1], deps);
|
|
610
|
+
}
|
|
596
611
|
return json(404, { error: "not found" });
|
|
597
612
|
}
|
|
598
613
|
|
|
@@ -739,6 +754,13 @@ function createRegistryStore(dataDir, storage) {
|
|
|
739
754
|
const entry = current.users[userId];
|
|
740
755
|
return { userId, displayName: entry.displayName, registeredAt: entry.registeredAt };
|
|
741
756
|
});
|
|
757
|
+
},
|
|
758
|
+
async recipientOf(userId) {
|
|
759
|
+
const current = normalizeRegistry(await storage.readJsonOrFresh(path, freshRegistry, "mcp-registry"));
|
|
760
|
+
const entry = entryOf(current, userId);
|
|
761
|
+
if (entry === undefined)
|
|
762
|
+
return;
|
|
763
|
+
return { userId, displayName: entry.displayName, registeredAt: entry.registeredAt };
|
|
742
764
|
}
|
|
743
765
|
};
|
|
744
766
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rackbops/plugin-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Bridge plugin for the Discord delivery MCP (Rackbops/discord-mcp): the service side of docs/bridge-protocol.md, plus /agent registration and pairing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/plugin.js",
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
{ "name": "alerts", "description": "Time-sensitive findings and warnings" },
|
|
31
31
|
{ "name": "deals", "description": "Notable deals or opportunities" },
|
|
32
32
|
{ "name": "digest", "description": "Periodic summaries" },
|
|
33
|
-
{ "name": "ops", "description": "Operational status and infrastructure notices" }
|
|
33
|
+
{ "name": "ops", "description": "Operational status and infrastructure notices" },
|
|
34
|
+
{ "name": "agent-chat", "description": "Agent-to-agent conversation (read back with discord-mcp's read_messages)" }
|
|
34
35
|
]
|
|
35
36
|
}
|
|
36
37
|
}
|