@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 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 and optional stream retention. `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. Response may include `warnings[]` if the project exceeds the 50-collection soft cap.",
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
- async ({ projectId, name, realtimeMode, streamRetention }) => {
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: [{ type: "text", text: "At least one of realtimeMode or streamRetention must be provided" }],
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
  }