@prmichaelsen/remember-mcp 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.
Files changed (95) hide show
  1. package/.env.example +65 -0
  2. package/AGENT.md +840 -0
  3. package/README.md +72 -0
  4. package/agent/design/.gitkeep +0 -0
  5. package/agent/design/access-control-result-pattern.md +458 -0
  6. package/agent/design/action-audit-memory-types.md +637 -0
  7. package/agent/design/common-template-fields.md +282 -0
  8. package/agent/design/complete-tool-set.md +407 -0
  9. package/agent/design/content-types-expansion.md +521 -0
  10. package/agent/design/cross-database-id-strategy.md +358 -0
  11. package/agent/design/default-template-library.md +423 -0
  12. package/agent/design/firestore-wrapper-analysis.md +606 -0
  13. package/agent/design/llm-provider-abstraction.md +691 -0
  14. package/agent/design/location-handling-architecture.md +523 -0
  15. package/agent/design/memory-templates-design.md +364 -0
  16. package/agent/design/permissions-storage-architecture.md +680 -0
  17. package/agent/design/relationship-storage-strategy.md +361 -0
  18. package/agent/design/remember-mcp-implementation-tasks.md +417 -0
  19. package/agent/design/remember-mcp-progress.yaml +141 -0
  20. package/agent/design/requirements-enhancements.md +468 -0
  21. package/agent/design/requirements.md +56 -0
  22. package/agent/design/template-storage-strategy.md +412 -0
  23. package/agent/design/template-suggestion-system.md +853 -0
  24. package/agent/design/trust-escalation-prevention.md +343 -0
  25. package/agent/design/trust-system-implementation.md +592 -0
  26. package/agent/design/user-preferences.md +683 -0
  27. package/agent/design/weaviate-collection-strategy.md +461 -0
  28. package/agent/milestones/.gitkeep +0 -0
  29. package/agent/milestones/milestone-1-project-foundation.md +121 -0
  30. package/agent/milestones/milestone-2-core-memory-system.md +150 -0
  31. package/agent/milestones/milestone-3-relationships-graph.md +116 -0
  32. package/agent/milestones/milestone-4-user-preferences.md +103 -0
  33. package/agent/milestones/milestone-5-template-system.md +126 -0
  34. package/agent/milestones/milestone-6-auth-multi-tenancy.md +124 -0
  35. package/agent/milestones/milestone-7-trust-permissions.md +133 -0
  36. package/agent/milestones/milestone-8-testing-quality.md +137 -0
  37. package/agent/milestones/milestone-9-deployment-documentation.md +147 -0
  38. package/agent/patterns/.gitkeep +0 -0
  39. package/agent/patterns/bootstrap.md +1271 -0
  40. package/agent/patterns/firebase-admin-sdk-v8-usage.md +950 -0
  41. package/agent/patterns/firestore-users-pattern-best-practices.md +347 -0
  42. package/agent/patterns/library-services.md +454 -0
  43. package/agent/patterns/testing-colocated.md +316 -0
  44. package/agent/progress.yaml +395 -0
  45. package/agent/tasks/.gitkeep +0 -0
  46. package/agent/tasks/task-1-initialize-project-structure.md +266 -0
  47. package/agent/tasks/task-2-install-dependencies.md +199 -0
  48. package/agent/tasks/task-3-setup-weaviate-client.md +330 -0
  49. package/agent/tasks/task-4-setup-firestore-client.md +362 -0
  50. package/agent/tasks/task-5-create-basic-mcp-server.md +114 -0
  51. package/agent/tasks/task-6-create-integration-tests.md +195 -0
  52. package/agent/tasks/task-7-finalize-milestone-1.md +363 -0
  53. package/agent/tasks/task-8-setup-utility-scripts.md +382 -0
  54. package/agent/tasks/task-9-create-server-factory.md +404 -0
  55. package/dist/config.d.ts +26 -0
  56. package/dist/constants/content-types.d.ts +60 -0
  57. package/dist/firestore/init.d.ts +14 -0
  58. package/dist/firestore/paths.d.ts +53 -0
  59. package/dist/firestore/paths.spec.d.ts +2 -0
  60. package/dist/server-factory.d.ts +40 -0
  61. package/dist/server-factory.js +1741 -0
  62. package/dist/server-factory.spec.d.ts +2 -0
  63. package/dist/server.d.ts +3 -0
  64. package/dist/server.js +1690 -0
  65. package/dist/tools/create-memory.d.ts +94 -0
  66. package/dist/tools/delete-memory.d.ts +47 -0
  67. package/dist/tools/search-memory.d.ts +88 -0
  68. package/dist/types/memory.d.ts +183 -0
  69. package/dist/utils/logger.d.ts +7 -0
  70. package/dist/weaviate/client.d.ts +39 -0
  71. package/dist/weaviate/client.spec.d.ts +2 -0
  72. package/dist/weaviate/schema.d.ts +29 -0
  73. package/esbuild.build.js +60 -0
  74. package/esbuild.watch.js +25 -0
  75. package/jest.config.js +31 -0
  76. package/jest.e2e.config.js +17 -0
  77. package/package.json +68 -0
  78. package/src/.gitkeep +0 -0
  79. package/src/config.ts +56 -0
  80. package/src/constants/content-types.ts +454 -0
  81. package/src/firestore/init.ts +68 -0
  82. package/src/firestore/paths.spec.ts +75 -0
  83. package/src/firestore/paths.ts +124 -0
  84. package/src/server-factory.spec.ts +60 -0
  85. package/src/server-factory.ts +215 -0
  86. package/src/server.ts +243 -0
  87. package/src/tools/create-memory.ts +198 -0
  88. package/src/tools/delete-memory.ts +126 -0
  89. package/src/tools/search-memory.ts +216 -0
  90. package/src/types/memory.ts +276 -0
  91. package/src/utils/logger.ts +42 -0
  92. package/src/weaviate/client.spec.ts +58 -0
  93. package/src/weaviate/client.ts +114 -0
  94. package/src/weaviate/schema.ts +288 -0
  95. package/tsconfig.json +26 -0
@@ -0,0 +1,198 @@
1
+ /**
2
+ * remember_create_memory tool
3
+ * Creates a new memory in the user's collection
4
+ */
5
+
6
+ import type { Memory, ContentType, Location, MemoryContext } from '../types/memory.js';
7
+ import { ensureMemoryCollection, getMemoryCollection } from '../weaviate/schema.js';
8
+ import { logger } from '../utils/logger.js';
9
+ import { DEFAULT_CONTENT_TYPE, getContentTypeDescription, isValidContentType } from '../constants/content-types.js';
10
+
11
+ /**
12
+ * Tool definition for remember_create_memory
13
+ */
14
+ export const createMemoryTool = {
15
+ name: 'remember_create_memory',
16
+ description: `Create a new memory with optional template.
17
+
18
+ Memories can store any type of information: notes, events, people, recipes, etc.
19
+ Each memory has a weight (significance 0-1) and trust level (access control 0-1).
20
+ Location and context are automatically captured from the request.
21
+
22
+ Examples:
23
+ - "Remember that I met Sarah at the conference"
24
+ - "Save this recipe for chocolate chip cookies"
25
+ - "Note that my tent is stored in garage bin A4"
26
+ `,
27
+ inputSchema: {
28
+ type: 'object',
29
+ properties: {
30
+ content: {
31
+ type: 'string',
32
+ description: 'Memory content (main text)',
33
+ },
34
+ title: {
35
+ type: 'string',
36
+ description: 'Optional short title',
37
+ },
38
+ type: {
39
+ type: 'string',
40
+ description: getContentTypeDescription(),
41
+ default: DEFAULT_CONTENT_TYPE,
42
+ },
43
+ weight: {
44
+ type: 'number',
45
+ description: 'Significance/priority (0-1, default: 0.5)',
46
+ minimum: 0,
47
+ maximum: 1,
48
+ },
49
+ trust: {
50
+ type: 'number',
51
+ description: 'Access control level (0-1, default: 0.5)',
52
+ minimum: 0,
53
+ maximum: 1,
54
+ },
55
+ tags: {
56
+ type: 'array',
57
+ items: { type: 'string' },
58
+ description: 'Tags for organization',
59
+ },
60
+ references: {
61
+ type: 'array',
62
+ items: { type: 'string' },
63
+ description: 'Source URLs',
64
+ },
65
+ template_id: {
66
+ type: 'string',
67
+ description: 'Template ID to use (optional)',
68
+ },
69
+ skip_template_suggestion: {
70
+ type: 'boolean',
71
+ description: 'Skip automatic template suggestion',
72
+ default: false,
73
+ },
74
+ },
75
+ required: ['content'],
76
+ },
77
+ };
78
+
79
+ /**
80
+ * Create memory arguments
81
+ */
82
+ export interface CreateMemoryArgs {
83
+ content: string;
84
+ title?: string;
85
+ type?: ContentType;
86
+ weight?: number;
87
+ trust?: number;
88
+ tags?: string[];
89
+ references?: string[];
90
+ template_id?: string;
91
+ skip_template_suggestion?: boolean;
92
+ structured_content?: Record<string, any>;
93
+ }
94
+
95
+ /**
96
+ * Create memory result
97
+ */
98
+ export interface CreateMemoryResult {
99
+ memory_id: string;
100
+ created_at: string;
101
+ message: string;
102
+ }
103
+
104
+ /**
105
+ * Handle remember_create_memory tool
106
+ */
107
+ export async function handleCreateMemory(
108
+ args: CreateMemoryArgs,
109
+ userId: string,
110
+ context?: Partial<MemoryContext>
111
+ ): Promise<string> {
112
+ try {
113
+ logger.info('Creating memory', { userId, type: args.type });
114
+
115
+ // Ensure collection exists
116
+ await ensureMemoryCollection(userId);
117
+ const collection = getMemoryCollection(userId);
118
+
119
+ // Build memory object
120
+ const now = new Date().toISOString();
121
+ const memory: Omit<Memory, 'id'> = {
122
+ // Core identity
123
+ user_id: userId,
124
+ doc_type: 'memory',
125
+
126
+ // Content
127
+ content: args.content,
128
+ title: args.title,
129
+ summary: args.title, // Use title as summary for now
130
+ type: (args.type && isValidContentType(args.type) ? args.type : DEFAULT_CONTENT_TYPE) as ContentType,
131
+
132
+ // Scoring
133
+ weight: args.weight ?? 0.5,
134
+ trust: args.trust ?? 0.5,
135
+ confidence: 1.0,
136
+
137
+ // Location (from context or default)
138
+ location: {
139
+ gps: null,
140
+ address: null,
141
+ source: 'unavailable',
142
+ confidence: 0,
143
+ is_approximate: true,
144
+ },
145
+
146
+ // Context
147
+ context: {
148
+ timestamp: now,
149
+ source: {
150
+ type: 'api',
151
+ platform: 'mcp',
152
+ },
153
+ summary: context?.summary || 'Memory created via MCP',
154
+ conversation_id: context?.conversation_id,
155
+ ...context,
156
+ },
157
+
158
+ // Relationships
159
+ relationships: [],
160
+
161
+ // Access tracking
162
+ access_count: 0,
163
+ last_accessed_at: now,
164
+ access_frequency: 0,
165
+
166
+ // Metadata
167
+ created_at: now,
168
+ updated_at: now,
169
+ version: 1,
170
+ tags: args.tags || [],
171
+ references: args.references || [],
172
+
173
+ // Template
174
+ template_id: args.template_id,
175
+ structured_content: args.structured_content,
176
+
177
+ // Computed weight
178
+ base_weight: args.weight ?? 0.5,
179
+ computed_weight: args.weight ?? 0.5,
180
+ };
181
+
182
+ // Insert into Weaviate
183
+ const result = await collection.data.insert(memory as any);
184
+
185
+ logger.info('Memory created successfully', { memoryId: result, userId });
186
+
187
+ const response: CreateMemoryResult = {
188
+ memory_id: result,
189
+ created_at: now,
190
+ message: `Memory created successfully with ID: ${result}`,
191
+ };
192
+
193
+ return JSON.stringify(response, null, 2);
194
+ } catch (error) {
195
+ logger.error('Failed to create memory:', error);
196
+ throw new Error(`Failed to create memory: ${error instanceof Error ? error.message : String(error)}`);
197
+ }
198
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * remember_delete_memory tool
3
+ * Delete a memory from the user's collection
4
+ */
5
+
6
+ import { getMemoryCollection } from '../weaviate/schema.js';
7
+ import { logger } from '../utils/logger.js';
8
+
9
+ /**
10
+ * Tool definition for remember_delete_memory
11
+ */
12
+ export const deleteMemoryTool = {
13
+ name: 'remember_delete_memory',
14
+ description: `Delete a memory from your collection.
15
+
16
+ Optionally delete connected relationships as well.
17
+ This action cannot be undone.
18
+
19
+ Examples:
20
+ - "Delete that old camping note"
21
+ - "Remove the recipe I saved yesterday"
22
+ `,
23
+ inputSchema: {
24
+ type: 'object',
25
+ properties: {
26
+ memory_id: {
27
+ type: 'string',
28
+ description: 'ID of the memory to delete',
29
+ },
30
+ delete_relationships: {
31
+ type: 'boolean',
32
+ description: 'Also delete connected relationships. Default: false',
33
+ default: false,
34
+ },
35
+ },
36
+ required: ['memory_id'],
37
+ },
38
+ };
39
+
40
+ /**
41
+ * Delete memory arguments
42
+ */
43
+ export interface DeleteMemoryArgs {
44
+ memory_id: string;
45
+ delete_relationships?: boolean;
46
+ }
47
+
48
+ /**
49
+ * Delete memory result
50
+ */
51
+ export interface DeleteMemoryResult {
52
+ memory_id: string;
53
+ deleted: boolean;
54
+ relationships_deleted?: number;
55
+ message: string;
56
+ }
57
+
58
+ /**
59
+ * Handle remember_delete_memory tool
60
+ */
61
+ export async function handleDeleteMemory(
62
+ args: DeleteMemoryArgs,
63
+ userId: string
64
+ ): Promise<string> {
65
+ try {
66
+ logger.info('Deleting memory', { userId, memoryId: args.memory_id });
67
+
68
+ const collection = getMemoryCollection(userId);
69
+
70
+ // Get memory to verify ownership and get relationships
71
+ const memory = await collection.query.fetchObjectById(args.memory_id, {
72
+ returnProperties: ['user_id', 'doc_type', 'relationships'],
73
+ });
74
+
75
+ if (!memory) {
76
+ throw new Error(`Memory not found: ${args.memory_id}`);
77
+ }
78
+
79
+ // Verify ownership
80
+ if (memory.properties.user_id !== userId) {
81
+ throw new Error('Unauthorized: Cannot delete another user\'s memory');
82
+ }
83
+
84
+ // Verify it's a memory (not a relationship)
85
+ if (memory.properties.doc_type !== 'memory') {
86
+ throw new Error('Cannot delete relationships using this tool. Use remember_delete_relationship instead.');
87
+ }
88
+
89
+ let relationshipsDeleted = 0;
90
+
91
+ // Delete connected relationships if requested
92
+ if (args.delete_relationships && memory.properties.relationships) {
93
+ const relationshipIds = memory.properties.relationships as string[];
94
+
95
+ for (const relId of relationshipIds) {
96
+ try {
97
+ await collection.data.deleteById(relId);
98
+ relationshipsDeleted++;
99
+ } catch (error) {
100
+ logger.warn(`Failed to delete relationship ${relId}:`, error);
101
+ }
102
+ }
103
+ }
104
+
105
+ // Delete the memory
106
+ await collection.data.deleteById(args.memory_id);
107
+
108
+ logger.info('Memory deleted successfully', {
109
+ userId,
110
+ memoryId: args.memory_id,
111
+ relationshipsDeleted
112
+ });
113
+
114
+ const result: DeleteMemoryResult = {
115
+ memory_id: args.memory_id,
116
+ deleted: true,
117
+ relationships_deleted: relationshipsDeleted,
118
+ message: `Memory deleted successfully${relationshipsDeleted > 0 ? ` (${relationshipsDeleted} relationships also deleted)` : ''}`,
119
+ };
120
+
121
+ return JSON.stringify(result, null, 2);
122
+ } catch (error) {
123
+ logger.error('Failed to delete memory:', error);
124
+ throw new Error(`Failed to delete memory: ${error instanceof Error ? error.message : String(error)}`);
125
+ }
126
+ }
@@ -0,0 +1,216 @@
1
+ /**
2
+ * remember_search_memory tool
3
+ * Search memories using hybrid semantic + keyword search
4
+ */
5
+
6
+ import type { Memory, SearchOptions, SearchResult, SearchFilters } from '../types/memory.js';
7
+ import { getMemoryCollection } from '../weaviate/schema.js';
8
+ import { logger } from '../utils/logger.js';
9
+
10
+ /**
11
+ * Tool definition for remember_search_memory
12
+ */
13
+ export const searchMemoryTool = {
14
+ name: 'remember_search_memory',
15
+ description: `Search memories using hybrid semantic and keyword search.
16
+
17
+ Supports:
18
+ - Semantic search (meaning-based)
19
+ - Keyword search (exact matches)
20
+ - Hybrid search (balanced with alpha parameter)
21
+ - Filtering by type, tags, weight, trust, date range
22
+ - Location-based search
23
+
24
+ Examples:
25
+ - "Find memories about camping trips"
26
+ - "Search for recipes I saved"
27
+ - "Show me notes from last week"
28
+ `,
29
+ inputSchema: {
30
+ type: 'object',
31
+ properties: {
32
+ query: {
33
+ type: 'string',
34
+ description: 'Search query',
35
+ },
36
+ alpha: {
37
+ type: 'number',
38
+ description: 'Balance between semantic (1.0) and keyword (0.0) search. Default: 0.7',
39
+ minimum: 0,
40
+ maximum: 1,
41
+ default: 0.7,
42
+ },
43
+ limit: {
44
+ type: 'number',
45
+ description: 'Maximum number of results. Default: 10',
46
+ minimum: 1,
47
+ maximum: 100,
48
+ default: 10,
49
+ },
50
+ offset: {
51
+ type: 'number',
52
+ description: 'Pagination offset. Default: 0',
53
+ minimum: 0,
54
+ default: 0,
55
+ },
56
+ filters: {
57
+ type: 'object',
58
+ description: 'Optional filters',
59
+ properties: {
60
+ types: {
61
+ type: 'array',
62
+ items: { type: 'string' },
63
+ description: 'Filter by content types',
64
+ },
65
+ tags: {
66
+ type: 'array',
67
+ items: { type: 'string' },
68
+ description: 'Filter by tags',
69
+ },
70
+ weight_min: {
71
+ type: 'number',
72
+ description: 'Minimum weight (0-1)',
73
+ },
74
+ trust_min: {
75
+ type: 'number',
76
+ description: 'Minimum trust level (0-1)',
77
+ },
78
+ date_from: {
79
+ type: 'string',
80
+ description: 'Start date (ISO 8601)',
81
+ },
82
+ date_to: {
83
+ type: 'string',
84
+ description: 'End date (ISO 8601)',
85
+ },
86
+ },
87
+ },
88
+ include_relationships: {
89
+ type: 'boolean',
90
+ description: 'Include relationships in results. Default: false',
91
+ default: false,
92
+ },
93
+ },
94
+ required: ['query'],
95
+ },
96
+ };
97
+
98
+ /**
99
+ * Handle remember_search_memory tool
100
+ */
101
+ export async function handleSearchMemory(
102
+ args: SearchOptions,
103
+ userId: string
104
+ ): Promise<string> {
105
+ try {
106
+ logger.info('Searching memories', { userId, query: args.query });
107
+
108
+ const collection = getMemoryCollection(userId);
109
+ const alpha = args.alpha ?? 0.7;
110
+ const limit = args.limit ?? 10;
111
+ const offset = args.offset ?? 0;
112
+
113
+ // Build where filter
114
+ const whereFilters: any[] = [
115
+ {
116
+ path: 'doc_type',
117
+ operator: 'Equal',
118
+ valueText: 'memory',
119
+ },
120
+ ];
121
+
122
+ // Add type filter
123
+ if (args.filters?.types && args.filters.types.length > 0) {
124
+ whereFilters.push({
125
+ path: 'type',
126
+ operator: 'ContainsAny',
127
+ valueTextArray: args.filters.types,
128
+ });
129
+ }
130
+
131
+ // Add weight filter
132
+ if (args.filters?.weight_min !== undefined) {
133
+ whereFilters.push({
134
+ path: 'weight',
135
+ operator: 'GreaterThanEqual',
136
+ valueNumber: args.filters.weight_min,
137
+ });
138
+ }
139
+
140
+ // Add trust filter
141
+ if (args.filters?.trust_min !== undefined) {
142
+ whereFilters.push({
143
+ path: 'trust',
144
+ operator: 'GreaterThanEqual',
145
+ valueNumber: args.filters.trust_min,
146
+ });
147
+ }
148
+
149
+ // Add date range filters
150
+ if (args.filters?.date_from) {
151
+ whereFilters.push({
152
+ path: 'created_at',
153
+ operator: 'GreaterThanEqual',
154
+ valueDate: new Date(args.filters.date_from),
155
+ });
156
+ }
157
+
158
+ if (args.filters?.date_to) {
159
+ whereFilters.push({
160
+ path: 'created_at',
161
+ operator: 'LessThanEqual',
162
+ valueDate: new Date(args.filters.date_to),
163
+ });
164
+ }
165
+
166
+ // Build search options
167
+ const searchOptions: any = {
168
+ alpha: alpha,
169
+ limit: limit + offset, // Get extra for offset
170
+ };
171
+
172
+ // Add filters if present
173
+ if (whereFilters.length > 0) {
174
+ searchOptions.filters = whereFilters.length > 1 ? {
175
+ operator: 'And' as const,
176
+ operands: whereFilters,
177
+ } : whereFilters[0];
178
+ }
179
+
180
+ // Perform hybrid search with Weaviate v3 API
181
+ const results = await collection.query.hybrid(args.query, searchOptions);
182
+
183
+ // Apply offset
184
+ const paginatedResults = results.objects.slice(offset);
185
+
186
+ // Format memories
187
+ const memories: Partial<Memory>[] = paginatedResults.map((obj: any) => ({
188
+ id: obj.uuid,
189
+ ...obj.properties,
190
+ }));
191
+
192
+ // Build result
193
+ const searchResult: SearchResult = {
194
+ memories: memories as Memory[],
195
+ total: memories.length,
196
+ offset: offset,
197
+ limit: limit,
198
+ };
199
+
200
+ // TODO: Include relationships if requested
201
+ if (args.include_relationships) {
202
+ searchResult.relationships = [];
203
+ }
204
+
205
+ logger.info('Search completed', {
206
+ userId,
207
+ query: args.query,
208
+ results: memories.length
209
+ });
210
+
211
+ return JSON.stringify(searchResult, null, 2);
212
+ } catch (error) {
213
+ logger.error('Failed to search memories:', error);
214
+ throw new Error(`Failed to search memories: ${error instanceof Error ? error.message : String(error)}`);
215
+ }
216
+ }