@mmnto/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.
@@ -0,0 +1,19 @@
1
+ import type { Embedder, TotemConfig } from '@mmnto/totem';
2
+ import { LanceStore } from '@mmnto/totem';
3
+ export interface ServerContext {
4
+ projectRoot: string;
5
+ config: TotemConfig;
6
+ store: LanceStore;
7
+ embedder: Embedder;
8
+ }
9
+ /**
10
+ * Re-open the cached LanceStore connection after a full sync rebuild.
11
+ * No-op if the context hasn't been initialized yet.
12
+ */
13
+ export declare function reconnectStore(): Promise<void>;
14
+ /**
15
+ * Lazily initialize and return the shared server context.
16
+ * Config, embedder, and LanceStore are created on first call and cached.
17
+ */
18
+ export declare function getContext(): Promise<ServerContext>;
19
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAkB,UAAU,EAAqB,MAAM,cAAc,CAAC;AAE7E,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAID;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAIpD;AAiCD;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC,CAsBzD"}
@@ -0,0 +1,64 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { createEmbedder, LanceStore, TotemConfigSchema } from '@mmnto/totem';
4
+ let cached;
5
+ /**
6
+ * Re-open the cached LanceStore connection after a full sync rebuild.
7
+ * No-op if the context hasn't been initialized yet.
8
+ */
9
+ export async function reconnectStore() {
10
+ if (cached) {
11
+ await cached.store.reconnect();
12
+ }
13
+ }
14
+ /**
15
+ * Load environment variables from .env file (does not override existing).
16
+ */
17
+ function loadEnv(cwd) {
18
+ const envPath = path.join(cwd, '.env');
19
+ if (!fs.existsSync(envPath))
20
+ return;
21
+ const content = fs.readFileSync(envPath, 'utf-8');
22
+ for (const line of content.split('\n')) {
23
+ const match = line.match(/^([^#=]+)=(.*)$/);
24
+ if (match) {
25
+ const key = match[1].trim();
26
+ const value = match[2].trim();
27
+ if (!process.env[key]) {
28
+ process.env[key] = value;
29
+ }
30
+ }
31
+ }
32
+ }
33
+ /**
34
+ * Load and parse totem.config.ts via jiti.
35
+ */
36
+ async function loadConfig(configPath) {
37
+ const { createJiti } = await import('jiti');
38
+ const jiti = createJiti(import.meta.url);
39
+ const mod = (await jiti.import(configPath));
40
+ const raw = mod['default'] ?? mod;
41
+ return TotemConfigSchema.parse(raw);
42
+ }
43
+ /**
44
+ * Lazily initialize and return the shared server context.
45
+ * Config, embedder, and LanceStore are created on first call and cached.
46
+ */
47
+ export async function getContext() {
48
+ if (cached)
49
+ return cached;
50
+ const projectRoot = process.cwd();
51
+ const configPath = path.join(projectRoot, 'totem.config.ts');
52
+ if (!fs.existsSync(configPath)) {
53
+ throw new Error('[Totem Error] No totem.config.ts found in current directory. Run `totem init` first.');
54
+ }
55
+ loadEnv(projectRoot);
56
+ const config = await loadConfig(configPath);
57
+ const embedder = createEmbedder(config.embedding);
58
+ const storePath = path.join(projectRoot, config.lanceDir);
59
+ const store = new LanceStore(storePath, embedder);
60
+ await store.connect();
61
+ cached = { projectRoot, config, store, embedder };
62
+ return cached;
63
+ }
64
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAS7E,IAAI,MAAiC,CAAC;AAEtC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;IACjC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,OAAO,CAAC,GAAW;IAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO;IAEpC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAClD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC5C,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC;YAC/B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,UAAU,CAAC,UAAkB;IAC1C,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAA4B,CAAC;IACvE,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC;IAClC,OAAO,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAElC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;IAC7D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CACb,sFAAsF,CACvF,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,WAAW,CAAC,CAAC;IAErB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAClD,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;IAEtB,MAAM,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
+ import { z } from 'zod';
6
+ import { registerAddLesson } from './tools/add-lesson.js';
7
+ import { registerSearchKnowledge } from './tools/search-knowledge.js';
8
+ const require = createRequire(import.meta.url);
9
+ const { version } = z.object({ version: z.string() }).parse(require('../package.json'));
10
+ const server = new McpServer({
11
+ name: '@mmnto/totem',
12
+ version,
13
+ });
14
+ registerSearchKnowledge(server);
15
+ registerAddLesson(server);
16
+ const transport = new StdioServerTransport();
17
+ await server.connect(transport);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAExF,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,cAAc;IACpB,OAAO;CACR,CAAC,CAAC;AAEH,uBAAuB,CAAC,MAAM,CAAC,CAAC;AAChC,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAE1B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerAddLesson(server: McpServer): void;
3
+ //# sourceMappingURL=add-lesson.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-lesson.d.ts","sourceRoot":"","sources":["../../src/tools/add-lesson.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAuBzE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsFzD"}
@@ -0,0 +1,98 @@
1
+ import { spawn } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import { z } from 'zod';
5
+ import { getContext, reconnectStore } from '../context.js';
6
+ /**
7
+ * Detect the correct package-manager command for running `totem sync`.
8
+ */
9
+ function detectSyncCommand(projectRoot) {
10
+ if (fs.existsSync(path.join(projectRoot, 'pnpm-lock.yaml'))) {
11
+ return { cmd: 'pnpm', args: ['exec', 'totem', 'sync', '--incremental'] };
12
+ }
13
+ if (fs.existsSync(path.join(projectRoot, 'yarn.lock'))) {
14
+ return { cmd: 'yarn', args: ['totem', 'sync', '--incremental'] };
15
+ }
16
+ return { cmd: 'npx', args: ['totem', 'sync', '--incremental'] };
17
+ }
18
+ const RECONNECT_DELAY_MS = 5_000;
19
+ /** Debounce guard — prevents concurrent sync processes. */
20
+ let syncPending = false;
21
+ export function registerAddLesson(server) {
22
+ server.registerTool('add_lesson', {
23
+ description: 'Persist a lesson learned to .totem/lessons.md. An incremental re-index is automatically triggered in the background.',
24
+ inputSchema: {
25
+ lesson: z.string().describe('The lesson text to persist'),
26
+ context_tags: z
27
+ .array(z.string())
28
+ .describe('Tags for categorization (e.g. ["caching", "nextjs", "trap"])'),
29
+ },
30
+ annotations: {
31
+ readOnlyHint: false,
32
+ },
33
+ }, async ({ lesson, context_tags }) => {
34
+ try {
35
+ const { projectRoot, config } = await getContext();
36
+ const totemDir = path.join(projectRoot, config.totemDir);
37
+ await fs.promises.mkdir(totemDir, { recursive: true });
38
+ const lessonsPath = path.join(totemDir, 'lessons.md');
39
+ const timestamp = new Date().toISOString();
40
+ const tags = context_tags.join(', ');
41
+ const entry = `\n## Lesson — ${timestamp}\n\n` + `**Tags:** ${tags}\n\n` + `${lesson}\n`;
42
+ await fs.promises.appendFile(lessonsPath, entry, 'utf-8');
43
+ // Fire-and-forget: spawn background incremental sync so the lesson
44
+ // is searchable within this session (Issue #22).
45
+ // Debounce: skip if a sync is already in flight.
46
+ if (!syncPending) {
47
+ syncPending = true;
48
+ const { cmd, args } = detectSyncCommand(projectRoot);
49
+ const logPath = path.join(totemDir, 'mcp-sync.log');
50
+ const logFd = fs.openSync(logPath, 'a');
51
+ try {
52
+ const child = spawn(cmd, args, {
53
+ cwd: projectRoot,
54
+ detached: true,
55
+ stdio: ['ignore', logFd, logFd],
56
+ shell: true,
57
+ windowsHide: true,
58
+ });
59
+ child.unref();
60
+ }
61
+ finally {
62
+ fs.closeSync(logFd);
63
+ }
64
+ // Reconnect the store after the sync has had time to finish,
65
+ // so the next search_knowledge call sees the new data.
66
+ const errLogPath = path.join(totemDir, 'mcp-errors.log');
67
+ setTimeout(() => {
68
+ reconnectStore()
69
+ .catch((err) => {
70
+ const msg = `[${new Date().toISOString()}] Store reconnect failed: ${err instanceof Error ? err.message : String(err)}\n`;
71
+ fs.promises.appendFile(errLogPath, msg, 'utf-8').catch(() => {
72
+ // Last-resort: file logging failed — nothing left to do.
73
+ });
74
+ })
75
+ .finally(() => {
76
+ syncPending = false;
77
+ });
78
+ }, RECONNECT_DELAY_MS);
79
+ }
80
+ return {
81
+ content: [
82
+ {
83
+ type: 'text',
84
+ text: `Lesson saved to ${config.totemDir}/lessons.md. Background re-index triggered — it will be searchable shortly.`,
85
+ },
86
+ ],
87
+ };
88
+ }
89
+ catch (err) {
90
+ const originalMessage = err instanceof Error ? err.message : String(err);
91
+ const message = originalMessage.startsWith('[Totem Error]')
92
+ ? originalMessage
93
+ : `[Totem Error] Failed to add lesson: ${originalMessage}`;
94
+ return { content: [{ type: 'text', text: message }], isError: true };
95
+ }
96
+ });
97
+ }
98
+ //# sourceMappingURL=add-lesson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-lesson.js","sourceRoot":"","sources":["../../src/tools/add-lesson.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerSearchKnowledge(server: McpServer): void;
3
+ //# sourceMappingURL=search-knowledge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-knowledge.d.ts","sourceRoot":"","sources":["../../src/tools/search-knowledge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA6CzE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwD/D"}
@@ -0,0 +1,78 @@
1
+ import { z } from 'zod';
2
+ import { ContentTypeSchema } from '@mmnto/totem';
3
+ import { getContext, reconnectStore } from '../context.js';
4
+ // Heuristic to detect stale LanceDB file handles after a full sync rebuild.
5
+ // Observed errors that indicate a stale handle:
6
+ // - "IO-error: ... not found" when underlying .lance files are deleted
7
+ // - "LanceError: ..." for other file access issues after rebuild
8
+ // TODO: Replace with error codes if future LanceDB versions expose them.
9
+ const LANCE_STALE_ERROR_PATTERN = /not found|LanceError/i;
10
+ async function performSearch(query, typeFilter, maxResults) {
11
+ const { store } = await getContext();
12
+ const results = await store.search({
13
+ query,
14
+ typeFilter,
15
+ maxResults: maxResults ?? 5,
16
+ });
17
+ if (results.length === 0) {
18
+ return { content: [{ type: 'text', text: 'No results found.' }] };
19
+ }
20
+ const formatted = results
21
+ .map((r, i) => `### ${i + 1}. ${r.label} (${r.type})\n` +
22
+ `**File:** ${r.filePath} | **Score:** ${r.score.toFixed(3)}\n\n` +
23
+ `${r.content}`)
24
+ .join('\n\n---\n\n');
25
+ return { content: [{ type: 'text', text: formatted }] };
26
+ }
27
+ export function registerSearchKnowledge(server) {
28
+ server.registerTool('search_knowledge', {
29
+ description: 'Search the Totem knowledge index for relevant code, session logs, specs, or lessons.',
30
+ inputSchema: {
31
+ query: z.string().describe('The search query'),
32
+ type_filter: z
33
+ .enum(ContentTypeSchema.options)
34
+ .optional()
35
+ .describe('Filter results by content type: code, session_log, or spec'),
36
+ max_results: z
37
+ .number()
38
+ .int()
39
+ .positive()
40
+ .optional()
41
+ .describe('Maximum number of results to return (default: 5)'),
42
+ },
43
+ annotations: {
44
+ readOnlyHint: true,
45
+ },
46
+ }, async ({ query, type_filter, max_results }) => {
47
+ try {
48
+ return await performSearch(query, type_filter, max_results);
49
+ }
50
+ catch (err) {
51
+ const originalMessage = err instanceof Error ? err.message : String(err);
52
+ const isStale = LANCE_STALE_ERROR_PATTERN.test(originalMessage);
53
+ if (isStale) {
54
+ try {
55
+ await reconnectStore();
56
+ return await performSearch(query, type_filter, max_results);
57
+ }
58
+ catch (retryErr) {
59
+ const retryMessage = retryErr instanceof Error ? retryErr.message : String(retryErr);
60
+ return {
61
+ content: [
62
+ {
63
+ type: 'text',
64
+ text: `[Totem Error] Failed to search knowledge after reconnect: ${retryMessage}`,
65
+ },
66
+ ],
67
+ isError: true,
68
+ };
69
+ }
70
+ }
71
+ const message = originalMessage.startsWith('[Totem Error]')
72
+ ? originalMessage
73
+ : `[Totem Error] Failed to search knowledge: ${originalMessage}`;
74
+ return { content: [{ type: 'text', text: message }], isError: true };
75
+ }
76
+ });
77
+ }
78
+ //# sourceMappingURL=search-knowledge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-knowledge.js","sourceRoot":"","sources":["../../src/tools/search-knowledge.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@mmnto/mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Totem — AI persistent memory and context layer",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "bin": {
15
+ "totem-mcp": "./dist/index.js"
16
+ },
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "dev": "tsc --watch",
20
+ "clean": "rm -rf dist",
21
+ "lint": "eslint src/",
22
+ "test": "echo \"No tests yet\" && exit 0"
23
+ },
24
+ "dependencies": {
25
+ "@mmnto/totem": "workspace:*",
26
+ "@modelcontextprotocol/sdk": "^1.0.0",
27
+ "jiti": "^2.4.0",
28
+ "zod": "^3.24.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^22.0.0",
32
+ "typescript": "^5.7.0"
33
+ },
34
+ "files": [
35
+ "dist"
36
+ ],
37
+ "license": "MIT",
38
+ "author": "mmnto-ai",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://github.com/mmnto-ai/totem.git",
42
+ "directory": "packages/mcp"
43
+ },
44
+ "homepage": "https://github.com/mmnto-ai/totem",
45
+ "bugs": {
46
+ "url": "https://github.com/mmnto-ai/totem/issues"
47
+ },
48
+ "publishConfig": {
49
+ "access": "public"
50
+ }
51
+ }