@prmichaelsen/remember-mcp 3.15.7 → 3.16.2

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 (49) hide show
  1. package/.github/workflows/publish.yml +55 -0
  2. package/CHANGELOG.md +20 -0
  3. package/agent/design/local.unified-internal-memory-tools.md +325 -0
  4. package/agent/milestones/milestone-20-unified-internal-memory-tools.md +58 -0
  5. package/agent/progress.yaml +115 -1
  6. package/agent/tasks/milestone-20-unified-internal-memory-tools/task-212-add-internal-context-type.md +54 -0
  7. package/agent/tasks/milestone-20-unified-internal-memory-tools/task-213-update-server-factory-internal-context.md +117 -0
  8. package/agent/tasks/milestone-20-unified-internal-memory-tools/task-214-create-tag-builder-utility.md +50 -0
  9. package/agent/tasks/milestone-20-unified-internal-memory-tools/task-215-create-unified-internal-memory-tools.md +65 -0
  10. package/agent/tasks/milestone-20-unified-internal-memory-tools/task-216-update-default-search-filters.md +46 -0
  11. package/agent/tasks/milestone-20-unified-internal-memory-tools/task-217-delete-standalone-ghost-tools.md +46 -0
  12. package/agent/tasks/milestone-20-unified-internal-memory-tools/task-218-add-tests-unified-internal-tools.md +66 -0
  13. package/dist/e2e-helpers.d.ts +1 -1
  14. package/dist/server-factory.d.ts +17 -41
  15. package/dist/server-factory.js +420 -149
  16. package/dist/server.js +202 -20
  17. package/dist/tools/{create-ghost-memory.d.ts → create-internal-memory.d.ts} +7 -9
  18. package/dist/tools/internal-tools.spec.d.ts +2 -0
  19. package/dist/tools/{query-ghost-memory.d.ts → query-internal-memory.d.ts} +6 -6
  20. package/dist/tools/{search-ghost-memory-by.d.ts → search-internal-memory-by.d.ts} +6 -6
  21. package/dist/tools/{search-ghost-memory.d.ts → search-internal-memory.d.ts} +6 -6
  22. package/dist/tools/{update-ghost-memory.d.ts → update-internal-memory.d.ts} +6 -6
  23. package/dist/types/auth.d.ts +22 -8
  24. package/dist/utils/internal-tags.d.ts +14 -0
  25. package/dist/utils/internal-tags.spec.d.ts +2 -0
  26. package/package.json +2 -3
  27. package/src/e2e-helpers.ts +4 -2
  28. package/src/ghost-persona.e2e.ts +18 -17
  29. package/src/server-factory.ts +117 -55
  30. package/src/tools/create-internal-memory.ts +105 -0
  31. package/src/tools/find-similar.ts +2 -2
  32. package/src/tools/internal-tools.spec.ts +312 -0
  33. package/src/tools/query-internal-memory.ts +73 -0
  34. package/src/tools/query-memory.ts +15 -12
  35. package/src/tools/search-by.spec.ts +6 -2
  36. package/src/tools/search-by.ts +6 -6
  37. package/src/tools/{search-ghost-memory-by.ts → search-internal-memory-by.ts} +34 -27
  38. package/src/tools/search-internal-memory.ts +87 -0
  39. package/src/tools/search-memory.ts +15 -12
  40. package/src/tools/search-space.ts +1 -0
  41. package/src/tools/{update-ghost-memory.ts → update-internal-memory.ts} +23 -17
  42. package/src/types/auth.ts +22 -8
  43. package/src/utils/internal-tags.spec.ts +104 -0
  44. package/src/utils/internal-tags.ts +46 -0
  45. package/dist/tools/ghost-tools.spec.d.ts +0 -2
  46. package/src/tools/create-ghost-memory.ts +0 -103
  47. package/src/tools/ghost-tools.spec.ts +0 -361
  48. package/src/tools/query-ghost-memory.ts +0 -63
  49. package/src/tools/search-ghost-memory.ts +0 -73
@@ -10,11 +10,11 @@ import {
10
10
  e2eEnsureCollection, e2eCleanup, parseResult, waitForIndex,
11
11
  } from './e2e-helpers.js';
12
12
  import { handleGhostConfig } from './tools/ghost-config.js';
13
- import { handleCreateGhostMemory } from './tools/create-ghost-memory.js';
14
- import { handleSearchGhostMemory } from './tools/search-ghost-memory.js';
15
- import { handleUpdateGhostMemory } from './tools/update-ghost-memory.js';
16
- import { handleQueryGhostMemory } from './tools/query-ghost-memory.js';
17
- import { handleSearchGhostMemoryBy } from './tools/search-ghost-memory-by.js';
13
+ import { handleCreateInternalMemory } from './tools/create-internal-memory.js';
14
+ import { handleSearchInternalMemory } from './tools/search-internal-memory.js';
15
+ import { handleUpdateInternalMemory } from './tools/update-internal-memory.js';
16
+ import { handleQueryInternalMemory } from './tools/query-internal-memory.js';
17
+ import { handleSearchInternalMemoryBy } from './tools/search-internal-memory-by.js';
18
18
  import { handleGetCore } from './tools/get-core.js';
19
19
 
20
20
  const ownerId = e2eUserId('ghost_owner');
@@ -79,7 +79,7 @@ describe('E2E: Ghost/Persona', () => {
79
79
  // -------------------------------------------------------------------------
80
80
 
81
81
  it('creates a ghost memory', async () => {
82
- const res = parseResult(await handleCreateGhostMemory(
82
+ const res = parseResult(await handleCreateInternalMemory(
83
83
  {
84
84
  content: `${accessorId} asked about my favorite hiking trails. They seem genuinely interested in outdoor activities.`,
85
85
  weight: 0.6,
@@ -94,7 +94,8 @@ describe('E2E: Ghost/Persona', () => {
94
94
  expect(res.memory_id).toBeTruthy();
95
95
  expect(res.content_type).toBe('ghost');
96
96
  expect(res.tags).toContain('ghost');
97
- expect(res.tags).toContain(`ghost:${accessorId}`);
97
+ expect(res.tags).toContain('ghost_type:user');
98
+ expect(res.tags).toContain(`ghost_owner:user:${ownerId}`);
98
99
  ghostMemoryId = res.memory_id;
99
100
  console.log(` created ghost memory ${ghostMemoryId}`);
100
101
  });
@@ -106,10 +107,10 @@ describe('E2E: Ghost/Persona', () => {
106
107
  it('searches ghost memories', async () => {
107
108
  await waitForIndex(5000);
108
109
 
109
- // Search ghost memories specifically
110
- const res = parseResult(await handleSearchGhostMemory(
110
+ // Search ghost memories via unified internal tool
111
+ const res = parseResult(await handleSearchInternalMemory(
111
112
  { query: 'hiking trails outdoor activities', limit: 5 },
112
- ownerId, ownerAuth,
113
+ ownerId, ghostAuth,
113
114
  ));
114
115
 
115
116
  expect(res.memories).toBeDefined();
@@ -123,7 +124,7 @@ describe('E2E: Ghost/Persona', () => {
123
124
  // -------------------------------------------------------------------------
124
125
 
125
126
  it('updates the ghost memory', async () => {
126
- const res = parseResult(await handleUpdateGhostMemory(
127
+ const res = parseResult(await handleUpdateInternalMemory(
127
128
  {
128
129
  memory_id: ghostMemoryId,
129
130
  content: `${accessorId} asked about my favorite hiking trails. They seem genuinely interested in outdoor activities. Follow-up: they mentioned they go rock climbing too.`,
@@ -141,10 +142,10 @@ describe('E2E: Ghost/Persona', () => {
141
142
  it('queries ghost memories with natural language', async () => {
142
143
  await waitForIndex();
143
144
 
144
- // Use ownerAuth to avoid trust filter — query is already filtered to ghost content_type
145
- const res = parseResult(await handleQueryGhostMemory(
145
+ // Use ghostAuth — query is auto-scoped to ghost content_type via internal context
146
+ const res = parseResult(await handleQueryInternalMemory(
146
147
  { query: 'What are the accessor\'s outdoor interests?', limit: 5, min_relevance: 0.3 },
147
- ownerId, ownerAuth,
148
+ ownerId, ghostAuth,
148
149
  ));
149
150
 
150
151
  expect(res.memories).toBeDefined();
@@ -160,10 +161,10 @@ describe('E2E: Ghost/Persona', () => {
160
161
  // This creates an impossible filter: content_type='ghost' AND content_type!='ghost'.
161
162
  // Fix: core should skip ghost exclusion when types filter explicitly includes 'ghost'.
162
163
  // This test WILL FAIL until the core bug is fixed.
163
- it('search_ghost_memory_by byTime returns ghost results', async () => {
164
- const res = parseResult(await handleSearchGhostMemoryBy(
164
+ it('search_internal_memory_by byTime returns ghost results', async () => {
165
+ const res = parseResult(await handleSearchInternalMemoryBy(
165
166
  { mode: 'byTime', limit: 5 },
166
- ownerId, ownerAuth,
167
+ ownerId, ghostAuth,
167
168
  ));
168
169
 
169
170
  expect(res.memories).toBeDefined();
@@ -46,12 +46,12 @@ import { moderateTool, handleModerate } from './tools/moderate.js';
46
46
  import { ghostConfigTool, handleGhostConfig } from './tools/ghost-config.js';
47
47
  import { searchByTool, handleSearchBy } from './tools/search-by.js';
48
48
 
49
- // Import ghost memory tools
50
- import { createGhostMemoryTool, handleCreateGhostMemory } from './tools/create-ghost-memory.js';
51
- import { updateGhostMemoryTool, handleUpdateGhostMemory } from './tools/update-ghost-memory.js';
52
- import { searchGhostMemoryTool, handleSearchGhostMemory } from './tools/search-ghost-memory.js';
53
- import { queryGhostMemoryTool, handleQueryGhostMemory } from './tools/query-ghost-memory.js';
54
- import { searchGhostMemoryByTool, handleSearchGhostMemoryBy } from './tools/search-ghost-memory-by.js';
49
+ // Import unified internal memory tools
50
+ import { createInternalMemoryTool, handleCreateInternalMemory } from './tools/create-internal-memory.js';
51
+ import { updateInternalMemoryTool, handleUpdateInternalMemory } from './tools/update-internal-memory.js';
52
+ import { searchInternalMemoryTool, handleSearchInternalMemory } from './tools/search-internal-memory.js';
53
+ import { queryInternalMemoryTool, handleQueryInternalMemory } from './tools/query-internal-memory.js';
54
+ import { searchInternalMemoryByTool, handleSearchInternalMemoryBy } from './tools/search-internal-memory-by.js';
55
55
 
56
56
  // Import core introspection tools
57
57
  import { getCoreTool, handleGetCore } from './tools/get-core.js';
@@ -65,18 +65,25 @@ export interface ServerOptions {
65
65
  name?: string;
66
66
  version?: string;
67
67
  /**
68
- * Ghost mode configuration. When set, the server operates in ghost mode:
69
- * - Search/query tools search the ghost owner's collection
70
- * - Trust filtering is applied based on the accessor's trust level
71
- * - Trust level is resolved server-side from GhostConfig (Firestore)
68
+ * Internal context for ghost/agent sessions. When set, the server provides
69
+ * unified internal memory tools with behavior driven by the context type.
72
70
  *
73
- * agentbase.me sets this when creating a ghost conversation server.
71
+ * Populated from platform HTTP headers via mcp-auth extras:
72
+ * X-Internal-Type → type ('ghost' | 'agent')
73
+ * X-Ghost-Owner → owner_user_id
74
+ * X-Ghost-Type → ghost_type ('user' | 'space' | 'group')
75
+ * X-Ghost-Space → ghost_space
76
+ * X-Ghost-Group → ghost_group
77
+ *
78
+ * Trust level is resolved server-side from GhostConfig (Firestore).
74
79
  * The LLM never has access to set or override these values.
75
80
  */
76
- ghostMode?: {
77
- /** Ghost owner's user ID (whose memories to search) */
78
- owner_user_id: string;
79
- /** Accessor's user ID (who is chatting with the ghost) */
81
+ internalContext?: {
82
+ type: 'ghost' | 'agent';
83
+ ghost_type?: 'user' | 'space' | 'group';
84
+ ghost_space?: string;
85
+ ghost_group?: string;
86
+ owner_user_id?: string;
80
87
  accessor_user_id: string;
81
88
  };
82
89
  }
@@ -157,29 +164,72 @@ async function ensureDatabasesInitialized(): Promise<void> {
157
164
  * });
158
165
  * ```
159
166
  */
167
+ /**
168
+ * Normalize flat mcp-auth extras into structured ServerOptions.
169
+ *
170
+ * mcp-auth strips X- prefix and converts hyphens to underscores:
171
+ * X-Internal-Type → internal_type
172
+ * X-Ghost-Owner → ghost_owner
173
+ * X-Ghost-Type → ghost_type
174
+ * X-Ghost-Space → ghost_space
175
+ * X-Ghost-Group → ghost_group
176
+ */
177
+ function normalizeOptions(
178
+ raw: ServerOptions | Record<string, string | string[] | undefined>,
179
+ userId: string
180
+ ): ServerOptions {
181
+ // Already structured — has internalContext or no internal_type key
182
+ if ('internalContext' in raw || !('internal_type' in raw)) {
183
+ return raw as ServerOptions;
184
+ }
185
+
186
+ // Flat extras from mcp-auth
187
+ const extras = raw as Record<string, string | string[] | undefined>;
188
+ const internalType = extras.internal_type as string | undefined;
189
+
190
+ if (!internalType) {
191
+ return {};
192
+ }
193
+
194
+ return {
195
+ internalContext: {
196
+ type: internalType as 'ghost' | 'agent',
197
+ ghost_type: extras.ghost_type as 'user' | 'space' | 'group' | undefined,
198
+ ghost_space: extras.ghost_space as string | undefined,
199
+ ghost_group: extras.ghost_group as string | undefined,
200
+ owner_user_id: extras.ghost_owner as string | undefined,
201
+ accessor_user_id: userId,
202
+ },
203
+ };
204
+ }
205
+
160
206
  export async function createServer(
161
207
  accessToken: string,
162
208
  userId: string,
163
- options: ServerOptions = {}
209
+ options: ServerOptions | Record<string, string | string[] | undefined> = {}
164
210
  ): Promise<Server> {
165
211
  // Note: accessToken is not used by remember-mcp (self-managed data)
166
212
  // but required by mcp-auth contract. Can be any value including empty string.
167
-
213
+
168
214
  if (!userId) {
169
215
  throw new Error('userId is required');
170
216
  }
171
-
217
+
218
+ // Normalize: mcp-auth passes flat extras (e.g. { internal_type: 'ghost', ghost_owner: 'alice' })
219
+ // Direct callers pass structured ServerOptions (e.g. { internalContext: { type: 'ghost', ... } })
220
+ const opts = normalizeOptions(options, userId);
221
+
172
222
  logger.debug('Creating server instance', { userId });
173
-
223
+
174
224
  // Ensure databases are initialized (happens once globally)
175
225
  // Initialization must succeed or server creation fails
176
226
  await ensureDatabasesInitialized();
177
-
227
+
178
228
  // Create MCP server
179
229
  const server = new Server(
180
230
  {
181
- name: options.name || 'remember-mcp',
182
- version: options.version || '0.2.0',
231
+ name: opts.name || 'remember-mcp',
232
+ version: opts.version || '0.2.0',
183
233
  },
184
234
  {
185
235
  capabilities: {
@@ -187,26 +237,38 @@ export async function createServer(
187
237
  },
188
238
  }
189
239
  );
190
-
191
- // Resolve ghost mode trust level from Firestore if ghost mode is configured
192
- let resolvedGhostMode: import('./types/auth.js').GhostModeContext | undefined;
193
- if (options.ghostMode) {
194
- const ghostConfig = await getGhostConfig(options.ghostMode.owner_user_id);
195
- const trustLevel = await resolveAccessorTrustLevel(ghostConfig, options.ghostMode.owner_user_id, options.ghostMode.accessor_user_id);
196
- resolvedGhostMode = {
197
- owner_user_id: options.ghostMode.owner_user_id,
198
- accessor_user_id: options.ghostMode.accessor_user_id,
199
- accessor_trust_level: trustLevel,
240
+
241
+ // Resolve internal context with trust level from Firestore if ghost mode
242
+ let resolvedInternalContext: import('./types/auth.js').InternalContext | undefined;
243
+ if (opts.internalContext) {
244
+ const ic = opts.internalContext;
245
+ let accessorTrustLevel: number | undefined;
246
+
247
+ if (ic.type === 'ghost' && ic.owner_user_id) {
248
+ const ghostConfig = await getGhostConfig(ic.owner_user_id);
249
+ accessorTrustLevel = await resolveAccessorTrustLevel(ghostConfig, ic.owner_user_id, ic.accessor_user_id);
250
+ }
251
+
252
+ resolvedInternalContext = {
253
+ type: ic.type,
254
+ ghost_type: ic.ghost_type,
255
+ ghost_space: ic.ghost_space,
256
+ ghost_group: ic.ghost_group,
257
+ owner_user_id: ic.owner_user_id,
258
+ accessor_user_id: ic.accessor_user_id,
259
+ accessor_trust_level: accessorTrustLevel,
200
260
  };
201
- logger.info('Ghost mode resolved', {
202
- ownerUserId: resolvedGhostMode.owner_user_id,
203
- accessorUserId: resolvedGhostMode.accessor_user_id,
204
- trustLevel: resolvedGhostMode.accessor_trust_level,
261
+ logger.info('Internal context resolved', {
262
+ type: resolvedInternalContext.type,
263
+ ghostType: resolvedInternalContext.ghost_type,
264
+ ownerUserId: resolvedInternalContext.owner_user_id,
265
+ accessorUserId: resolvedInternalContext.accessor_user_id,
266
+ trustLevel: resolvedInternalContext.accessor_trust_level,
205
267
  });
206
268
  }
207
269
 
208
270
  // Register handlers with userId scope
209
- registerHandlers(server, userId, accessToken, resolvedGhostMode);
271
+ registerHandlers(server, userId, accessToken, resolvedInternalContext);
210
272
 
211
273
  return server;
212
274
  }
@@ -218,7 +280,7 @@ function registerHandlers(
218
280
  server: Server,
219
281
  userId: string,
220
282
  accessToken: string,
221
- ghostMode?: import('./types/auth.js').GhostModeContext
283
+ internalContext?: import('./types/auth.js').InternalContext
222
284
  ): void {
223
285
  // List available tools
224
286
  server.setRequestHandler(ListToolsRequestSchema, async () => {
@@ -251,12 +313,12 @@ function registerHandlers(
251
313
  ghostConfigTool,
252
314
  // Search modes
253
315
  searchByTool,
254
- // Ghost memory tools
255
- createGhostMemoryTool,
256
- updateGhostMemoryTool,
257
- searchGhostMemoryTool,
258
- queryGhostMemoryTool,
259
- searchGhostMemoryByTool,
316
+ // Unified internal memory tools
317
+ createInternalMemoryTool,
318
+ updateInternalMemoryTool,
319
+ searchInternalMemoryTool,
320
+ queryInternalMemoryTool,
321
+ searchInternalMemoryByTool,
260
322
  // Core introspection
261
323
  getCoreTool,
262
324
  // Space search modes
@@ -272,7 +334,7 @@ function registerHandlers(
272
334
  try {
273
335
  // Resolve credentials once per request
274
336
  const credentials = await credentialsProvider.getCredentials(accessToken, userId);
275
- const authContext: AuthContext = { accessToken, credentials, ghostMode };
337
+ const authContext: AuthContext = { accessToken, credentials, internalContext };
276
338
 
277
339
  let result: string;
278
340
 
@@ -365,24 +427,24 @@ function registerHandlers(
365
427
  result = await handleSearchBy(args as any, userId, authContext);
366
428
  break;
367
429
 
368
- case 'remember_create_ghost_memory':
369
- result = await handleCreateGhostMemory(args as any, userId, authContext);
430
+ case 'remember_create_internal_memory':
431
+ result = await handleCreateInternalMemory(args as any, userId, authContext);
370
432
  break;
371
433
 
372
- case 'remember_update_ghost_memory':
373
- result = await handleUpdateGhostMemory(args as any, userId, authContext);
434
+ case 'remember_update_internal_memory':
435
+ result = await handleUpdateInternalMemory(args as any, userId, authContext);
374
436
  break;
375
437
 
376
- case 'remember_search_ghost_memory':
377
- result = await handleSearchGhostMemory(args as any, userId, authContext);
438
+ case 'remember_search_internal_memory':
439
+ result = await handleSearchInternalMemory(args as any, userId, authContext);
378
440
  break;
379
441
 
380
- case 'remember_query_ghost_memory':
381
- result = await handleQueryGhostMemory(args as any, userId, authContext);
442
+ case 'remember_query_internal_memory':
443
+ result = await handleQueryInternalMemory(args as any, userId, authContext);
382
444
  break;
383
445
 
384
- case 'remember_search_ghost_memory_by':
385
- result = await handleSearchGhostMemoryBy(args as any, userId, authContext);
446
+ case 'remember_search_internal_memory_by':
447
+ result = await handleSearchInternalMemoryBy(args as any, userId, authContext);
386
448
  break;
387
449
 
388
450
  case 'remember_get_core':
@@ -0,0 +1,105 @@
1
+ /**
2
+ * remember_create_internal_memory tool
3
+ * Creates a ghost or agent memory based on the current session's InternalContext.
4
+ * Content type and tags are derived from platform HTTP headers, not tool args.
5
+ */
6
+
7
+ import { handleToolError } from '../utils/error-handler.js';
8
+ import { createDebugLogger } from '../utils/debug.js';
9
+ import type { AuthContext } from '../types/auth.js';
10
+ import { createCoreServices } from '../core-services.js';
11
+ import { buildInternalTags } from '../utils/internal-tags.js';
12
+
13
+ export const createInternalMemoryTool = {
14
+ name: 'remember_create_internal_memory',
15
+ description: `Create an internal memory (ghost observation or agent note) based on the current session context.
16
+
17
+ In ghost mode: creates a ghost memory tracking conversation observations, impressions,
18
+ and insights. Automatically tagged with ghost source isolation tags.
19
+
20
+ In agent mode: creates an agent memory for AI observations and notes.
21
+ Automatically tagged with agent tags.
22
+
23
+ Content type and tags are determined by the platform session context.
24
+ This tool errors if no internal session context is present.`,
25
+ inputSchema: {
26
+ type: 'object',
27
+ properties: {
28
+ content: { type: 'string', description: 'Memory content' },
29
+ title: { type: 'string', description: 'Optional title' },
30
+ tags: { type: 'array', items: { type: 'string' }, description: 'Additional tags (internal tags added automatically)' },
31
+ weight: { type: 'number', minimum: 0, maximum: 1, description: 'Significance (0-1)' },
32
+ trust: { type: 'number', minimum: 0, maximum: 1, description: 'Trust level (0-1)' },
33
+ feel_salience: { type: 'number', minimum: 0, maximum: 1 },
34
+ feel_social_weight: { type: 'number', minimum: 0, maximum: 1 },
35
+ feel_narrative_importance: { type: 'number', minimum: 0, maximum: 1 },
36
+ },
37
+ required: ['content'],
38
+ },
39
+ };
40
+
41
+ export interface CreateInternalMemoryArgs {
42
+ content: string;
43
+ title?: string;
44
+ tags?: string[];
45
+ weight?: number;
46
+ trust?: number;
47
+ [key: string]: any;
48
+ }
49
+
50
+ export async function handleCreateInternalMemory(
51
+ args: CreateInternalMemoryArgs,
52
+ userId: string,
53
+ authContext?: AuthContext
54
+ ): Promise<string> {
55
+ const debug = createDebugLogger({ tool: 'remember_create_internal_memory', userId, operation: 'create internal memory' });
56
+ try {
57
+ debug.info('Tool invoked');
58
+
59
+ const ctx = authContext?.internalContext;
60
+ if (!ctx) {
61
+ return JSON.stringify({ error: 'Internal context required. X-Internal-Type header must be set.' });
62
+ }
63
+
64
+ const { memory } = createCoreServices(userId);
65
+
66
+ // Build tags from internal context (ghost source isolation or agent)
67
+ const internalTags = buildInternalTags(authContext!);
68
+ const userTags = args.tags ?? [];
69
+ const mergedTags = [...new Set([...internalTags, ...userTags])];
70
+
71
+ // Extract feel_* fields
72
+ const feelFields: Record<string, number> = {};
73
+ for (const [key, value] of Object.entries(args)) {
74
+ if (key.startsWith('feel_') && typeof value === 'number') {
75
+ feelFields[key] = value;
76
+ }
77
+ }
78
+
79
+ const result = await memory.create({
80
+ content: args.content,
81
+ title: args.title,
82
+ type: ctx.type as any,
83
+ weight: args.weight,
84
+ trust: args.trust,
85
+ tags: mergedTags,
86
+ context_summary: `Internal memory created via MCP (${ctx.type})`,
87
+ ...feelFields,
88
+ } as any);
89
+
90
+ return JSON.stringify({
91
+ memory_id: result.memory_id,
92
+ created_at: result.created_at,
93
+ content_type: ctx.type,
94
+ tags: mergedTags,
95
+ message: `${ctx.type} memory created successfully with ID: ${result.memory_id}`,
96
+ }, null, 2);
97
+ } catch (error) {
98
+ debug.error('Tool failed', { error: error instanceof Error ? error.message : String(error) });
99
+ handleToolError(error, {
100
+ toolName: 'remember_create_internal_memory',
101
+ operation: 'create internal memory',
102
+ userId,
103
+ });
104
+ }
105
+ }
@@ -120,9 +120,9 @@ export async function handleFindSimilar(
120
120
  deleted_filter: args.deleted_filter,
121
121
  });
122
122
 
123
- // Post-filter ghost content (core doesn't exclude ghosts)
123
+ // Post-filter internal content types (core doesn't exclude ghost/agent)
124
124
  const filteredMemories = coreResult.similar_memories.filter(
125
- (m: any) => m.content_type !== 'ghost'
125
+ (m: any) => m.content_type !== 'ghost' && m.content_type !== 'agent'
126
126
  );
127
127
 
128
128
  const result: FindSimilarResult = {