@spacelr/mcp 0.0.13 → 0.1.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/dist/index.mjs +44 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1228,7 +1228,7 @@ function registerDatabaseTools(server, api) {
|
|
|
1228
1228
|
server.registerTool(
|
|
1229
1229
|
"database_collections_update_metadata",
|
|
1230
1230
|
{
|
|
1231
|
-
description: "Update a collection's realtime delivery mode
|
|
1231
|
+
description: "Update a collection's realtime delivery mode, stream retention, write rate-limit override, or search filter requirements. `realtimeMode: 'stream'` switches the collection to Redis Streams for durable event replay (needed for chat, notifications, activity feeds). `realtimeMode: 'pubsub'` (default) is fire-and-forget, used for dashboards and list views. Exactly one of `streamRetention.maxLen` (approx. entry count) or `streamRetention.maxAgeMs` (retention age in ms) may be set. `writeThrottle` overrides the default per-collection write rate limit (10 writes / 10 s) \u2014 set `enabled: false` to disable entirely (e.g. audit logs), or override `limit` / `windowMs`. `searchConfig.requireFilter` declares top-level filter keys that callers MUST include in every `collection.search()` call to prevent unindexable full-scan regex queries \u2014 affects ALL callers immediately (no deprecation window). Response may include `warnings[]` if the project exceeds the 50-collection soft cap.",
|
|
1232
1232
|
inputSchema: {
|
|
1233
1233
|
projectId: z4.string(),
|
|
1234
1234
|
name: z4.string(),
|
|
@@ -1239,17 +1239,55 @@ function registerDatabaseTools(server, api) {
|
|
|
1239
1239
|
}).refine(
|
|
1240
1240
|
(r) => !(r.maxLen !== void 0 && r.maxAgeMs !== void 0),
|
|
1241
1241
|
{ message: "Set at most one of maxLen or maxAgeMs" }
|
|
1242
|
-
).optional()
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1242
|
+
).optional(),
|
|
1243
|
+
writeThrottle: z4.object({
|
|
1244
|
+
enabled: z4.boolean().optional().describe("When false, skip write throttling entirely for this collection"),
|
|
1245
|
+
limit: z4.number().int().min(1).max(1e4).optional().describe("Max writes per window (1..10000)"),
|
|
1246
|
+
windowMs: z4.number().int().min(1e3).max(36e5).optional().describe("Window duration in ms (1000..3_600_000 = 1s to 1h)")
|
|
1247
|
+
}).refine(
|
|
1248
|
+
(t) => t.enabled !== void 0 || t.limit !== void 0 || t.windowMs !== void 0,
|
|
1249
|
+
{ message: "writeThrottle must set at least one of enabled, limit, or windowMs" }
|
|
1250
|
+
).optional(),
|
|
1251
|
+
searchConfig: z4.object({
|
|
1252
|
+
requireFilter: z4.array(
|
|
1253
|
+
z4.string().regex(/^[a-zA-Z0-9_]+$/, "Top-level field names only (no dots, alphanumeric + underscore)").max(64).refine(
|
|
1254
|
+
(k) => !["__proto__", "constructor", "prototype"].includes(k),
|
|
1255
|
+
{ message: "Reserved JS object keys (__proto__, constructor, prototype) are not allowed" }
|
|
1256
|
+
)
|
|
1257
|
+
).min(1).max(10).optional().describe(
|
|
1258
|
+
"Top-level filter keys required on every search() call. Empty array rejected \u2014 to CLEAR an existing requirement, pass `searchConfig: {}` (an empty object). Omitting `searchConfig` entirely is a no-op (no change). Duplicate keys are deduplicated server-side, but you should send a deduplicated list."
|
|
1259
|
+
)
|
|
1260
|
+
// `searchConfig.fields` is intentionally NOT exposed here. The
|
|
1261
|
+
// backend DTO accepts it but treats it as "Reserved: future
|
|
1262
|
+
// allow-list of searchable fields. Stored but not enforced.".
|
|
1263
|
+
// Surfacing it via MCP would let callers persist values that
|
|
1264
|
+
// have no observable effect today and may take on different
|
|
1265
|
+
// semantics when enforcement ships. Add back once the feature
|
|
1266
|
+
// is live.
|
|
1267
|
+
}).strict().optional()
|
|
1268
|
+
}
|
|
1269
|
+
},
|
|
1270
|
+
async ({ projectId, name, realtimeMode, streamRetention, writeThrottle, searchConfig }) => {
|
|
1246
1271
|
try {
|
|
1247
1272
|
const body = {};
|
|
1248
1273
|
if (realtimeMode !== void 0) body.realtimeMode = realtimeMode;
|
|
1249
1274
|
if (streamRetention !== void 0) body.streamRetention = streamRetention;
|
|
1275
|
+
if (writeThrottle !== void 0) body.writeThrottle = writeThrottle;
|
|
1276
|
+
if (searchConfig !== void 0) {
|
|
1277
|
+
const normalized = {};
|
|
1278
|
+
if (searchConfig.requireFilter !== void 0) {
|
|
1279
|
+
normalized.requireFilter = Array.from(new Set(searchConfig.requireFilter));
|
|
1280
|
+
}
|
|
1281
|
+
body.searchConfig = normalized;
|
|
1282
|
+
}
|
|
1250
1283
|
if (Object.keys(body).length === 0) {
|
|
1251
1284
|
return {
|
|
1252
|
-
content: [
|
|
1285
|
+
content: [
|
|
1286
|
+
{
|
|
1287
|
+
type: "text",
|
|
1288
|
+
text: "At least one of realtimeMode, streamRetention, writeThrottle, or searchConfig must be provided"
|
|
1289
|
+
}
|
|
1290
|
+
],
|
|
1253
1291
|
isError: true
|
|
1254
1292
|
};
|
|
1255
1293
|
}
|