@prmichaelsen/remember-mcp 2.3.4 → 2.5.1

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.
Files changed (34) hide show
  1. package/AGENT.md +2 -2
  2. package/CHANGELOG.md +63 -0
  3. package/README.md +50 -5
  4. package/agent/commands/git.commit.md +511 -0
  5. package/agent/commands/git.init.md +513 -0
  6. package/agent/milestones/milestone-11-unified-public-collection.md +205 -0
  7. package/agent/scripts/install.sh +31 -16
  8. package/agent/scripts/update.sh +32 -17
  9. package/agent/tasks/task-45-fix-publish-false-success-bug.md +114 -181
  10. package/agent/tasks/task-46-update-spacememory-types.md +94 -0
  11. package/agent/tasks/task-47-update-space-schema.md +102 -0
  12. package/agent/tasks/task-48-create-memory-public-collection.md +96 -0
  13. package/agent/tasks/task-49-update-remember-publish.md +153 -0
  14. package/agent/tasks/task-50-update-remember-confirm.md +111 -0
  15. package/agent/tasks/task-51-update-remember-search-space.md +154 -0
  16. package/agent/tasks/task-52-update-remember-query-space.md +142 -0
  17. package/agent/tasks/task-53-add-multispace-tests.md +193 -0
  18. package/agent/tasks/task-54-update-documentation-multispace.md +191 -0
  19. package/dist/server-factory.js +203 -107
  20. package/dist/server.js +203 -107
  21. package/dist/tools/publish.d.ts +1 -1
  22. package/dist/tools/query-space.d.ts +1 -1
  23. package/dist/tools/search-space.d.ts +1 -1
  24. package/dist/types/space-memory.d.ts +5 -3
  25. package/dist/weaviate/space-schema.d.ts +16 -0
  26. package/package.json +1 -1
  27. package/src/services/confirmation-token.service.ts +74 -30
  28. package/src/tools/confirm.ts +15 -16
  29. package/src/tools/publish.ts +42 -20
  30. package/src/tools/query-space.ts +38 -24
  31. package/src/tools/search-space.ts +51 -28
  32. package/src/types/space-memory.ts +5 -3
  33. package/src/weaviate/space-schema.spec.ts +55 -0
  34. package/src/weaviate/space-schema.ts +45 -6
package/dist/server.js CHANGED
@@ -3283,33 +3283,72 @@ var ConfirmationTokenService = class {
3283
3283
  * @returns Request ID and token
3284
3284
  */
3285
3285
  async createRequest(userId, action, payload, targetCollection) {
3286
- const token = randomUUID();
3287
- const now = /* @__PURE__ */ new Date();
3288
- const expiresAt = new Date(now.getTime() + this.EXPIRY_MINUTES * 60 * 1e3);
3289
- const request = {
3290
- user_id: userId,
3291
- token,
3292
- action,
3293
- target_collection: targetCollection,
3294
- payload,
3295
- created_at: now.toISOString(),
3296
- expires_at: expiresAt.toISOString(),
3297
- status: "pending"
3298
- };
3299
- const collectionPath = `users/${userId}/requests`;
3300
- console.log("[ConfirmationTokenService] Creating request:", {
3301
- userId,
3302
- action,
3303
- targetCollection,
3304
- collectionPath
3305
- });
3306
- const docRef = await addDocument(collectionPath, request);
3307
- console.log("[ConfirmationTokenService] Request created:", {
3308
- requestId: docRef.id,
3309
- token,
3310
- expiresAt: request.expires_at
3311
- });
3312
- return { requestId: docRef.id, token };
3286
+ try {
3287
+ const token = randomUUID();
3288
+ const now = /* @__PURE__ */ new Date();
3289
+ const expiresAt = new Date(now.getTime() + this.EXPIRY_MINUTES * 60 * 1e3);
3290
+ const request = {
3291
+ user_id: userId,
3292
+ token,
3293
+ action,
3294
+ target_collection: targetCollection,
3295
+ payload,
3296
+ created_at: now.toISOString(),
3297
+ expires_at: expiresAt.toISOString(),
3298
+ status: "pending"
3299
+ };
3300
+ const collectionPath = `users/${userId}/requests`;
3301
+ console.log("[ConfirmationTokenService] Creating request:", {
3302
+ userId,
3303
+ action,
3304
+ targetCollection,
3305
+ collectionPath,
3306
+ requestData: {
3307
+ token,
3308
+ action,
3309
+ payloadKeys: Object.keys(payload)
3310
+ }
3311
+ });
3312
+ console.log("[ConfirmationTokenService] Calling addDocument...");
3313
+ const docRef = await addDocument(collectionPath, request);
3314
+ console.log("[ConfirmationTokenService] addDocument returned:", {
3315
+ hasDocRef: !!docRef,
3316
+ hasId: !!docRef?.id,
3317
+ docRefId: docRef?.id
3318
+ });
3319
+ if (!docRef) {
3320
+ const error = new Error("Firestore addDocument returned null/undefined");
3321
+ console.error("[ConfirmationTokenService] CRITICAL: addDocument returned null", {
3322
+ userId,
3323
+ collectionPath
3324
+ });
3325
+ throw error;
3326
+ }
3327
+ if (!docRef.id) {
3328
+ const error = new Error("Firestore addDocument returned docRef without ID");
3329
+ console.error("[ConfirmationTokenService] CRITICAL: docRef has no ID", {
3330
+ userId,
3331
+ collectionPath,
3332
+ docRef
3333
+ });
3334
+ throw error;
3335
+ }
3336
+ console.log("[ConfirmationTokenService] Request created successfully:", {
3337
+ requestId: docRef.id,
3338
+ token,
3339
+ expiresAt: request.expires_at
3340
+ });
3341
+ return { requestId: docRef.id, token };
3342
+ } catch (error) {
3343
+ console.error("[ConfirmationTokenService] FAILED to create request:", {
3344
+ error: error instanceof Error ? error.message : String(error),
3345
+ stack: error instanceof Error ? error.stack : void 0,
3346
+ userId,
3347
+ action,
3348
+ collectionPath: `users/${userId}/requests`
3349
+ });
3350
+ throw error;
3351
+ }
3313
3352
  }
3314
3353
  /**
3315
3354
  * Validate and retrieve a confirmation request
@@ -3446,6 +3485,7 @@ var confirmationTokenService = new ConfirmationTokenService();
3446
3485
  // src/weaviate/space-schema.ts
3447
3486
  init_space_memory();
3448
3487
  import weaviate3 from "weaviate-client";
3488
+ var PUBLIC_COLLECTION_NAME = "Memory_public";
3449
3489
  function getSpaceCollectionName(spaceId) {
3450
3490
  return `Memory_${spaceId}`;
3451
3491
  }
@@ -3453,7 +3493,7 @@ function isValidSpaceId(spaceId) {
3453
3493
  return SUPPORTED_SPACES.includes(spaceId);
3454
3494
  }
3455
3495
  async function createSpaceCollection(client2, spaceId) {
3456
- const collectionName = getSpaceCollectionName(spaceId);
3496
+ const collectionName = spaceId === "public" ? PUBLIC_COLLECTION_NAME : getSpaceCollectionName(spaceId);
3457
3497
  console.log(`[Weaviate] Creating space collection ${collectionName}...`);
3458
3498
  await client2.collections.create({
3459
3499
  name: collectionName,
@@ -3471,10 +3511,15 @@ async function createSpaceCollection(client2, spaceId) {
3471
3511
  description: 'Document type: "space_memory"'
3472
3512
  },
3473
3513
  // Space identity
3514
+ {
3515
+ name: "spaces",
3516
+ dataType: "text[]",
3517
+ description: 'Spaces this memory is published to (e.g., ["the_void", "dogs"])'
3518
+ },
3474
3519
  {
3475
3520
  name: "space_id",
3476
3521
  dataType: "text",
3477
- description: 'Space identifier (e.g., "the_void")'
3522
+ description: "DEPRECATED: Use spaces array instead. Will be removed in v3.0.0."
3478
3523
  },
3479
3524
  {
3480
3525
  name: "author_id",
@@ -3608,14 +3653,11 @@ async function createSpaceCollection(client2, spaceId) {
3608
3653
  });
3609
3654
  console.log(`[Weaviate] Space collection ${collectionName} created successfully`);
3610
3655
  }
3611
- async function ensureSpaceCollection(client2, spaceId) {
3612
- if (!isValidSpaceId(spaceId)) {
3613
- throw new Error(`Invalid space ID: ${spaceId}. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`);
3614
- }
3615
- const collectionName = getSpaceCollectionName(spaceId);
3656
+ async function ensurePublicCollection(client2) {
3657
+ const collectionName = PUBLIC_COLLECTION_NAME;
3616
3658
  const exists = await client2.collections.exists(collectionName);
3617
3659
  if (!exists) {
3618
- await createSpaceCollection(client2, spaceId);
3660
+ await createSpaceCollection(client2, "public");
3619
3661
  }
3620
3662
  return client2.collections.get(collectionName);
3621
3663
  }
@@ -3624,7 +3666,7 @@ async function ensureSpaceCollection(client2, spaceId) {
3624
3666
  init_space_memory();
3625
3667
  var publishTool = {
3626
3668
  name: "remember_publish",
3627
- description: 'Publish a memory to a shared space (like "The Void"). The memory will be COPIED (not moved) from your personal collection. Generates a confirmation token. Use remember_confirm to execute.',
3669
+ description: 'Publish a memory to one or more shared spaces (like "The Void"). The memory will be COPIED (not moved) from your personal collection. Generates a confirmation token. Use remember_confirm to execute.',
3628
3670
  inputSchema: {
3629
3671
  type: "object",
3630
3672
  properties: {
@@ -3632,11 +3674,15 @@ var publishTool = {
3632
3674
  type: "string",
3633
3675
  description: "ID of the memory from your personal collection to publish"
3634
3676
  },
3635
- target: {
3636
- type: "string",
3637
- description: "Target space to publish to (snake_case ID)",
3638
- enum: SUPPORTED_SPACES,
3639
- default: "the_void"
3677
+ spaces: {
3678
+ type: "array",
3679
+ items: {
3680
+ type: "string",
3681
+ enum: SUPPORTED_SPACES
3682
+ },
3683
+ description: 'Spaces to publish to (e.g., ["the_void", "dogs"]). Can publish to multiple spaces at once.',
3684
+ minItems: 1,
3685
+ default: ["the_void"]
3640
3686
  },
3641
3687
  additional_tags: {
3642
3688
  type: "array",
@@ -3645,7 +3691,7 @@ var publishTool = {
3645
3691
  default: []
3646
3692
  }
3647
3693
  },
3648
- required: ["memory_id", "target"]
3694
+ required: ["memory_id", "spaces"]
3649
3695
  }
3650
3696
  };
3651
3697
  async function handlePublish(args, userId) {
@@ -3653,18 +3699,21 @@ async function handlePublish(args, userId) {
3653
3699
  console.log("[remember_publish] Starting publish request:", {
3654
3700
  userId,
3655
3701
  memoryId: args.memory_id,
3656
- target: args.target,
3702
+ spaces: args.spaces,
3703
+ spaceCount: args.spaces.length,
3657
3704
  additionalTags: args.additional_tags?.length || 0
3658
3705
  });
3659
- if (!isValidSpaceId(args.target)) {
3660
- console.log("[remember_publish] Invalid space ID:", args.target);
3706
+ const invalidSpaces = args.spaces.filter((s) => !isValidSpaceId(s));
3707
+ if (invalidSpaces.length > 0) {
3708
+ console.log("[remember_publish] Invalid space IDs:", invalidSpaces);
3661
3709
  return JSON.stringify(
3662
3710
  {
3663
3711
  success: false,
3664
- error: "Invalid space ID",
3665
- message: `Space "${args.target}" is not supported. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`,
3712
+ error: "Invalid space IDs",
3713
+ message: `Invalid spaces: ${invalidSpaces.join(", ")}. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`,
3666
3714
  context: {
3667
- provided_space: args.target,
3715
+ invalid_spaces: invalidSpaces,
3716
+ provided_spaces: args.spaces,
3668
3717
  supported_spaces: SUPPORTED_SPACES
3669
3718
  }
3670
3719
  },
@@ -3672,6 +3721,18 @@ async function handlePublish(args, userId) {
3672
3721
  2
3673
3722
  );
3674
3723
  }
3724
+ if (args.spaces.length === 0) {
3725
+ console.log("[remember_publish] Empty spaces array");
3726
+ return JSON.stringify(
3727
+ {
3728
+ success: false,
3729
+ error: "Empty spaces array",
3730
+ message: "Must specify at least one space to publish to"
3731
+ },
3732
+ null,
3733
+ 2
3734
+ );
3735
+ }
3675
3736
  const weaviateClient = getWeaviateClient();
3676
3737
  const collectionName = getMemoryCollectionName(userId);
3677
3738
  console.log("[remember_publish] Fetching memory from collection:", collectionName);
@@ -3730,6 +3791,7 @@ async function handlePublish(args, userId) {
3730
3791
  }
3731
3792
  const payload = {
3732
3793
  memory_id: args.memory_id,
3794
+ spaces: args.spaces,
3733
3795
  additional_tags: args.additional_tags || []
3734
3796
  };
3735
3797
  console.log("[remember_publish] Generating confirmation token");
@@ -3737,7 +3799,8 @@ async function handlePublish(args, userId) {
3737
3799
  userId,
3738
3800
  "publish_memory",
3739
3801
  payload,
3740
- args.target
3802
+ void 0
3803
+ // No single target_collection anymore
3741
3804
  );
3742
3805
  console.log("[remember_publish] Token generated:", {
3743
3806
  requestId,
@@ -3753,12 +3816,12 @@ async function handlePublish(args, userId) {
3753
3816
  2
3754
3817
  );
3755
3818
  } catch (error) {
3756
- handleToolError(error, {
3819
+ return handleToolError(error, {
3757
3820
  toolName: "remember_publish",
3758
3821
  userId,
3759
3822
  operation: "publish memory",
3760
3823
  memory_id: args.memory_id,
3761
- target: args.target
3824
+ spaces: args.spaces
3762
3825
  });
3763
3826
  }
3764
3827
  }
@@ -3820,7 +3883,8 @@ async function executePublishMemory(request, userId) {
3820
3883
  console.log("[executePublishMemory] Starting execution:", {
3821
3884
  userId,
3822
3885
  memoryId: request.payload.memory_id,
3823
- targetSpace: request.target_collection
3886
+ spaces: request.payload.spaces,
3887
+ spaceCount: request.payload.spaces?.length || 0
3824
3888
  });
3825
3889
  const weaviateClient = getWeaviateClient();
3826
3890
  const userCollection = weaviateClient.collections.get(
@@ -3858,18 +3922,16 @@ async function executePublishMemory(request, userId) {
3858
3922
  2
3859
3923
  );
3860
3924
  }
3861
- console.log("[executePublishMemory] Ensuring space collection:", request.target_collection || "the_void");
3862
- const targetCollection = await ensureSpaceCollection(
3863
- weaviateClient,
3864
- request.target_collection || "the_void"
3865
- );
3866
- console.log("[executePublishMemory] Space collection ready");
3925
+ console.log("[executePublishMemory] Ensuring public collection");
3926
+ const publicCollection = await ensurePublicCollection(weaviateClient);
3927
+ console.log("[executePublishMemory] Public collection ready");
3867
3928
  const originalTags = Array.isArray(originalMemory.properties.tags) ? originalMemory.properties.tags : [];
3868
3929
  const additionalTags = Array.isArray(request.payload.additional_tags) ? request.payload.additional_tags : [];
3869
3930
  const publishedMemory = {
3870
3931
  ...originalMemory.properties,
3871
3932
  // Add space-specific fields
3872
- space_id: request.target_collection || "the_void",
3933
+ spaces: request.payload.spaces || ["the_void"],
3934
+ // ✅ Array of spaces!
3873
3935
  author_id: userId,
3874
3936
  // Track original author
3875
3937
  published_at: (/* @__PURE__ */ new Date()).toISOString(),
@@ -3883,14 +3945,14 @@ async function executePublishMemory(request, userId) {
3883
3945
  updated_at: (/* @__PURE__ */ new Date()).toISOString(),
3884
3946
  version: 1
3885
3947
  };
3886
- console.log("[executePublishMemory] Inserting into space collection:", {
3887
- spaceId: request.target_collection || "the_void",
3948
+ console.log("[executePublishMemory] Inserting into Memory_public:", {
3949
+ spaces: request.payload.spaces,
3950
+ spaceCount: request.payload.spaces?.length || 0,
3888
3951
  memoryId: request.payload.memory_id,
3889
3952
  hasUserId: !!publishedMemory.user_id,
3890
- hasAuthorId: !!publishedMemory.author_id,
3891
- hasSpaceId: !!publishedMemory.space_id
3953
+ hasAuthorId: !!publishedMemory.author_id
3892
3954
  });
3893
- const result = await targetCollection.data.insert(publishedMemory);
3955
+ const result = await publicCollection.data.insert(publishedMemory);
3894
3956
  console.log("[executePublishMemory] Insert result:", {
3895
3957
  success: !!result,
3896
3958
  spaceMemoryId: result
@@ -3898,7 +3960,8 @@ async function executePublishMemory(request, userId) {
3898
3960
  return JSON.stringify(
3899
3961
  {
3900
3962
  success: true,
3901
- space_memory_id: result
3963
+ space_memory_id: result,
3964
+ spaces: request.payload.spaces || ["the_void"]
3902
3965
  },
3903
3966
  null,
3904
3967
  2
@@ -3964,7 +4027,7 @@ import { Filters as Filters3 } from "weaviate-client";
3964
4027
  init_space_memory();
3965
4028
  var searchSpaceTool = {
3966
4029
  name: "remember_search_space",
3967
- description: "Search shared spaces to discover thoughts, ideas, and memories. Works like remember_search_memory but searches shared spaces instead of personal memories.",
4030
+ description: "Search one or more shared spaces to discover thoughts, ideas, and memories. Works like remember_search_memory but searches shared spaces instead of personal memories. Can search multiple spaces in a single query.",
3968
4031
  inputSchema: {
3969
4032
  type: "object",
3970
4033
  properties: {
@@ -3972,11 +4035,15 @@ var searchSpaceTool = {
3972
4035
  type: "string",
3973
4036
  description: "Search query (semantic + keyword hybrid)"
3974
4037
  },
3975
- space: {
3976
- type: "string",
3977
- description: "Which space to search",
3978
- enum: SUPPORTED_SPACES,
3979
- default: "the_void"
4038
+ spaces: {
4039
+ type: "array",
4040
+ items: {
4041
+ type: "string",
4042
+ enum: SUPPORTED_SPACES
4043
+ },
4044
+ description: 'Spaces to search (e.g., ["the_void", "dogs"]). Can search multiple spaces at once.',
4045
+ minItems: 1,
4046
+ default: ["the_void"]
3980
4047
  },
3981
4048
  content_type: {
3982
4049
  type: "string",
@@ -4018,49 +4085,66 @@ var searchSpaceTool = {
4018
4085
  description: "Offset for pagination"
4019
4086
  }
4020
4087
  },
4021
- required: ["query", "space"]
4088
+ required: ["query", "spaces"]
4022
4089
  }
4023
4090
  };
4024
4091
  async function handleSearchSpace(args, userId) {
4025
4092
  try {
4026
- if (!isValidSpaceId(args.space)) {
4093
+ const invalidSpaces = args.spaces.filter((s) => !isValidSpaceId(s));
4094
+ if (invalidSpaces.length > 0) {
4027
4095
  return JSON.stringify(
4028
4096
  {
4029
4097
  success: false,
4030
- error: "Invalid space ID",
4031
- message: `Space "${args.space}" is not supported. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`
4098
+ error: "Invalid space IDs",
4099
+ message: `Invalid spaces: ${invalidSpaces.join(", ")}. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`,
4100
+ context: {
4101
+ invalid_spaces: invalidSpaces,
4102
+ provided_spaces: args.spaces,
4103
+ supported_spaces: SUPPORTED_SPACES
4104
+ }
4105
+ },
4106
+ null,
4107
+ 2
4108
+ );
4109
+ }
4110
+ if (args.spaces.length === 0) {
4111
+ return JSON.stringify(
4112
+ {
4113
+ success: false,
4114
+ error: "Empty spaces array",
4115
+ message: "Must specify at least one space to search"
4032
4116
  },
4033
4117
  null,
4034
4118
  2
4035
4119
  );
4036
4120
  }
4037
4121
  const weaviateClient = getWeaviateClient();
4038
- const spaceCollection = await ensureSpaceCollection(weaviateClient, args.space);
4122
+ const publicCollection = await ensurePublicCollection(weaviateClient);
4039
4123
  const filterList = [];
4040
- filterList.push(spaceCollection.filter.byProperty("space_id").equal(args.space));
4041
- filterList.push(spaceCollection.filter.byProperty("doc_type").equal("space_memory"));
4124
+ filterList.push(publicCollection.filter.byProperty("spaces").containsAny(args.spaces));
4125
+ filterList.push(publicCollection.filter.byProperty("doc_type").equal("space_memory"));
4042
4126
  if (args.content_type) {
4043
- filterList.push(spaceCollection.filter.byProperty("type").equal(args.content_type));
4127
+ filterList.push(publicCollection.filter.byProperty("type").equal(args.content_type));
4044
4128
  }
4045
4129
  if (args.tags && args.tags.length > 0) {
4046
4130
  args.tags.forEach((tag) => {
4047
- filterList.push(spaceCollection.filter.byProperty("tags").containsAny([tag]));
4131
+ filterList.push(publicCollection.filter.byProperty("tags").containsAny([tag]));
4048
4132
  });
4049
4133
  }
4050
4134
  if (args.min_weight !== void 0) {
4051
- filterList.push(spaceCollection.filter.byProperty("weight").greaterOrEqual(args.min_weight));
4135
+ filterList.push(publicCollection.filter.byProperty("weight").greaterOrEqual(args.min_weight));
4052
4136
  }
4053
4137
  if (args.max_weight !== void 0) {
4054
- filterList.push(spaceCollection.filter.byProperty("weight").lessOrEqual(args.max_weight));
4138
+ filterList.push(publicCollection.filter.byProperty("weight").lessOrEqual(args.max_weight));
4055
4139
  }
4056
4140
  if (args.date_from) {
4057
- filterList.push(spaceCollection.filter.byProperty("created_at").greaterOrEqual(new Date(args.date_from)));
4141
+ filterList.push(publicCollection.filter.byProperty("created_at").greaterOrEqual(new Date(args.date_from)));
4058
4142
  }
4059
4143
  if (args.date_to) {
4060
- filterList.push(spaceCollection.filter.byProperty("created_at").lessOrEqual(new Date(args.date_to)));
4144
+ filterList.push(publicCollection.filter.byProperty("created_at").lessOrEqual(new Date(args.date_to)));
4061
4145
  }
4062
4146
  const whereFilter = filterList.length > 0 ? Filters3.and(...filterList) : void 0;
4063
- const searchResults = await spaceCollection.query.hybrid(args.query, {
4147
+ const searchResults = await publicCollection.query.hybrid(args.query, {
4064
4148
  limit: args.limit || 10,
4065
4149
  offset: args.offset || 0,
4066
4150
  ...whereFilter && { where: whereFilter }
@@ -4071,7 +4155,7 @@ async function handleSearchSpace(args, userId) {
4071
4155
  _score: obj.metadata?.score
4072
4156
  }));
4073
4157
  const result = {
4074
- space: args.space,
4158
+ spaces_searched: args.spaces,
4075
4159
  query: args.query,
4076
4160
  memories,
4077
4161
  total: memories.length,
@@ -4080,10 +4164,10 @@ async function handleSearchSpace(args, userId) {
4080
4164
  };
4081
4165
  return JSON.stringify(result, null, 2);
4082
4166
  } catch (error) {
4083
- handleToolError(error, {
4167
+ return handleToolError(error, {
4084
4168
  toolName: "remember_search_space",
4085
- operation: "search space",
4086
- space: args.space,
4169
+ operation: "search spaces",
4170
+ spaces: args.spaces,
4087
4171
  query: args.query
4088
4172
  });
4089
4173
  }
@@ -4143,46 +4227,58 @@ var querySpaceTool = {
4143
4227
  description: "Output format: detailed (full objects) or compact (text summary)"
4144
4228
  }
4145
4229
  },
4146
- required: ["question", "space"]
4230
+ required: ["question", "spaces"]
4147
4231
  }
4148
4232
  };
4149
4233
  async function handleQuerySpace(args, userId) {
4150
4234
  try {
4151
- if (!isValidSpaceId(args.space)) {
4235
+ const invalidSpaces = args.spaces.filter((s) => !isValidSpaceId(s));
4236
+ if (invalidSpaces.length > 0) {
4152
4237
  return JSON.stringify(
4153
4238
  {
4154
4239
  success: false,
4155
- error: "Invalid space ID",
4156
- message: `Space "${args.space}" is not supported. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`
4240
+ error: "Invalid space IDs",
4241
+ message: `Invalid spaces: ${invalidSpaces.join(", ")}. Supported spaces: ${SUPPORTED_SPACES.join(", ")}`
4242
+ },
4243
+ null,
4244
+ 2
4245
+ );
4246
+ }
4247
+ if (args.spaces.length === 0) {
4248
+ return JSON.stringify(
4249
+ {
4250
+ success: false,
4251
+ error: "Empty spaces array",
4252
+ message: "Must specify at least one space to query"
4157
4253
  },
4158
4254
  null,
4159
4255
  2
4160
4256
  );
4161
4257
  }
4162
4258
  const weaviateClient = getWeaviateClient();
4163
- const spaceCollection = await ensureSpaceCollection(weaviateClient, args.space);
4259
+ const publicCollection = await ensurePublicCollection(weaviateClient);
4164
4260
  const filterList = [];
4165
- filterList.push(spaceCollection.filter.byProperty("space_id").equal(args.space));
4166
- filterList.push(spaceCollection.filter.byProperty("doc_type").equal("space_memory"));
4261
+ filterList.push(publicCollection.filter.byProperty("spaces").containsAny(args.spaces));
4262
+ filterList.push(publicCollection.filter.byProperty("doc_type").equal("space_memory"));
4167
4263
  if (args.content_type) {
4168
- filterList.push(spaceCollection.filter.byProperty("type").equal(args.content_type));
4264
+ filterList.push(publicCollection.filter.byProperty("type").equal(args.content_type));
4169
4265
  }
4170
4266
  if (args.tags && args.tags.length > 0) {
4171
4267
  args.tags.forEach((tag) => {
4172
- filterList.push(spaceCollection.filter.byProperty("tags").containsAny([tag]));
4268
+ filterList.push(publicCollection.filter.byProperty("tags").containsAny([tag]));
4173
4269
  });
4174
4270
  }
4175
4271
  if (args.min_weight !== void 0) {
4176
- filterList.push(spaceCollection.filter.byProperty("weight").greaterOrEqual(args.min_weight));
4272
+ filterList.push(publicCollection.filter.byProperty("weight").greaterOrEqual(args.min_weight));
4177
4273
  }
4178
4274
  if (args.date_from) {
4179
- filterList.push(spaceCollection.filter.byProperty("created_at").greaterOrEqual(new Date(args.date_from)));
4275
+ filterList.push(publicCollection.filter.byProperty("created_at").greaterOrEqual(new Date(args.date_from)));
4180
4276
  }
4181
4277
  if (args.date_to) {
4182
- filterList.push(spaceCollection.filter.byProperty("created_at").lessOrEqual(new Date(args.date_to)));
4278
+ filterList.push(publicCollection.filter.byProperty("created_at").lessOrEqual(new Date(args.date_to)));
4183
4279
  }
4184
4280
  const whereFilter = filterList.length > 0 ? Filters4.and(...filterList) : void 0;
4185
- const searchResults = await spaceCollection.query.nearText(args.question, {
4281
+ const searchResults = await publicCollection.query.nearText(args.question, {
4186
4282
  limit: args.limit || 10,
4187
4283
  ...whereFilter && { where: whereFilter }
4188
4284
  });
@@ -4194,7 +4290,7 @@ async function handleQuerySpace(args, userId) {
4194
4290
  });
4195
4291
  const result = {
4196
4292
  question: args.question,
4197
- space: args.space,
4293
+ spaces_queried: args.spaces,
4198
4294
  format: "compact",
4199
4295
  summary: summaries.join("\n"),
4200
4296
  count: searchResults.objects.length
@@ -4208,7 +4304,7 @@ async function handleQuerySpace(args, userId) {
4208
4304
  }));
4209
4305
  const result = {
4210
4306
  question: args.question,
4211
- space: args.space,
4307
+ spaces_queried: args.spaces,
4212
4308
  format: "detailed",
4213
4309
  memories,
4214
4310
  total: memories.length
@@ -4216,10 +4312,10 @@ async function handleQuerySpace(args, userId) {
4216
4312
  return JSON.stringify(result, null, 2);
4217
4313
  }
4218
4314
  } catch (error) {
4219
- handleToolError(error, {
4315
+ return handleToolError(error, {
4220
4316
  toolName: "remember_query_space",
4221
- operation: "query space",
4222
- space: args.space,
4317
+ operation: "query spaces",
4318
+ spaces: args.spaces,
4223
4319
  question: args.question
4224
4320
  });
4225
4321
  }
@@ -11,7 +11,7 @@ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
11
11
  export declare const publishTool: Tool;
12
12
  interface PublishArgs {
13
13
  memory_id: string;
14
- target: string;
14
+ spaces: string[];
15
15
  additional_tags?: string[];
16
16
  }
17
17
  /**
@@ -11,7 +11,7 @@ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
11
11
  export declare const querySpaceTool: Tool;
12
12
  interface QuerySpaceArgs {
13
13
  question: string;
14
- space: string;
14
+ spaces: string[];
15
15
  content_type?: string;
16
16
  tags?: string[];
17
17
  min_weight?: number;
@@ -11,7 +11,7 @@ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
11
11
  export declare const searchSpaceTool: Tool;
12
12
  interface SearchSpaceArgs {
13
13
  query: string;
14
- space: string;
14
+ spaces: string[];
15
15
  content_type?: string;
16
16
  tags?: string[];
17
17
  min_weight?: number;
@@ -12,10 +12,12 @@ import type { Memory, SearchOptions, SearchResult } from './memory.js';
12
12
  */
13
13
  export interface SpaceMemory extends Omit<Memory, 'user_id' | 'doc_type'> {
14
14
  /**
15
- * Space identifier (snake_case)
16
- * Examples: 'the_void', 'public_space'
15
+ * Spaces this memory is published to (snake_case array)
16
+ * Examples: ['the_void'], ['dogs', 'cats'], ['the_void', 'dogs']
17
+ *
18
+ * A memory can belong to multiple spaces simultaneously.
17
19
  */
18
- space_id: string;
20
+ spaces: string[];
19
21
  /**
20
22
  * Original author's user_id (for permissions)
21
23
  * This is private and not shown publicly
@@ -5,9 +5,14 @@
5
5
  * for discovery by other users.
6
6
  */
7
7
  import { type WeaviateClient, type Collection } from 'weaviate-client';
8
+ /**
9
+ * Unified public collection name for all public spaces
10
+ */
11
+ export declare const PUBLIC_COLLECTION_NAME = "Memory_public";
8
12
  /**
9
13
  * Get collection name for a space
10
14
  *
15
+ * @deprecated Use PUBLIC_COLLECTION_NAME instead. Will be removed in v3.0.0.
11
16
  * @param spaceId - Space identifier (snake_case)
12
17
  * @returns Collection name in format Memory_{space_id}
13
18
  *
@@ -45,9 +50,20 @@ export declare function getSpaceDisplayName(spaceId: string): string;
45
50
  * @returns True if valid, false otherwise
46
51
  */
47
52
  export declare function isValidSpaceId(spaceId: string): boolean;
53
+ /**
54
+ * Ensure the unified public collection exists, creating it if needed
55
+ *
56
+ * @param client - Weaviate client
57
+ * @returns Collection reference to Memory_public
58
+ *
59
+ * @example
60
+ * const collection = await ensurePublicCollection(client);
61
+ */
62
+ export declare function ensurePublicCollection(client: WeaviateClient): Promise<Collection<any>>;
48
63
  /**
49
64
  * Ensure a space collection exists, creating it if needed
50
65
  *
66
+ * @deprecated Use ensurePublicCollection() instead. Will be removed in v3.0.0.
51
67
  * @param client - Weaviate client
52
68
  * @param spaceId - Space identifier
53
69
  * @returns Collection reference
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prmichaelsen/remember-mcp",
3
- "version": "2.3.4",
3
+ "version": "2.5.1",
4
4
  "description": "Multi-tenant memory system MCP server with vector search and relationships",
5
5
  "main": "dist/server.js",
6
6
  "type": "module",