@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,276 @@
1
+ /**
2
+ * Memory type definitions for remember-mcp
3
+ */
4
+
5
+ /**
6
+ * Content types for memories
7
+ * Based on agent/design/content-types-expansion.md
8
+ */
9
+ export type ContentType =
10
+ // Core types
11
+ | 'code'
12
+ | 'note'
13
+ | 'documentation'
14
+ | 'reference'
15
+ // Task & Planning
16
+ | 'todo'
17
+ | 'checklist'
18
+ | 'project'
19
+ | 'goal'
20
+ | 'habit'
21
+ // Communication
22
+ | 'email'
23
+ | 'conversation'
24
+ | 'meeting'
25
+ | 'person'
26
+ // Content & Media
27
+ | 'article'
28
+ | 'webpage'
29
+ | 'social'
30
+ | 'image'
31
+ | 'video'
32
+ | 'audio'
33
+ | 'transcript'
34
+ | 'presentation'
35
+ | 'spreadsheet'
36
+ | 'pdf'
37
+ // Creative
38
+ | 'screenplay'
39
+ | 'recipe'
40
+ | 'idea'
41
+ | 'quote'
42
+ // Personal
43
+ | 'journal'
44
+ | 'memory'
45
+ | 'event'
46
+ // Organizational
47
+ | 'bookmark'
48
+ | 'form'
49
+ | 'location'
50
+ // Business
51
+ | 'invoice'
52
+ | 'contract'
53
+ // System
54
+ | 'system'
55
+ | 'action'
56
+ | 'audit'
57
+ | 'history';
58
+
59
+ /**
60
+ * GPS coordinates
61
+ */
62
+ export interface GPSCoordinates {
63
+ latitude: number;
64
+ longitude: number;
65
+ accuracy?: number; // Accuracy in meters
66
+ altitude?: number;
67
+ timestamp: string; // ISO 8601 datetime
68
+ }
69
+
70
+ /**
71
+ * Address information
72
+ */
73
+ export interface Address {
74
+ formatted: string; // Full formatted address
75
+ street?: string;
76
+ city?: string;
77
+ state?: string;
78
+ country?: string;
79
+ postal_code?: string;
80
+ timezone?: string;
81
+ }
82
+
83
+ /**
84
+ * Location information (from platform cookies)
85
+ */
86
+ export interface Location {
87
+ gps: GPSCoordinates | null;
88
+ address: Address | null;
89
+ source: 'gps' | 'ip' | 'manual' | 'cached' | 'unavailable';
90
+ confidence: number; // 0-1
91
+ is_approximate: boolean;
92
+ }
93
+
94
+ /**
95
+ * Conversation participant
96
+ */
97
+ export interface Participant {
98
+ user_id: string;
99
+ role: 'user' | 'assistant' | 'system';
100
+ name?: string;
101
+ }
102
+
103
+ /**
104
+ * Source information
105
+ */
106
+ export interface Source {
107
+ type: 'conversation' | 'import' | 'inference' | 'manual' | 'api';
108
+ platform?: string; // web, mobile, api
109
+ client?: string;
110
+ version?: string;
111
+ }
112
+
113
+ /**
114
+ * Environment information
115
+ */
116
+ export interface Environment {
117
+ location?: Location;
118
+ device?: string;
119
+ user_agent?: string;
120
+ }
121
+
122
+ /**
123
+ * Context information about how/when memory was created
124
+ */
125
+ export interface MemoryContext {
126
+ conversation_id?: string;
127
+ conversation_title?: string;
128
+ turn_number?: number;
129
+ summary?: string; // Brief summary for quick retrieval
130
+ participants?: Participant[];
131
+ timestamp: string; // ISO 8601 datetime
132
+ timezone?: string;
133
+ source: Source;
134
+ environment?: Environment;
135
+ tags?: string[];
136
+ notes?: string;
137
+ }
138
+
139
+ /**
140
+ * Core Memory interface
141
+ * Based on agent/design/requirements-enhancements.md
142
+ */
143
+ export interface Memory {
144
+ // Core Identity
145
+ id: string; // UUID from Weaviate
146
+ user_id: string;
147
+ doc_type: 'memory'; // Discriminator for unified collection
148
+
149
+ // Content
150
+ content: string; // Main memory content (vectorized)
151
+ title?: string;
152
+ summary?: string;
153
+ type: ContentType;
154
+
155
+ // Significance & Trust
156
+ weight: number; // 0-1, significance/priority
157
+ trust: number; // 0-1, access control level
158
+ confidence?: number; // 0-1, system confidence in accuracy
159
+
160
+ // Location (from platform)
161
+ location: Location;
162
+
163
+ // Context
164
+ context: MemoryContext;
165
+
166
+ // Relationships
167
+ relationships: string[]; // IDs of relationship documents
168
+
169
+ // Access Tracking (for weight calculation)
170
+ access_count: number;
171
+ last_accessed_at?: string; // ISO 8601 datetime
172
+ access_frequency?: number; // Accesses per day
173
+
174
+ // Metadata
175
+ created_at: string; // ISO 8601 datetime
176
+ updated_at: string; // ISO 8601 datetime
177
+ version: number;
178
+
179
+ // Organization
180
+ tags: string[];
181
+ category?: string;
182
+ references?: string[]; // Source URLs
183
+
184
+ // Template Integration (optional)
185
+ template_id?: string;
186
+ template_version?: string;
187
+ structured_content?: Record<string, any>;
188
+
189
+ // Computed Weight (for search ranking)
190
+ base_weight: number; // User-specified
191
+ computed_weight?: number; // Calculated with access multipliers
192
+ }
193
+
194
+ /**
195
+ * Relationship interface
196
+ * Stored in same collection as memories with doc_type: "relationship"
197
+ */
198
+ export interface Relationship {
199
+ // Core Identity
200
+ id: string;
201
+ user_id: string;
202
+ doc_type: 'relationship'; // Discriminator
203
+
204
+ // Connection
205
+ memory_ids: string[]; // 2...N memory IDs
206
+ relationship_type: string; // Free-form: "causes", "contradicts", "inspired_by", etc.
207
+
208
+ // Observation
209
+ observation: string; // Description of the connection (vectorized)
210
+ strength: number; // 0-1
211
+ confidence: number; // 0-1
212
+
213
+ // Context
214
+ context: MemoryContext;
215
+
216
+ // Metadata
217
+ created_at: string;
218
+ updated_at: string;
219
+ version: number;
220
+ tags: string[];
221
+ }
222
+
223
+ /**
224
+ * Union type for documents in Memory collection
225
+ */
226
+ export type MemoryDocument = Memory | Relationship;
227
+
228
+ /**
229
+ * Partial memory for updates
230
+ */
231
+ export type MemoryUpdate = Partial<Omit<Memory, 'id' | 'user_id' | 'doc_type' | 'created_at' | 'version'>>;
232
+
233
+ /**
234
+ * Partial relationship for updates
235
+ */
236
+ export type RelationshipUpdate = Partial<Omit<Relationship, 'id' | 'user_id' | 'doc_type' | 'created_at' | 'version'>>;
237
+
238
+ /**
239
+ * Search filters
240
+ */
241
+ export interface SearchFilters {
242
+ types?: ContentType[];
243
+ tags?: string[];
244
+ weight_min?: number;
245
+ weight_max?: number;
246
+ trust_min?: number;
247
+ trust_max?: number;
248
+ date_from?: string;
249
+ date_to?: string;
250
+ location_near?: GPSCoordinates;
251
+ location_radius_meters?: number;
252
+ has_relationships?: boolean;
253
+ }
254
+
255
+ /**
256
+ * Search options
257
+ */
258
+ export interface SearchOptions {
259
+ query: string;
260
+ alpha?: number; // 0-1, balance between semantic (1.0) and keyword (0.0)
261
+ filters?: SearchFilters;
262
+ include_relationships?: boolean;
263
+ limit?: number;
264
+ offset?: number;
265
+ }
266
+
267
+ /**
268
+ * Search result
269
+ */
270
+ export interface SearchResult {
271
+ memories: Memory[];
272
+ relationships?: Relationship[];
273
+ total: number;
274
+ offset: number;
275
+ limit: number;
276
+ }
@@ -0,0 +1,42 @@
1
+ import { config } from '../config.js';
2
+
3
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
4
+
5
+ const LOG_LEVELS: Record<LogLevel, number> = {
6
+ debug: 0,
7
+ info: 1,
8
+ warn: 2,
9
+ error: 3,
10
+ };
11
+
12
+ const currentLevel = LOG_LEVELS[config.server.logLevel as LogLevel] ?? LOG_LEVELS.info;
13
+
14
+ function shouldLog(level: LogLevel): boolean {
15
+ return LOG_LEVELS[level] >= currentLevel;
16
+ }
17
+
18
+ export const logger = {
19
+ debug: (message: string, ...args: any[]) => {
20
+ if (shouldLog('debug')) {
21
+ console.debug(`[DEBUG] ${message}`, ...args);
22
+ }
23
+ },
24
+
25
+ info: (message: string, ...args: any[]) => {
26
+ if (shouldLog('info')) {
27
+ console.info(`[INFO] ${message}`, ...args);
28
+ }
29
+ },
30
+
31
+ warn: (message: string, ...args: any[]) => {
32
+ if (shouldLog('warn')) {
33
+ console.warn(`[WARN] ${message}`, ...args);
34
+ }
35
+ },
36
+
37
+ error: (message: string, ...args: any[]) => {
38
+ if (shouldLog('error')) {
39
+ console.error(`[ERROR] ${message}`, ...args);
40
+ }
41
+ },
42
+ };
@@ -0,0 +1,58 @@
1
+ import { describe, it, expect, beforeAll } from '@jest/globals';
2
+ import {
3
+ initWeaviateClient,
4
+ testWeaviateConnection,
5
+ sanitizeUserId,
6
+ getMemoryCollectionName,
7
+ getTemplateCollectionName,
8
+ getAuditCollectionName,
9
+ } from '../../src/weaviate/client.js';
10
+
11
+ describe('Weaviate Client', () => {
12
+ describe('User ID Sanitization', () => {
13
+ it('should sanitize email addresses', () => {
14
+ expect(sanitizeUserId('user@example.com')).toBe('User_example_com');
15
+ });
16
+
17
+ it('should sanitize user IDs with hyphens', () => {
18
+ expect(sanitizeUserId('user-123')).toBe('User_123');
19
+ });
20
+
21
+ it('should handle IDs starting with numbers', () => {
22
+ expect(sanitizeUserId('123user')).toBe('_123user');
23
+ });
24
+
25
+ it('should handle special characters', () => {
26
+ expect(sanitizeUserId('user!@#$%123')).toBe('User_____123');
27
+ });
28
+ });
29
+
30
+ describe('Collection Name Generation', () => {
31
+ it('should generate memory collection names', () => {
32
+ expect(getMemoryCollectionName('user123')).toBe('Memory_User123');
33
+ expect(getMemoryCollectionName('user@test.com')).toBe('Memory_User_test_com');
34
+ });
35
+
36
+ it('should generate template collection names', () => {
37
+ expect(getTemplateCollectionName('user123')).toBe('Template_User123');
38
+ expect(getTemplateCollectionName('user@test.com')).toBe('Template_User_test_com');
39
+ });
40
+
41
+ it('should generate audit collection names', () => {
42
+ expect(getAuditCollectionName('user123')).toBe('Audit_User123');
43
+ expect(getAuditCollectionName('user@test.com')).toBe('Audit_User_test_com');
44
+ });
45
+ });
46
+
47
+ // Integration tests (require Weaviate instance)
48
+ describe.skip('Weaviate Connection', () => {
49
+ beforeAll(async () => {
50
+ await initWeaviateClient();
51
+ });
52
+
53
+ it('should initialize client', async () => {
54
+ const result = await testWeaviateConnection();
55
+ expect(result).toBe(true);
56
+ });
57
+ });
58
+ });
@@ -0,0 +1,114 @@
1
+ import weaviate, { WeaviateClient } from 'weaviate-client';
2
+ import { config } from '../config.js';
3
+
4
+ let client: WeaviateClient | null = null;
5
+
6
+ /**
7
+ * Initialize Weaviate client
8
+ */
9
+ export async function initWeaviateClient(): Promise<WeaviateClient> {
10
+ if (client) {
11
+ return client;
12
+ }
13
+
14
+ // Weaviate v3 client initialization
15
+ client = await weaviate.connectToWeaviateCloud(config.weaviate.url, {
16
+ authCredentials: config.weaviate.apiKey
17
+ ? new weaviate.ApiKey(config.weaviate.apiKey)
18
+ : undefined,
19
+ headers: config.openai.apiKey
20
+ ? { 'X-OpenAI-Api-Key': config.openai.apiKey }
21
+ : undefined,
22
+ });
23
+
24
+ console.log('[Weaviate] Client initialized');
25
+ return client;
26
+ }
27
+
28
+ /**
29
+ * Get Weaviate client instance
30
+ */
31
+ export function getWeaviateClient(): WeaviateClient {
32
+ if (!client) {
33
+ throw new Error('Weaviate client not initialized. Call initWeaviateClient() first.');
34
+ }
35
+ return client;
36
+ }
37
+
38
+ /**
39
+ * Test Weaviate connection
40
+ */
41
+ export async function testWeaviateConnection(): Promise<boolean> {
42
+ try {
43
+ const weaviateClient = getWeaviateClient();
44
+ const isReady = await weaviateClient.isReady();
45
+ console.log('[Weaviate] Connection successful, ready:', isReady);
46
+ return isReady;
47
+ } catch (error) {
48
+ console.error('[Weaviate] Connection failed:', error);
49
+ return false;
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Sanitize user_id for collection name
55
+ * Weaviate collection names must start with uppercase letter and contain only alphanumeric
56
+ */
57
+ export function sanitizeUserId(userId: string): string {
58
+ // Remove special characters, keep alphanumeric
59
+ let sanitized = userId.replace(/[^a-zA-Z0-9]/g, '_');
60
+
61
+ // If starts with number, prepend underscore
62
+ if (/^[0-9]/.test(sanitized)) {
63
+ sanitized = '_' + sanitized;
64
+ }
65
+
66
+ // Ensure starts with uppercase letter
67
+ return sanitized.charAt(0).toUpperCase() + sanitized.slice(1);
68
+ }
69
+
70
+ /**
71
+ * Get collection name for user's memories
72
+ */
73
+ export function getMemoryCollectionName(userId: string): string {
74
+ return `Memory_${sanitizeUserId(userId)}`;
75
+ }
76
+
77
+ /**
78
+ * Get collection name for user's templates
79
+ */
80
+ export function getTemplateCollectionName(userId: string): string {
81
+ return `Template_${sanitizeUserId(userId)}`;
82
+ }
83
+
84
+ /**
85
+ * Get collection name for user's audit logs
86
+ */
87
+ export function getAuditCollectionName(userId: string): string {
88
+ return `Audit_${sanitizeUserId(userId)}`;
89
+ }
90
+
91
+ /**
92
+ * Check if collection exists
93
+ */
94
+ export async function collectionExists(collectionName: string): Promise<boolean> {
95
+ try {
96
+ const weaviateClient = getWeaviateClient();
97
+ const exists = await weaviateClient.collections.exists(collectionName);
98
+ return exists;
99
+ } catch (error) {
100
+ console.error(`[Weaviate] Error checking collection ${collectionName}:`, error);
101
+ return false;
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Close Weaviate client connection
107
+ */
108
+ export async function closeWeaviateClient(): Promise<void> {
109
+ if (client) {
110
+ // Weaviate client doesn't have explicit close method
111
+ client = null;
112
+ console.log('[Weaviate] Client closed');
113
+ }
114
+ }