memorandum-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 (52) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +237 -0
  3. package/README.ru.md +237 -0
  4. package/dist/config.d.ts +36 -0
  5. package/dist/config.js +63 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/document-store.d.ts +145 -0
  8. package/dist/document-store.js +682 -0
  9. package/dist/document-store.js.map +1 -0
  10. package/dist/document-tools.d.ts +10 -0
  11. package/dist/document-tools.js +101 -0
  12. package/dist/document-tools.js.map +1 -0
  13. package/dist/document-types.d.ts +147 -0
  14. package/dist/document-types.js +125 -0
  15. package/dist/document-types.js.map +1 -0
  16. package/dist/embedder.d.ts +55 -0
  17. package/dist/embedder.js +152 -0
  18. package/dist/embedder.js.map +1 -0
  19. package/dist/embedding-queue.d.ts +66 -0
  20. package/dist/embedding-queue.js +152 -0
  21. package/dist/embedding-queue.js.map +1 -0
  22. package/dist/errors.d.ts +26 -0
  23. package/dist/errors.js +46 -0
  24. package/dist/errors.js.map +1 -0
  25. package/dist/index.d.ts +9 -0
  26. package/dist/index.js +147 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/logger.d.ts +12 -0
  29. package/dist/logger.js +22 -0
  30. package/dist/logger.js.map +1 -0
  31. package/dist/semantic-index.d.ts +126 -0
  32. package/dist/semantic-index.js +427 -0
  33. package/dist/semantic-index.js.map +1 -0
  34. package/dist/semantic-tools.d.ts +10 -0
  35. package/dist/semantic-tools.js +80 -0
  36. package/dist/semantic-tools.js.map +1 -0
  37. package/dist/semantic-types.d.ts +161 -0
  38. package/dist/semantic-types.js +101 -0
  39. package/dist/semantic-types.js.map +1 -0
  40. package/dist/store.d.ts +130 -0
  41. package/dist/store.js +389 -0
  42. package/dist/store.js.map +1 -0
  43. package/dist/tools.d.ts +15 -0
  44. package/dist/tools.js +104 -0
  45. package/dist/tools.js.map +1 -0
  46. package/dist/types.d.ts +97 -0
  47. package/dist/types.js +88 -0
  48. package/dist/types.js.map +1 -0
  49. package/dist/vector-store.d.ts +85 -0
  50. package/dist/vector-store.js +241 -0
  51. package/dist/vector-store.js.map +1 -0
  52. package/package.json +50 -0
@@ -0,0 +1,80 @@
1
+ import { z } from 'zod';
2
+ import { toMcpErrorResponse } from './errors.js';
3
+ const SemanticSearchDisplaySchema = z.object({
4
+ query: z.string().optional().describe('Search query in natural language'),
5
+ source: z.string().optional().describe('Filter by source: all (default), documents, facts'),
6
+ limit: z.number().optional().describe('Maximum results (default: 10)'),
7
+ threshold: z.number().optional().describe('Minimum relevance threshold 0.0-1.0 (default: 0.3)'),
8
+ namespace: z.string().optional().describe('Filter by namespace (facts only)'),
9
+ tag: z.string().optional().describe('Filter by tag (documents only)'),
10
+ topic: z.string().optional().describe('Filter by topic (documents only)'),
11
+ content_type: z.string().optional().describe('Filter by content type (documents only)'),
12
+ });
13
+ const SemanticReindexDisplaySchema = z.object({
14
+ source: z.string().optional().describe('What to reindex: all (default), documents, facts'),
15
+ });
16
+ const SemanticSearchInputSchema = z.strictObject({
17
+ query: z.string().min(1).max(1000),
18
+ source: z.enum(['all', 'documents', 'facts']).default('all'),
19
+ limit: z.number().int().min(1).max(100).default(10),
20
+ threshold: z.number().min(0).max(1).default(0.3),
21
+ namespace: z.string().optional(),
22
+ tag: z.string().optional(),
23
+ topic: z.string().optional(),
24
+ content_type: z.string().optional(),
25
+ });
26
+ const SemanticReindexInputSchema = z.strictObject({
27
+ source: z.enum(['all', 'documents', 'facts']).default('all'),
28
+ });
29
+ /**
30
+ * Registers semantic_search and semantic_reindex tools on the MCP server.
31
+ * @param server - The MCP server instance to register tools on.
32
+ * @param semanticIndex - The semantic index used for embedding-based search and reindexing.
33
+ * @param _logger - Logger instance (reserved for future use).
34
+ */
35
+ export function registerSemanticTools(server, semanticIndex, _logger) {
36
+ server.registerTool('semantic_search', {
37
+ title: 'Semantic Search',
38
+ description: 'Search documents and facts by meaning using natural language queries. Returns ranked results with relevance scores.',
39
+ inputSchema: SemanticSearchDisplaySchema,
40
+ }, async (rawInput) => {
41
+ try {
42
+ const input = SemanticSearchInputSchema.parse(rawInput);
43
+ const result = await semanticIndex.search(input.query, {
44
+ source: input.source, limit: input.limit, threshold: input.threshold,
45
+ namespace: input.namespace, tag: input.tag, topic: input.topic, content_type: input.content_type,
46
+ });
47
+ const output = { status: result.status, hint: result.hint, results: result.results, total: result.total, query: input.query };
48
+ return {
49
+ content: [{ type: 'text', text: JSON.stringify(output) }],
50
+ structuredContent: output,
51
+ };
52
+ }
53
+ catch (error) {
54
+ return toMcpErrorResponse(error);
55
+ }
56
+ });
57
+ server.registerTool('semantic_reindex', {
58
+ title: 'Semantic Reindex',
59
+ description: 'Rebuild the semantic search index for all documents and/or facts.',
60
+ inputSchema: SemanticReindexDisplaySchema,
61
+ }, async (rawInput) => {
62
+ try {
63
+ const input = SemanticReindexInputSchema.parse(rawInput);
64
+ const result = await semanticIndex.reindex(input.source);
65
+ const output = {
66
+ success: true,
67
+ indexed: { facts: result.facts, documents: result.documents, total: result.total },
68
+ skipped: result.skipped, duration_ms: result.duration_ms, model: semanticIndex.modelId,
69
+ };
70
+ return {
71
+ content: [{ type: 'text', text: JSON.stringify(output) }],
72
+ structuredContent: output,
73
+ };
74
+ }
75
+ catch (error) {
76
+ return toMcpErrorResponse(error);
77
+ }
78
+ });
79
+ }
80
+ //# sourceMappingURL=semantic-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-tools.js","sourceRoot":"","sources":["../src/semantic-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,161 @@
1
+ import { z } from 'zod';
2
+ export declare const VECTOR_INDEX_VERSION = 2;
3
+ export declare const DEFAULT_SEARCH_LIMIT = 10;
4
+ export declare const DEFAULT_SEARCH_THRESHOLD = 0.3;
5
+ export declare const FACT_ID_PREFIX = "fact:";
6
+ export declare const DOC_ID_PREFIX = "doc:";
7
+ export declare const IndexStatusEnum: z.ZodEnum<{
8
+ ready: "ready";
9
+ empty: "empty";
10
+ stale_model: "stale_model";
11
+ partial: "partial";
12
+ model_loading: "model_loading";
13
+ model_unavailable: "model_unavailable";
14
+ }>;
15
+ export type IndexStatus = z.infer<typeof IndexStatusEnum>;
16
+ export declare const INDEX_STATUS_HINTS: Record<IndexStatus, string | undefined>;
17
+ export declare const FactVectorMetadataSchema: z.ZodObject<{
18
+ key: z.ZodString;
19
+ namespace: z.ZodString;
20
+ preview: z.ZodString;
21
+ }, z.core.$strip>;
22
+ export declare const DocumentVectorMetadataSchema: z.ZodObject<{
23
+ documentId: z.ZodString;
24
+ title: z.ZodString;
25
+ topic: z.ZodOptional<z.ZodString>;
26
+ tags: z.ZodArray<z.ZodString>;
27
+ contentType: z.ZodString;
28
+ }, z.core.$strip>;
29
+ export declare const VectorMetadataSchema: z.ZodUnion<readonly [z.ZodObject<{
30
+ key: z.ZodString;
31
+ namespace: z.ZodString;
32
+ preview: z.ZodString;
33
+ }, z.core.$strip>, z.ZodObject<{
34
+ documentId: z.ZodString;
35
+ title: z.ZodString;
36
+ topic: z.ZodOptional<z.ZodString>;
37
+ tags: z.ZodArray<z.ZodString>;
38
+ contentType: z.ZodString;
39
+ }, z.core.$strip>]>;
40
+ export type FactVectorMetadata = z.infer<typeof FactVectorMetadataSchema>;
41
+ export type DocumentVectorMetadata = z.infer<typeof DocumentVectorMetadataSchema>;
42
+ export type VectorMetadata = z.infer<typeof VectorMetadataSchema>;
43
+ export declare const VectorEntrySchema: z.ZodObject<{
44
+ id: z.ZodString;
45
+ vector: z.ZodArray<z.ZodNumber>;
46
+ source: z.ZodEnum<{
47
+ fact: "fact";
48
+ document: "document";
49
+ }>;
50
+ metadata: z.ZodUnion<readonly [z.ZodObject<{
51
+ key: z.ZodString;
52
+ namespace: z.ZodString;
53
+ preview: z.ZodString;
54
+ }, z.core.$strip>, z.ZodObject<{
55
+ documentId: z.ZodString;
56
+ title: z.ZodString;
57
+ topic: z.ZodOptional<z.ZodString>;
58
+ tags: z.ZodArray<z.ZodString>;
59
+ contentType: z.ZodString;
60
+ }, z.core.$strip>]>;
61
+ indexedAt: z.ZodNumber;
62
+ }, z.core.$strip>;
63
+ export type VectorEntry = z.infer<typeof VectorEntrySchema>;
64
+ export declare const EmbeddingFailureRecordSchema: z.ZodObject<{
65
+ retries: z.ZodNumber;
66
+ status: z.ZodEnum<{
67
+ pending: "pending";
68
+ failed: "failed";
69
+ }>;
70
+ lastError: z.ZodOptional<z.ZodString>;
71
+ lastAttempt: z.ZodNumber;
72
+ }, z.core.$strip>;
73
+ export type EmbeddingFailureRecord = z.infer<typeof EmbeddingFailureRecordSchema>;
74
+ export declare const EmbeddingQueueItemSchema: z.ZodObject<{
75
+ id: z.ZodString;
76
+ source: z.ZodEnum<{
77
+ fact: "fact";
78
+ document: "document";
79
+ }>;
80
+ textToEmbed: z.ZodString;
81
+ metadata: z.ZodUnion<readonly [z.ZodObject<{
82
+ key: z.ZodString;
83
+ namespace: z.ZodString;
84
+ preview: z.ZodString;
85
+ }, z.core.$strip>, z.ZodObject<{
86
+ documentId: z.ZodString;
87
+ title: z.ZodString;
88
+ topic: z.ZodOptional<z.ZodString>;
89
+ tags: z.ZodArray<z.ZodString>;
90
+ contentType: z.ZodString;
91
+ }, z.core.$strip>]>;
92
+ enqueuedAt: z.ZodNumber;
93
+ }, z.core.$strip>;
94
+ export type EmbeddingQueueItem = z.infer<typeof EmbeddingQueueItemSchema>;
95
+ export declare const VectorIndexSchema: z.ZodObject<{
96
+ version: z.ZodNumber;
97
+ modelId: z.ZodString;
98
+ dimensions: z.ZodNumber;
99
+ entries: z.ZodArray<z.ZodObject<{
100
+ id: z.ZodString;
101
+ vector: z.ZodArray<z.ZodNumber>;
102
+ source: z.ZodEnum<{
103
+ fact: "fact";
104
+ document: "document";
105
+ }>;
106
+ metadata: z.ZodUnion<readonly [z.ZodObject<{
107
+ key: z.ZodString;
108
+ namespace: z.ZodString;
109
+ preview: z.ZodString;
110
+ }, z.core.$strip>, z.ZodObject<{
111
+ documentId: z.ZodString;
112
+ title: z.ZodString;
113
+ topic: z.ZodOptional<z.ZodString>;
114
+ tags: z.ZodArray<z.ZodString>;
115
+ contentType: z.ZodString;
116
+ }, z.core.$strip>]>;
117
+ indexedAt: z.ZodNumber;
118
+ }, z.core.$strip>>;
119
+ updatedAt: z.ZodNumber;
120
+ failedEmbeddings: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
121
+ retries: z.ZodNumber;
122
+ status: z.ZodEnum<{
123
+ pending: "pending";
124
+ failed: "failed";
125
+ }>;
126
+ lastError: z.ZodOptional<z.ZodString>;
127
+ lastAttempt: z.ZodNumber;
128
+ }, z.core.$strip>>>;
129
+ }, z.core.$strip>;
130
+ export type VectorIndex = z.infer<typeof VectorIndexSchema>;
131
+ export declare const SearchResultSchema: z.ZodObject<{
132
+ source: z.ZodEnum<{
133
+ fact: "fact";
134
+ document: "document";
135
+ }>;
136
+ id: z.ZodString;
137
+ score: z.ZodNumber;
138
+ metadata: z.ZodUnion<readonly [z.ZodObject<{
139
+ key: z.ZodString;
140
+ namespace: z.ZodString;
141
+ preview: z.ZodString;
142
+ }, z.core.$strip>, z.ZodObject<{
143
+ documentId: z.ZodString;
144
+ title: z.ZodString;
145
+ topic: z.ZodOptional<z.ZodString>;
146
+ tags: z.ZodArray<z.ZodString>;
147
+ contentType: z.ZodString;
148
+ }, z.core.$strip>]>;
149
+ }, z.core.$strip>;
150
+ export type SearchResult = z.infer<typeof SearchResultSchema>;
151
+ export interface SearchFilterOptions {
152
+ source?: 'all' | 'documents' | 'facts';
153
+ namespace?: string;
154
+ tag?: string;
155
+ topic?: string;
156
+ content_type?: string;
157
+ limit?: number;
158
+ threshold?: number;
159
+ }
160
+ export declare function makeFactVectorId(namespace: string, key: string): string;
161
+ export declare function makeDocVectorId(documentId: string): string;
@@ -0,0 +1,101 @@
1
+ import { z } from 'zod';
2
+ // ============================================================================
3
+ // Constants
4
+ // ============================================================================
5
+ export const VECTOR_INDEX_VERSION = 2;
6
+ export const DEFAULT_SEARCH_LIMIT = 10;
7
+ export const DEFAULT_SEARCH_THRESHOLD = 0.3;
8
+ export const FACT_ID_PREFIX = 'fact:';
9
+ export const DOC_ID_PREFIX = 'doc:';
10
+ // ============================================================================
11
+ // Index Status
12
+ // ============================================================================
13
+ export const IndexStatusEnum = z.enum([
14
+ 'ready', 'empty', 'stale_model', 'partial', 'model_loading', 'model_unavailable',
15
+ ]);
16
+ export const INDEX_STATUS_HINTS = {
17
+ ready: undefined,
18
+ empty: 'Index is empty. Call semantic_reindex to index existing data.',
19
+ stale_model: 'Model has changed. Call semantic_reindex to re-index with the new model.',
20
+ partial: 'Index is incomplete. Call semantic_reindex for full indexing.',
21
+ model_loading: 'Model is loading, retry in a few seconds.',
22
+ model_unavailable: 'Embedding model could not be loaded. Run semantic_reindex to attempt repair, or use text-based search via memory_manage.',
23
+ };
24
+ // ============================================================================
25
+ // Vector Metadata
26
+ // ============================================================================
27
+ export const FactVectorMetadataSchema = z.object({
28
+ key: z.string(),
29
+ namespace: z.string(),
30
+ preview: z.string(),
31
+ });
32
+ export const DocumentVectorMetadataSchema = z.object({
33
+ documentId: z.string(),
34
+ title: z.string(),
35
+ topic: z.string().optional(),
36
+ tags: z.array(z.string()),
37
+ contentType: z.string(),
38
+ });
39
+ export const VectorMetadataSchema = z.union([
40
+ FactVectorMetadataSchema,
41
+ DocumentVectorMetadataSchema,
42
+ ]);
43
+ // ============================================================================
44
+ // Vector Entry
45
+ // ============================================================================
46
+ export const VectorEntrySchema = z.object({
47
+ id: z.string(),
48
+ vector: z.array(z.number()),
49
+ source: z.enum(['fact', 'document']),
50
+ metadata: VectorMetadataSchema,
51
+ indexedAt: z.number(),
52
+ });
53
+ // ============================================================================
54
+ // Embedding Failure Record
55
+ // ============================================================================
56
+ export const EmbeddingFailureRecordSchema = z.object({
57
+ retries: z.number().int().nonnegative(),
58
+ status: z.enum(['pending', 'failed']),
59
+ lastError: z.string().optional(),
60
+ lastAttempt: z.number(),
61
+ });
62
+ // ============================================================================
63
+ // Embedding Queue Item
64
+ // ============================================================================
65
+ export const EmbeddingQueueItemSchema = z.object({
66
+ id: z.string(),
67
+ source: z.enum(['fact', 'document']),
68
+ textToEmbed: z.string(),
69
+ metadata: VectorMetadataSchema,
70
+ enqueuedAt: z.number(),
71
+ });
72
+ // ============================================================================
73
+ // Vector Index (persisted to disk)
74
+ // ============================================================================
75
+ export const VectorIndexSchema = z.object({
76
+ version: z.number(),
77
+ modelId: z.string(),
78
+ dimensions: z.number(),
79
+ entries: z.array(VectorEntrySchema),
80
+ updatedAt: z.number(),
81
+ failedEmbeddings: z.record(z.string(), EmbeddingFailureRecordSchema).default({}),
82
+ });
83
+ // ============================================================================
84
+ // Search Result
85
+ // ============================================================================
86
+ export const SearchResultSchema = z.object({
87
+ source: z.enum(['fact', 'document']),
88
+ id: z.string(),
89
+ score: z.number(),
90
+ metadata: VectorMetadataSchema,
91
+ });
92
+ // ============================================================================
93
+ // Helper: Compose vector entry ID
94
+ // ============================================================================
95
+ export function makeFactVectorId(namespace, key) {
96
+ return `${FACT_ID_PREFIX}${namespace}\0${key}`;
97
+ }
98
+ export function makeDocVectorId(documentId) {
99
+ return `${DOC_ID_PREFIX}${documentId}`;
100
+ }
101
+ //# sourceMappingURL=semantic-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-types.js","sourceRoot":"","sources":["../src/semantic-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ import type { Logger } from 'pino';
2
+ import type { Config, ResolvedPaths } from './config.js';
3
+ import type { FactMetadata, NamespaceInfo, MemoryStats } from './types.js';
4
+ import type { SemanticIndex } from './semantic-index.js';
5
+ /**
6
+ * LRU-backed in-memory fact store with namespacing, TTL support,
7
+ * optional semantic indexing, and JSON file persistence.
8
+ */
9
+ export declare class MemoryStore {
10
+ private readonly cache;
11
+ private readonly config;
12
+ private readonly storagePath;
13
+ private readonly logger;
14
+ private semanticIndex;
15
+ private dirty;
16
+ lastSavedAt: number | null;
17
+ constructor(config: Config, paths: ResolvedPaths, logger: Logger);
18
+ /** Attaches a semantic index for embedding-based fact retrieval. */
19
+ setSemanticIndex(index: SemanticIndex): void;
20
+ /**
21
+ * Creates a composite cache key by joining namespace and key with a null byte.
22
+ * @param namespace - The namespace portion of the key.
23
+ * @param key - The fact key within the namespace.
24
+ * @returns The composite key string.
25
+ */
26
+ static makeKey(namespace: string, key: string): string;
27
+ /**
28
+ * Splits a composite cache key back into its namespace and key parts.
29
+ * Falls back to the "default" namespace when no separator is found.
30
+ * @param compositeKey - The composite key to parse.
31
+ * @returns An object containing the namespace and key.
32
+ */
33
+ static parseKey(compositeKey: string): {
34
+ namespace: string;
35
+ key: string;
36
+ };
37
+ private getRemainingTtlSeconds;
38
+ /**
39
+ * Writes or updates a fact in the store.
40
+ * @param key - Fact identifier.
41
+ * @param value - The fact payload.
42
+ * @param namespace - Namespace to store the fact under.
43
+ * @param ttlSeconds - Optional time-to-live in seconds.
44
+ * @returns An object indicating whether a new fact was created.
45
+ */
46
+ write(key: string, value: unknown, namespace: string, ttlSeconds?: number): {
47
+ created: boolean;
48
+ };
49
+ /**
50
+ * Reads a single fact by key and namespace.
51
+ * @param key - Fact identifier.
52
+ * @param namespace - Namespace the fact belongs to.
53
+ * @returns The fact metadata including TTL info, or null if not found.
54
+ */
55
+ read(key: string, namespace: string): FactMetadata | null;
56
+ /**
57
+ * Lists facts with optional namespace filtering, glob pattern matching, and pagination.
58
+ * Can optionally include values and store-level statistics.
59
+ */
60
+ list(options: {
61
+ namespace?: string;
62
+ pattern?: string;
63
+ limit: number;
64
+ includeValues: boolean;
65
+ includeStats: boolean;
66
+ }): {
67
+ facts: Array<Record<string, unknown>>;
68
+ stats?: MemoryStats;
69
+ };
70
+ /** Returns all namespaces with their respective fact counts. */
71
+ getNamespaces(): NamespaceInfo[];
72
+ /**
73
+ * Searches facts by regex pattern, matching against both keys and values.
74
+ * Validates the regex for safety against ReDoS before executing.
75
+ */
76
+ search(options: {
77
+ query: string;
78
+ namespace?: string;
79
+ limit: number;
80
+ }): {
81
+ results: Array<Record<string, unknown>>;
82
+ total_matches: number;
83
+ limit: number;
84
+ };
85
+ get size(): number;
86
+ get maxEntries(): number;
87
+ /**
88
+ * Deletes a single fact by key and namespace.
89
+ * @param key - Fact identifier.
90
+ * @param namespace - Namespace the fact belongs to.
91
+ * @returns True if the fact existed and was deleted.
92
+ */
93
+ delete(key: string, namespace: string): boolean;
94
+ /**
95
+ * Deletes all facts within the given namespace.
96
+ * @param namespace - The namespace to clear.
97
+ * @returns The number of facts deleted.
98
+ */
99
+ deleteNamespace(namespace: string): number;
100
+ /**
101
+ * Persists the cache to disk using atomic write (temp file + rename).
102
+ * Skips saving when no changes have been made or when the cache is empty
103
+ * but the file on disk still contains data (safety guard).
104
+ * @returns True if the save was performed successfully.
105
+ */
106
+ save(): Promise<boolean>;
107
+ /** Loads facts from the on-disk JSON file into the cache. Starts empty if the file is missing or corrupt. */
108
+ load(): Promise<void>;
109
+ private autosaveTimer;
110
+ /**
111
+ * Starts a recurring autosave timer that persists dirty state to disk.
112
+ * @param intervalMs - Interval between saves in milliseconds. Values <= 0 are ignored.
113
+ */
114
+ startAutosave(intervalMs: number): void;
115
+ /** Stops the autosave timer if one is running. */
116
+ stopAutosave(): void;
117
+ /**
118
+ * Exports all facts as a versioned JSON-serializable object.
119
+ * Includes TTL remaining at the time of export.
120
+ * @returns An export payload with version, timestamp, count, and fact data.
121
+ */
122
+ export(): Record<string, unknown>;
123
+ /**
124
+ * Imports facts from a JSON string previously produced by {@link export}.
125
+ * @param dataStr - JSON string containing the export payload.
126
+ * @param merge - When true, merges into existing data; when false, replaces all facts.
127
+ * @returns Summary with imported and overwritten counts.
128
+ */
129
+ import(dataStr: string, merge: boolean): Record<string, unknown>;
130
+ }