cc-forever-mcp 1.0.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,13 @@
1
+ /**
2
+ * Conversation chunker - Parse Human/Assistant pairs
3
+ */
4
+ interface Chunk {
5
+ text: string;
6
+ question: string;
7
+ }
8
+ /**
9
+ * Parse conversation into Q&A pairs
10
+ */
11
+ export declare function chunkConversation(content: string): Chunk[];
12
+ export {};
13
+ //# sourceMappingURL=chunker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunker.d.ts","sourceRoot":"","sources":["../src/chunker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,UAAU,KAAK;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,EAAE,CAmD1D"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Conversation chunker - Parse Human/Assistant pairs
3
+ */
4
+ /**
5
+ * Parse conversation into Q&A pairs
6
+ */
7
+ export function chunkConversation(content) {
8
+ const chunks = [];
9
+ const lines = content.split('\n');
10
+ let currentRole = null;
11
+ let currentContent = [];
12
+ let humanQuestion = '';
13
+ const rolePattern = /^(Human|User|Assistant|Claude):\s*/i;
14
+ for (const line of lines) {
15
+ const match = line.match(rolePattern);
16
+ if (match) {
17
+ const role = match[1].toLowerCase();
18
+ const newRole = role === 'human' || role === 'user' ? 'human' : 'assistant';
19
+ const textAfterRole = line.slice(match[0].length);
20
+ // Save previous content
21
+ if (currentRole === 'human' && currentContent.length > 0) {
22
+ humanQuestion = currentContent.join('\n').trim();
23
+ }
24
+ else if (currentRole === 'assistant' && humanQuestion && currentContent.length > 0) {
25
+ const answer = currentContent.join('\n').trim();
26
+ if (answer) {
27
+ chunks.push({
28
+ text: `Human: ${humanQuestion}\nAssistant: ${answer}`,
29
+ question: humanQuestion.slice(0, 200),
30
+ });
31
+ }
32
+ humanQuestion = '';
33
+ }
34
+ currentRole = newRole;
35
+ currentContent = textAfterRole ? [textAfterRole] : [];
36
+ }
37
+ else if (currentRole) {
38
+ currentContent.push(line);
39
+ }
40
+ }
41
+ // Handle last pair
42
+ if (currentRole === 'assistant' && humanQuestion && currentContent.length > 0) {
43
+ const answer = currentContent.join('\n').trim();
44
+ if (answer) {
45
+ chunks.push({
46
+ text: `Human: ${humanQuestion}\nAssistant: ${answer}`,
47
+ question: humanQuestion.slice(0, 200),
48
+ });
49
+ }
50
+ }
51
+ return chunks;
52
+ }
53
+ //# sourceMappingURL=chunker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunker.js","sourceRoot":"","sources":["../src/chunker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,MAAM,GAAY,EAAE,CAAA;IAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAEjC,IAAI,WAAW,GAAiC,IAAI,CAAA;IACpD,IAAI,cAAc,GAAa,EAAE,CAAA;IACjC,IAAI,aAAa,GAAG,EAAE,CAAA;IAEtB,MAAM,WAAW,GAAG,qCAAqC,CAAA;IAEzD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;QAErC,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;YACnC,MAAM,OAAO,GAAG,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAA;YAC3E,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;YAEjD,wBAAwB;YACxB,IAAI,WAAW,KAAK,OAAO,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzD,aAAa,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAA;YAClD,CAAC;iBAAM,IAAI,WAAW,KAAK,WAAW,IAAI,aAAa,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrF,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAA;gBAC/C,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,CAAC,IAAI,CAAC;wBACV,IAAI,EAAE,UAAU,aAAa,gBAAgB,MAAM,EAAE;wBACrD,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;qBACtC,CAAC,CAAA;gBACJ,CAAC;gBACD,aAAa,GAAG,EAAE,CAAA;YACpB,CAAC;YAED,WAAW,GAAG,OAAO,CAAA;YACrB,cAAc,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACvD,CAAC;aAAM,IAAI,WAAW,EAAE,CAAC;YACvB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC3B,CAAC;IACH,CAAC;IAED,mBAAmB;IACnB,IAAI,WAAW,KAAK,WAAW,IAAI,aAAa,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9E,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAA;QAC/C,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,UAAU,aAAa,gBAAgB,MAAM,EAAE;gBACrD,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;aACtC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Configuration loader
3
+ */
4
+ export interface Config {
5
+ embeddings?: {
6
+ path?: string;
7
+ };
8
+ data_dir?: string;
9
+ auto_index?: boolean;
10
+ source?: string;
11
+ }
12
+ /**
13
+ * Load config with priority:
14
+ * 1. Project-level: ./.forever/config.yml
15
+ * 2. User-level: ~/.forever/config.yml
16
+ * 3. Default settings
17
+ *
18
+ * data_dir is automatically set to the directory containing the config file
19
+ */
20
+ export declare function loadConfig(): Config;
21
+ /**
22
+ * Get data directory path
23
+ */
24
+ export declare function getDataDir(config: Config): string;
25
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,MAAM;IACrB,UAAU,CAAC,EAAE;QACX,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,CAAA;IACD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,IAAI,MAAM,CA6BnC;AA+CD;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CASjD"}
package/dist/config.js ADDED
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Configuration loader
3
+ */
4
+ import * as fs from 'node:fs';
5
+ import * as path from 'node:path';
6
+ import * as os from 'node:os';
7
+ /**
8
+ * Load config with priority:
9
+ * 1. Project-level: ./.forever/config.yml
10
+ * 2. User-level: ~/.forever/config.yml
11
+ * 3. Default settings
12
+ *
13
+ * data_dir is automatically set to the directory containing the config file
14
+ */
15
+ export function loadConfig() {
16
+ // Priority 1: Project-level
17
+ const projectDir = path.join(process.cwd(), '.forever');
18
+ const projectConfig = path.join(projectDir, 'config.yml');
19
+ if (fs.existsSync(projectConfig)) {
20
+ return {
21
+ ...parseYaml(projectConfig),
22
+ data_dir: projectDir,
23
+ source: projectConfig,
24
+ };
25
+ }
26
+ // Priority 2: User-level
27
+ const userDir = path.join(os.homedir(), '.forever');
28
+ const userConfig = path.join(userDir, 'config.yml');
29
+ if (fs.existsSync(userConfig)) {
30
+ return {
31
+ ...parseYaml(userConfig),
32
+ data_dir: userDir,
33
+ source: userConfig,
34
+ };
35
+ }
36
+ // Priority 3: Default (user-level)
37
+ return {
38
+ embeddings: { path: 'Xenova/all-MiniLM-L6-v2' },
39
+ data_dir: path.join(os.homedir(), '.forever'),
40
+ source: 'default',
41
+ };
42
+ }
43
+ /**
44
+ * Simple YAML parser (handles basic key: value pairs)
45
+ */
46
+ function parseYaml(filePath) {
47
+ const content = fs.readFileSync(filePath, 'utf-8');
48
+ const config = {};
49
+ let currentSection = '';
50
+ for (const line of content.split('\n')) {
51
+ const trimmed = line.trim();
52
+ if (!trimmed || trimmed.startsWith('#'))
53
+ continue;
54
+ // Check indentation for nested values
55
+ const indent = line.length - line.trimStart().length;
56
+ if (indent === 0 && trimmed.includes(':')) {
57
+ const [key, ...valueParts] = trimmed.split(':');
58
+ const value = valueParts.join(':').trim();
59
+ if (value) {
60
+ config[key.trim()] = parseValue(value);
61
+ currentSection = '';
62
+ }
63
+ else {
64
+ currentSection = key.trim();
65
+ config[currentSection] = {};
66
+ }
67
+ }
68
+ else if (indent > 0 && currentSection && trimmed.includes(':')) {
69
+ const [key, ...valueParts] = trimmed.split(':');
70
+ const value = valueParts.join(':').trim();
71
+ config[currentSection][key.trim()] = parseValue(value);
72
+ }
73
+ }
74
+ return config;
75
+ }
76
+ function parseValue(value) {
77
+ if (value.toLowerCase() === 'true')
78
+ return true;
79
+ if (value.toLowerCase() === 'false')
80
+ return false;
81
+ if (/^\d+$/.test(value))
82
+ return parseInt(value, 10);
83
+ if (/^\d+\.\d+$/.test(value))
84
+ return parseFloat(value);
85
+ return value.replace(/^["']|["']$/g, '');
86
+ }
87
+ /**
88
+ * Get data directory path
89
+ */
90
+ export function getDataDir(config) {
91
+ const dir = config.data_dir || path.join(os.homedir(), '.forever');
92
+ const expanded = dir.startsWith('~') ? dir.replace('~', os.homedir()) : dir;
93
+ if (!fs.existsSync(expanded)) {
94
+ fs.mkdirSync(expanded, { recursive: true });
95
+ }
96
+ return expanded;
97
+ }
98
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Embedder implementation with Transformers.js
3
+ */
4
+ export interface EmbedderConfig {
5
+ modelPath: string;
6
+ batchSize: number;
7
+ cacheDir: string;
8
+ }
9
+ export declare class Embedder {
10
+ private model;
11
+ private initPromise;
12
+ private readonly config;
13
+ constructor(config: EmbedderConfig);
14
+ initialize(): Promise<void>;
15
+ private ensureInitialized;
16
+ embed(text: string): Promise<number[]>;
17
+ }
18
+ //# sourceMappingURL=embedder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedder.d.ts","sourceRoot":"","sources":["../src/embedder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAMD,qBAAa,QAAQ;IACnB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;gBAE3B,MAAM,EAAE,cAAc;IAI5B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAanB,iBAAiB;IAkBzB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAoB7C"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Embedder implementation with Transformers.js
3
+ */
4
+ import { env, pipeline } from '@huggingface/transformers';
5
+ // ============================================
6
+ // Embedder Class
7
+ // ============================================
8
+ export class Embedder {
9
+ model = null;
10
+ initPromise = null;
11
+ config;
12
+ constructor(config) {
13
+ this.config = config;
14
+ }
15
+ async initialize() {
16
+ if (this.model)
17
+ return;
18
+ try {
19
+ env.cacheDir = this.config.cacheDir;
20
+ console.error(`Embedder: Loading model "${this.config.modelPath}"...`);
21
+ this.model = await pipeline('feature-extraction', this.config.modelPath);
22
+ console.error('Embedder: Model loaded successfully');
23
+ }
24
+ catch (error) {
25
+ throw new Error(`Failed to initialize Embedder: ${error.message}`);
26
+ }
27
+ }
28
+ async ensureInitialized() {
29
+ if (this.model)
30
+ return;
31
+ if (this.initPromise) {
32
+ await this.initPromise;
33
+ return;
34
+ }
35
+ console.error('Embedder: First use detected. Loading model (may take 1-2 minutes on first run)...');
36
+ this.initPromise = this.initialize().catch((error) => {
37
+ this.initPromise = null;
38
+ throw error;
39
+ });
40
+ await this.initPromise;
41
+ }
42
+ async embed(text) {
43
+ await this.ensureInitialized();
44
+ if (text.length === 0) {
45
+ throw new Error('Cannot generate embedding for empty text');
46
+ }
47
+ try {
48
+ const options = { pooling: 'mean', normalize: true };
49
+ const modelCall = this.model;
50
+ const output = await modelCall(text, options);
51
+ return Array.from(output.data);
52
+ }
53
+ catch (error) {
54
+ throw new Error(`Failed to generate embedding: ${error.message}`);
55
+ }
56
+ }
57
+ }
58
+ //# sourceMappingURL=embedder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedder.js","sourceRoot":"","sources":["../src/embedder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AAYzD,+CAA+C;AAC/C,iBAAiB;AACjB,+CAA+C;AAE/C,MAAM,OAAO,QAAQ;IACX,KAAK,GAAY,IAAI,CAAA;IACrB,WAAW,GAAyB,IAAI,CAAA;IAC/B,MAAM,CAAgB;IAEvC,YAAY,MAAsB;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;IAED,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,KAAK;YAAE,OAAM;QAEtB,IAAI,CAAC;YACH,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAA;YACnC,OAAO,CAAC,KAAK,CAAC,4BAA4B,IAAI,CAAC,MAAM,CAAC,SAAS,MAAM,CAAC,CAAA;YACtE,IAAI,CAAC,KAAK,GAAG,MAAM,QAAQ,CAAC,oBAAoB,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YACxE,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAA;QACtD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,kCAAmC,KAAe,CAAC,OAAO,EAAE,CAAC,CAAA;QAC/E,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,iBAAiB;QAC7B,IAAI,IAAI,CAAC,KAAK;YAAE,OAAM;QAEtB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,IAAI,CAAC,WAAW,CAAA;YACtB,OAAM;QACR,CAAC;QAED,OAAO,CAAC,KAAK,CAAC,oFAAoF,CAAC,CAAA;QAEnG,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACnD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAA;YACvB,MAAM,KAAK,CAAA;QACb,CAAC,CAAC,CAAA;QAEF,MAAM,IAAI,CAAC,WAAW,CAAA;IACxB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,IAAY;QACtB,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAA;QAE9B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;QAC7D,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAA;YACpD,MAAM,SAAS,GAAG,IAAI,CAAC,KAGa,CAAA;YACpC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YAC7C,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,iCAAkC,KAAe,CAAC,OAAO,EAAE,CAAC,CAAA;QAC9E,CAAC;IACH,CAAC;CAEF"}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CC-Forever MCP Server
4
+ * Persistent conversation memory with semantic search
5
+ *
6
+ * Uses LanceDB + Transformers.js for lightweight local embeddings
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}
package/dist/index.js ADDED
@@ -0,0 +1,300 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CC-Forever MCP Server
4
+ * Persistent conversation memory with semantic search
5
+ *
6
+ * Uses LanceDB + Transformers.js for lightweight local embeddings
7
+ */
8
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
9
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
10
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
11
+ import { VectorStore } from './vectorstore.js';
12
+ import { Embedder } from './embedder.js';
13
+ import { chunkConversation } from './chunker.js';
14
+ import { loadConfig, getDataDir } from './config.js';
15
+ // ============================================
16
+ // Main Server
17
+ // ============================================
18
+ class CCForeverServer {
19
+ server;
20
+ vectorStore = null;
21
+ embedder = null;
22
+ config = null;
23
+ initialized = false;
24
+ constructor() {
25
+ this.server = new Server({ name: 'cc-forever-mcp', version: '1.0.0' }, { capabilities: { tools: {} } });
26
+ this.setupHandlers();
27
+ }
28
+ setupHandlers() {
29
+ // List tools
30
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
31
+ tools: [
32
+ {
33
+ name: 'store_memory',
34
+ description: "Store Q&A conversation pairs in the memory index. Content MUST include both Human question AND Assistant answer. Example format: 'Human: How do I use OAuth?\\nAssistant: OAuth is an authentication protocol...'",
35
+ inputSchema: {
36
+ type: 'object',
37
+ properties: {
38
+ content: {
39
+ type: 'string',
40
+ description: "Conversation in 'Human: <question>\\nAssistant: <answer>' format. MUST include both Human and Assistant parts.",
41
+ },
42
+ project: {
43
+ type: 'string',
44
+ description: 'Project name (optional)',
45
+ },
46
+ tags: {
47
+ type: 'array',
48
+ items: { type: 'string' },
49
+ description: 'Tags (optional)',
50
+ },
51
+ chunk: {
52
+ type: 'boolean',
53
+ description: 'Whether to chunk into Q&A pairs (default: true)',
54
+ default: true,
55
+ },
56
+ },
57
+ required: ['content'],
58
+ },
59
+ },
60
+ {
61
+ name: 'retrieve_memory',
62
+ description: 'Search past conversations using semantic search',
63
+ inputSchema: {
64
+ type: 'object',
65
+ properties: {
66
+ query: {
67
+ type: 'string',
68
+ description: 'Search query',
69
+ },
70
+ n_results: {
71
+ type: 'integer',
72
+ description: 'Number of results to return (default: 5)',
73
+ default: 5,
74
+ },
75
+ threshold: {
76
+ type: 'number',
77
+ description: 'Similarity threshold 0-1 (default: 0.3)',
78
+ default: 0.3,
79
+ },
80
+ project: {
81
+ type: 'string',
82
+ description: 'Filter by project name (optional)',
83
+ },
84
+ },
85
+ required: ['query'],
86
+ },
87
+ },
88
+ {
89
+ name: 'get_stats',
90
+ description: 'Get index statistics and configuration info',
91
+ inputSchema: {
92
+ type: 'object',
93
+ properties: {},
94
+ },
95
+ },
96
+ ],
97
+ }));
98
+ // Call tool
99
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
100
+ const { name, arguments: args } = request.params;
101
+ try {
102
+ // Lazy initialization
103
+ if (!this.initialized) {
104
+ await this.initialize();
105
+ }
106
+ switch (name) {
107
+ case 'store_memory':
108
+ return await this.storeMemory(args);
109
+ case 'retrieve_memory':
110
+ return await this.retrieveMemory(args);
111
+ case 'get_stats':
112
+ return await this.getStats();
113
+ default:
114
+ return {
115
+ content: [{ type: 'text', text: JSON.stringify({ success: false, error: `Unknown tool: ${name}` }) }],
116
+ };
117
+ }
118
+ }
119
+ catch (error) {
120
+ return {
121
+ content: [
122
+ {
123
+ type: 'text',
124
+ text: JSON.stringify({
125
+ success: false,
126
+ error: `Tool execution failed: ${error.message}`,
127
+ }),
128
+ },
129
+ ],
130
+ };
131
+ }
132
+ });
133
+ }
134
+ async initialize() {
135
+ this.config = loadConfig();
136
+ const dataDir = getDataDir(this.config);
137
+ const modelPath = this.config.embeddings?.path || 'Xenova/all-MiniLM-L6-v2';
138
+ const cacheDir = `${dataDir}/models`;
139
+ this.embedder = new Embedder({
140
+ modelPath,
141
+ batchSize: 8,
142
+ cacheDir,
143
+ });
144
+ // Download model on initialization
145
+ console.error('CC-Forever: Downloading embedding model (this may take a moment)...');
146
+ await this.embedder.initialize();
147
+ this.vectorStore = new VectorStore({
148
+ dbPath: `${dataDir}/lancedb`,
149
+ tableName: 'memories',
150
+ });
151
+ await this.vectorStore.initialize();
152
+ this.initialized = true;
153
+ console.error('CC-Forever MCP Server initialized');
154
+ }
155
+ async storeMemory(args) {
156
+ const { content, project, tags, chunk = true } = args;
157
+ // Validation
158
+ if (!content || !content.trim()) {
159
+ return {
160
+ content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Content cannot be empty' }) }],
161
+ };
162
+ }
163
+ if (content.length > 100000) {
164
+ return {
165
+ content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Content too large (max 100KB)' }) }],
166
+ };
167
+ }
168
+ const timestamp = new Date().toISOString();
169
+ const chunks = chunk ? chunkConversation(content) : [{ text: content, question: content.slice(0, 200) }];
170
+ if (chunks.length === 0) {
171
+ return {
172
+ content: [
173
+ {
174
+ type: 'text',
175
+ text: JSON.stringify({
176
+ success: false,
177
+ error: "No valid Q&A pairs found in content. Format: 'Human: <question>\\nAssistant: <answer>'",
178
+ }),
179
+ },
180
+ ],
181
+ };
182
+ }
183
+ // Generate embeddings and store
184
+ const documents = [];
185
+ for (let i = 0; i < chunks.length; i++) {
186
+ const c = chunks[i];
187
+ const vector = await this.embedder.embed(c.text);
188
+ documents.push({
189
+ id: `${timestamp}-${i}`,
190
+ text: c.text,
191
+ question: c.question,
192
+ vector,
193
+ project: project || 'default',
194
+ tags: tags?.join(',') || 'conversation',
195
+ timestamp,
196
+ });
197
+ }
198
+ await this.vectorStore.insertChunks(documents);
199
+ return {
200
+ content: [
201
+ {
202
+ type: 'text',
203
+ text: JSON.stringify({
204
+ success: true,
205
+ chunks_stored: chunks.length,
206
+ timestamp,
207
+ }),
208
+ },
209
+ ],
210
+ };
211
+ }
212
+ async retrieveMemory(args) {
213
+ let { query, n_results = 5, threshold = 0.3, project } = args;
214
+ // Validation
215
+ if (!query || !query.trim()) {
216
+ return {
217
+ content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Query cannot be empty' }) }],
218
+ };
219
+ }
220
+ if (query.length > 10000) {
221
+ return {
222
+ content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Query too long (max 10KB)' }) }],
223
+ };
224
+ }
225
+ // Sanitize
226
+ n_results = Math.min(Math.max(n_results, 1), 100);
227
+ threshold = Math.max(0, Math.min(threshold, 1));
228
+ const queryVector = await this.embedder.embed(query);
229
+ const results = await this.vectorStore.search(queryVector, n_results * 2);
230
+ // Filter and format
231
+ const formatted = results
232
+ .filter((r) => {
233
+ // Convert distance to similarity (1 - distance for dot product)
234
+ const similarity = 1 - r.score;
235
+ if (similarity < threshold)
236
+ return false;
237
+ if (project && r.project !== project)
238
+ return false;
239
+ return true;
240
+ })
241
+ .slice(0, n_results)
242
+ .map((r) => ({
243
+ score: Math.round((1 - r.score) * 10000) / 10000,
244
+ question: r.question,
245
+ text: r.text,
246
+ timestamp: r.timestamp,
247
+ project: r.project,
248
+ tags: r.tags,
249
+ }));
250
+ return {
251
+ content: [
252
+ {
253
+ type: 'text',
254
+ text: JSON.stringify({
255
+ results: formatted,
256
+ query,
257
+ total_found: formatted.length,
258
+ }),
259
+ },
260
+ ],
261
+ };
262
+ }
263
+ async getStats() {
264
+ const status = await this.vectorStore.getStatus();
265
+ return {
266
+ content: [
267
+ {
268
+ type: 'text',
269
+ text: JSON.stringify({
270
+ success: true,
271
+ total_chunks: status.chunkCount,
272
+ model: this.config?.embeddings?.path || 'Xenova/all-MiniLM-L6-v2',
273
+ data_dir: getDataDir(this.config),
274
+ config_source: this.config?.source || 'default',
275
+ }),
276
+ },
277
+ ],
278
+ };
279
+ }
280
+ async run() {
281
+ const transport = new StdioServerTransport();
282
+ await this.server.connect(transport);
283
+ console.error('CC-Forever MCP Server running on stdio');
284
+ }
285
+ }
286
+ // ============================================
287
+ // Entry Point
288
+ // ============================================
289
+ async function main() {
290
+ try {
291
+ const server = new CCForeverServer();
292
+ await server.run();
293
+ }
294
+ catch (error) {
295
+ console.error('Failed to start CC-Forever MCP Server:', error);
296
+ process.exit(1);
297
+ }
298
+ }
299
+ main();
300
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * VectorStore implementation with LanceDB
3
+ */
4
+ export interface VectorStoreConfig {
5
+ dbPath: string;
6
+ tableName: string;
7
+ }
8
+ export interface MemoryChunk {
9
+ id: string;
10
+ text: string;
11
+ question: string;
12
+ vector: number[];
13
+ project: string;
14
+ tags: string;
15
+ timestamp: string;
16
+ }
17
+ export interface SearchResult {
18
+ text: string;
19
+ question: string;
20
+ score: number;
21
+ project: string;
22
+ tags: string;
23
+ timestamp: string;
24
+ }
25
+ export declare class VectorStore {
26
+ private db;
27
+ private table;
28
+ private readonly config;
29
+ constructor(config: VectorStoreConfig);
30
+ initialize(): Promise<void>;
31
+ insertChunks(chunks: MemoryChunk[]): Promise<void>;
32
+ search(queryVector: number[], limit?: number): Promise<SearchResult[]>;
33
+ getStatus(): Promise<{
34
+ chunkCount: number;
35
+ }>;
36
+ }
37
+ //# sourceMappingURL=vectorstore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vectorstore.d.ts","sourceRoot":"","sources":["../src/vectorstore.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;CAClB;AAMD,qBAAa,WAAW;IACtB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;gBAE9B,MAAM,EAAE,iBAAiB;IAI/B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB3B,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBlD,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAyBlE,SAAS,IAAI,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAYnD"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * VectorStore implementation with LanceDB
3
+ */
4
+ import { connect } from '@lancedb/lancedb';
5
+ // ============================================
6
+ // VectorStore Class
7
+ // ============================================
8
+ export class VectorStore {
9
+ db = null;
10
+ table = null;
11
+ config;
12
+ constructor(config) {
13
+ this.config = config;
14
+ }
15
+ async initialize() {
16
+ try {
17
+ this.db = await connect(this.config.dbPath);
18
+ const tableNames = await this.db.tableNames();
19
+ if (tableNames.includes(this.config.tableName)) {
20
+ this.table = await this.db.openTable(this.config.tableName);
21
+ console.error(`VectorStore: Opened existing table "${this.config.tableName}"`);
22
+ }
23
+ else {
24
+ console.error(`VectorStore: Table "${this.config.tableName}" will be created on first insertion`);
25
+ }
26
+ }
27
+ catch (error) {
28
+ throw new Error(`Failed to initialize VectorStore: ${error.message}`);
29
+ }
30
+ }
31
+ async insertChunks(chunks) {
32
+ if (chunks.length === 0)
33
+ return;
34
+ try {
35
+ if (!this.table) {
36
+ if (!this.db) {
37
+ throw new Error('VectorStore is not initialized');
38
+ }
39
+ const records = chunks.map((chunk) => chunk);
40
+ this.table = await this.db.createTable(this.config.tableName, records);
41
+ console.error(`VectorStore: Created table "${this.config.tableName}"`);
42
+ }
43
+ else {
44
+ const records = chunks.map((chunk) => chunk);
45
+ await this.table.add(records);
46
+ }
47
+ console.error(`VectorStore: Inserted ${chunks.length} chunks`);
48
+ }
49
+ catch (error) {
50
+ throw new Error(`Failed to insert chunks: ${error.message}`);
51
+ }
52
+ }
53
+ async search(queryVector, limit = 10) {
54
+ if (!this.table) {
55
+ return [];
56
+ }
57
+ try {
58
+ const results = await this.table
59
+ .vectorSearch(queryVector)
60
+ .distanceType('dot')
61
+ .limit(limit)
62
+ .toArray();
63
+ return results.map((r) => ({
64
+ text: r.text,
65
+ question: r.question,
66
+ score: r._distance ?? 0,
67
+ project: r.project,
68
+ tags: r.tags,
69
+ timestamp: r.timestamp,
70
+ }));
71
+ }
72
+ catch (error) {
73
+ throw new Error(`Failed to search: ${error.message}`);
74
+ }
75
+ }
76
+ async getStatus() {
77
+ if (!this.table) {
78
+ return { chunkCount: 0 };
79
+ }
80
+ try {
81
+ const allRecords = await this.table.query().toArray();
82
+ return { chunkCount: allRecords.length };
83
+ }
84
+ catch (error) {
85
+ return { chunkCount: 0 };
86
+ }
87
+ }
88
+ }
89
+ //# sourceMappingURL=vectorstore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vectorstore.js","sourceRoot":"","sources":["../src/vectorstore.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "cc-forever-mcp",
3
+ "version": "1.0.0",
4
+ "description": "CC-Forever MCP Server - Persistent conversation memory with semantic search",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "cc-forever-mcp": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "prepare": "npm run build",
16
+ "start": "node dist/index.js",
17
+ "dev": "tsx src/index.ts"
18
+ },
19
+ "dependencies": {
20
+ "@huggingface/transformers": "^3.7.6",
21
+ "@lancedb/lancedb": "^0.22.2",
22
+ "@modelcontextprotocol/sdk": "^1.25.1"
23
+ },
24
+ "devDependencies": {
25
+ "@types/node": "^20.0.0",
26
+ "tsx": "^4.19.4",
27
+ "typescript": "^5.0.0"
28
+ },
29
+ "engines": {
30
+ "node": ">=20"
31
+ }
32
+ }