@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 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}` and `GET /recipients` -- so the MCP service can
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
- items: sorted.slice(0, RECIPIENTS_MAX).map((e) => ({ user_id: e.userId, display_name: e.displayName.slice(0, DISPLAY_NAME_MAX) }))
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.3",
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
  }