drupal-mcp-connector 2.10.1 → 2.12.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.
@@ -21,6 +21,8 @@ export const FRAME_TYPES = Object.freeze([
21
21
  "denied",
22
22
  "mcp-request",
23
23
  "mcp-response",
24
+ "policy-bundle",
25
+ "policy-bundle-ack",
24
26
  ]);
25
27
 
26
28
  const FRAME_TYPE_SET = new Set(FRAME_TYPES);
@@ -118,13 +120,25 @@ export function writeFrame(socket, frame) {
118
120
  /**
119
121
  * Correlate mcp-request ids with their mcp-response frames.
120
122
  *
123
+ * Optional `owner` binds a tracked id to one tenant agent. A response from a
124
+ * different owner is ignored (cross-tenant injection cannot complete the
125
+ * wait). Disconnecting one owner rejects only that owner's pending ids.
126
+ *
121
127
  * @param {object} [options]
122
128
  * @param {number} [options.timeoutMs] Per-request wait bound.
123
- * @returns {{size: number, track: (id: string) => Promise<object>, settle: (frame: {id?: string}) => boolean, rejectAll: (error: Error) => void}}
129
+ * @returns {object}
124
130
  */
125
131
  export function createRequestBroker({ timeoutMs = 10_000 } = {}) {
126
132
  const pending = new Map();
127
133
 
134
+ function drop(id, apply) {
135
+ const waiter = pending.get(id);
136
+ if (!waiter) return false;
137
+ pending.delete(id);
138
+ apply(waiter);
139
+ return true;
140
+ }
141
+
128
142
  return {
129
143
  get size() {
130
144
  return pending.size;
@@ -132,9 +146,10 @@ export function createRequestBroker({ timeoutMs = 10_000 } = {}) {
132
146
 
133
147
  /**
134
148
  * @param {string} id
149
+ * @param {{owner?: string|null}} [options]
135
150
  * @returns {Promise<object>} Resolves with the matching response frame.
136
151
  */
137
- track(id) {
152
+ track(id, { owner = null } = {}) {
138
153
  return new Promise((resolve, reject) => {
139
154
  const timer = setTimeout(() => {
140
155
  pending.delete(id);
@@ -142,6 +157,7 @@ export function createRequestBroker({ timeoutMs = 10_000 } = {}) {
142
157
  }, timeoutMs);
143
158
  timer.unref?.();
144
159
  pending.set(id, {
160
+ owner,
145
161
  resolve(frame) {
146
162
  clearTimeout(timer);
147
163
  resolve(frame);
@@ -156,24 +172,36 @@ export function createRequestBroker({ timeoutMs = 10_000 } = {}) {
156
172
 
157
173
  /**
158
174
  * @param {{id?: string}} frame
175
+ * @param {{owner?: string|null}} [options]
159
176
  * @returns {boolean} True when a tracked request was resolved.
160
177
  */
161
- settle(frame) {
178
+ settle(frame, { owner = null } = {}) {
162
179
  if (typeof frame?.id !== "string") return false;
163
180
  const waiter = pending.get(frame.id);
164
181
  if (!waiter) return false;
165
- pending.delete(frame.id);
166
- waiter.resolve(frame);
167
- return true;
182
+ if (typeof waiter.owner === "string" && waiter.owner !== owner) {
183
+ return false;
184
+ }
185
+ return drop(frame.id, (entry) => entry.resolve(frame));
186
+ },
187
+
188
+ /**
189
+ * @param {string} owner
190
+ * @param {Error} error
191
+ */
192
+ rejectByOwner(owner, error) {
193
+ for (const [id, waiter] of [...pending]) {
194
+ if (waiter.owner !== owner) continue;
195
+ drop(id, (entry) => entry.reject(error));
196
+ }
168
197
  },
169
198
 
170
199
  /**
171
200
  * @param {Error} error
172
201
  */
173
202
  rejectAll(error) {
174
- for (const [id, waiter] of pending) {
175
- pending.delete(id);
176
- waiter.reject(error);
203
+ for (const [id] of [...pending]) {
204
+ drop(id, (entry) => entry.reject(error));
177
205
  }
178
206
  },
179
207
  };
package/src/tools/site.js CHANGED
@@ -47,7 +47,7 @@ async function listContentTypes({ site: siteName }) {
47
47
  * List named sites this principal may address. No backend call and no credentials.
48
48
  * `sites` stays a name list for compatibility; `targets` is the authoritative
49
49
  * resolved-target record.
50
- * @returns {Promise<{sites: string[], targets: Array<object>}>}
50
+ * @returns {Promise<{sites: string[], targets: Array<object>, tenants: Array<object>}>}
51
51
  */
52
52
  async function listConfiguredSites() {
53
53
  const names = listSiteNames();