@echoes-io/mcp-server 4.1.0 → 4.1.1
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.
- package/cli/index.d.ts +2 -0
- package/cli/index.js +186 -0
- package/package.json +2 -1
- package/src/database/index.d.ts +6 -0
- package/src/database/index.js +26 -0
- package/src/database/relations.d.ts +744 -0
- package/src/database/relations.js +52 -0
- package/src/database/schema.d.ts +733 -0
- package/src/database/schema.js +69 -0
- package/src/database/vector.d.ts +25 -0
- package/src/database/vector.js +98 -0
- package/src/index.d.ts +5 -0
- package/src/index.js +5 -0
- package/src/rag/character-ner.d.ts +36 -0
- package/src/rag/character-ner.js +416 -0
- package/src/rag/database-sync.d.ts +38 -0
- package/src/rag/database-sync.js +158 -0
- package/src/rag/embeddings.d.ts +74 -0
- package/src/rag/embeddings.js +164 -0
- package/src/rag/graph-rag.d.ts +69 -0
- package/src/rag/graph-rag.js +311 -0
- package/src/rag/hybrid-rag.d.ts +109 -0
- package/src/rag/hybrid-rag.js +255 -0
- package/src/rag/index.d.ts +16 -0
- package/src/rag/index.js +33 -0
- package/src/server.d.ts +43 -0
- package/src/server.js +177 -0
- package/src/tools/index-rag.d.ts +19 -0
- package/src/tools/index-rag.js +85 -0
- package/src/tools/index-tracker.d.ts +17 -0
- package/src/tools/index-tracker.js +89 -0
- package/src/tools/index.d.ts +5 -0
- package/src/tools/index.js +5 -0
- package/src/tools/rag-context.d.ts +34 -0
- package/src/tools/rag-context.js +51 -0
- package/src/tools/rag-search.d.ts +35 -0
- package/src/tools/rag-search.js +60 -0
- package/src/tools/words-count.d.ts +15 -0
- package/src/tools/words-count.js +28 -0
- package/src/types/frontmatter.d.ts +35 -0
- package/src/types/frontmatter.js +1 -0
- package/src/utils/index.d.ts +1 -0
- package/src/utils/index.js +1 -0
- package/src/utils/markdown.d.ts +6 -0
- package/src/utils/markdown.js +36 -0
- package/src/utils/timeline-detection.d.ts +13 -0
- package/src/utils/timeline-detection.js +76 -0
package/cli/index.d.ts
ADDED
package/cli/index.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { runServer } from '../src/server.js';
|
|
3
|
+
import { indexRag } from '../src/tools/index-rag.js';
|
|
4
|
+
import { indexTracker } from '../src/tools/index-tracker.js';
|
|
5
|
+
import { ragContext } from '../src/tools/rag-context.js';
|
|
6
|
+
import { ragSearch } from '../src/tools/rag-search.js';
|
|
7
|
+
import { wordsCount } from '../src/tools/words-count.js';
|
|
8
|
+
import { getTimelineContext } from '../src/utils/timeline-detection.js';
|
|
9
|
+
const [, , command, ...args] = process.argv;
|
|
10
|
+
async function main() {
|
|
11
|
+
if (!command) {
|
|
12
|
+
// No command = run MCP server
|
|
13
|
+
await runServer();
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
// CLI commands
|
|
17
|
+
switch (command) {
|
|
18
|
+
case 'words-count': {
|
|
19
|
+
const filePath = args[0];
|
|
20
|
+
const detailed = args.includes('--detailed');
|
|
21
|
+
if (!filePath) {
|
|
22
|
+
console.error('Usage: echoes-mcp-server words-count <file> [--detailed]');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const result = await wordsCount({ filePath, detailed });
|
|
27
|
+
console.log(JSON.stringify(result, null, 2));
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
case 'index-tracker': {
|
|
36
|
+
const timelineArg = args[0];
|
|
37
|
+
const contentPathArg = args[1];
|
|
38
|
+
try {
|
|
39
|
+
const { timeline, contentPath } = getTimelineContext(timelineArg, contentPathArg);
|
|
40
|
+
const result = await indexTracker({ timeline, contentPath });
|
|
41
|
+
console.log(JSON.stringify(result, null, 2));
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
case 'index-rag': {
|
|
50
|
+
const timelineArg = args[0];
|
|
51
|
+
const contentPathArg = args[1];
|
|
52
|
+
const arcFlag = args.indexOf('--arc');
|
|
53
|
+
const episodeFlag = args.indexOf('--episode');
|
|
54
|
+
try {
|
|
55
|
+
const { timeline, contentPath } = getTimelineContext(timelineArg, contentPathArg);
|
|
56
|
+
const arc = arcFlag !== -1 ? args[arcFlag + 1] : undefined;
|
|
57
|
+
const episode = episodeFlag !== -1 ? parseInt(args[episodeFlag + 1], 10) : undefined;
|
|
58
|
+
const result = await indexRag({ timeline, contentPath, arc, episode });
|
|
59
|
+
console.log(JSON.stringify(result, null, 2));
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case 'rag-search': {
|
|
68
|
+
const timelineArg = args[0];
|
|
69
|
+
const query = args[1] || args[0]; // If no timeline provided, first arg is query
|
|
70
|
+
try {
|
|
71
|
+
const { timeline } = getTimelineContext(timelineArg && args[1] ? timelineArg : undefined);
|
|
72
|
+
const actualQuery = args[1] ? query : timelineArg; // Adjust query based on args
|
|
73
|
+
if (!actualQuery) {
|
|
74
|
+
console.error('Usage: echoes-mcp-server rag-search "<query>" [options]');
|
|
75
|
+
console.error(' or: echoes-mcp-server rag-search <timeline> "<query>" [options]');
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
// Parse optional flags
|
|
79
|
+
const topKFlag = args.indexOf('--top-k');
|
|
80
|
+
const charactersFlag = args.indexOf('--characters');
|
|
81
|
+
const arcFlag = args.indexOf('--arc');
|
|
82
|
+
const povFlag = args.indexOf('--pov');
|
|
83
|
+
const allCharacters = args.includes('--all-characters');
|
|
84
|
+
const vectorOnly = args.includes('--vector-only');
|
|
85
|
+
const topK = topKFlag !== -1 ? parseInt(args[topKFlag + 1], 10) : 10;
|
|
86
|
+
const characters = charactersFlag !== -1 ? args[charactersFlag + 1].split(',') : undefined;
|
|
87
|
+
const arc = arcFlag !== -1 ? args[arcFlag + 1] : undefined;
|
|
88
|
+
const pov = povFlag !== -1 ? args[povFlag + 1] : undefined;
|
|
89
|
+
const result = await ragSearch({
|
|
90
|
+
timeline,
|
|
91
|
+
query: actualQuery,
|
|
92
|
+
topK,
|
|
93
|
+
characters,
|
|
94
|
+
allCharacters,
|
|
95
|
+
arc,
|
|
96
|
+
pov,
|
|
97
|
+
useGraphRAG: !vectorOnly,
|
|
98
|
+
});
|
|
99
|
+
console.log(JSON.stringify(result, null, 2));
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
case 'rag-context': {
|
|
108
|
+
const timelineArg = args[0];
|
|
109
|
+
const query = args[1] || args[0]; // If no timeline provided, first arg is query
|
|
110
|
+
try {
|
|
111
|
+
const { timeline } = getTimelineContext(timelineArg && args[1] ? timelineArg : undefined);
|
|
112
|
+
const actualQuery = args[1] ? query : timelineArg; // Adjust query based on args
|
|
113
|
+
if (!actualQuery) {
|
|
114
|
+
console.error('Usage: echoes-mcp-server rag-context "<query>" [options]');
|
|
115
|
+
console.error(' or: echoes-mcp-server rag-context <timeline> "<query>" [options]');
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
// Parse optional flags
|
|
119
|
+
const maxChaptersFlag = args.indexOf('--max-chapters');
|
|
120
|
+
const charactersFlag = args.indexOf('--characters');
|
|
121
|
+
const arcFlag = args.indexOf('--arc');
|
|
122
|
+
const povFlag = args.indexOf('--pov');
|
|
123
|
+
const allCharacters = args.includes('--all-characters');
|
|
124
|
+
const maxChapters = maxChaptersFlag !== -1 ? parseInt(args[maxChaptersFlag + 1], 10) : 5;
|
|
125
|
+
const characters = charactersFlag !== -1 ? args[charactersFlag + 1].split(',') : undefined;
|
|
126
|
+
const arc = arcFlag !== -1 ? args[arcFlag + 1] : undefined;
|
|
127
|
+
const pov = povFlag !== -1 ? args[povFlag + 1] : undefined;
|
|
128
|
+
const result = await ragContext({
|
|
129
|
+
timeline,
|
|
130
|
+
query: actualQuery,
|
|
131
|
+
maxChapters,
|
|
132
|
+
characters,
|
|
133
|
+
allCharacters,
|
|
134
|
+
arc,
|
|
135
|
+
pov,
|
|
136
|
+
});
|
|
137
|
+
console.log(JSON.stringify(result, null, 2));
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case 'help':
|
|
146
|
+
console.log(`
|
|
147
|
+
Echoes MCP Server v3.0.0
|
|
148
|
+
|
|
149
|
+
Usage:
|
|
150
|
+
echoes-mcp-server # Run MCP server
|
|
151
|
+
echoes-mcp-server words-count <file> # Count words in file
|
|
152
|
+
echoes-mcp-server index-tracker [timeline] [path] # Sync filesystem to database (auto-detects from cwd)
|
|
153
|
+
echoes-mcp-server index-rag [timeline] [path] # Index chapters into GraphRAG (auto-detects from cwd)
|
|
154
|
+
echoes-mcp-server rag-search "<query>" # Search chapters semantically (auto-detects timeline)
|
|
155
|
+
echoes-mcp-server rag-context "<query>" # Get full chapter context for AI (auto-detects timeline)
|
|
156
|
+
echoes-mcp-server help # Show this help
|
|
157
|
+
|
|
158
|
+
Auto-Detection:
|
|
159
|
+
Run from timeline-* directory: auto-detects timeline and content path
|
|
160
|
+
Run from .github directory: multi-timeline mode (requires explicit timeline)
|
|
161
|
+
Run from mcp-server directory: test mode
|
|
162
|
+
|
|
163
|
+
Examples:
|
|
164
|
+
cd timeline-pulse && echoes-mcp-server index-tracker # Auto-detects "pulse" timeline
|
|
165
|
+
cd timeline-pulse && echoes-mcp-server rag-search "romantic scene"
|
|
166
|
+
echoes-mcp-server rag-search pulse "romantic scene" # Explicit timeline
|
|
167
|
+
|
|
168
|
+
Options:
|
|
169
|
+
--detailed # Include detailed statistics (words-count)
|
|
170
|
+
--arc <name> # Filter by arc (index-rag, rag-search, rag-context)
|
|
171
|
+
--episode <num> # Filter by episode (index-rag)
|
|
172
|
+
--top-k <num> # Max results (rag-search, default: 10)
|
|
173
|
+
--max-chapters <num> # Max chapters (rag-context, default: 5)
|
|
174
|
+
--characters <name1,name2> # Filter by characters (rag-search, rag-context)
|
|
175
|
+
--all-characters # Require all characters (rag-search, rag-context)
|
|
176
|
+
--pov <name> # Filter by POV (rag-search, rag-context)
|
|
177
|
+
--vector-only # Use vector search only (rag-search)
|
|
178
|
+
`);
|
|
179
|
+
break;
|
|
180
|
+
default:
|
|
181
|
+
console.error(`Unknown command: ${command}`);
|
|
182
|
+
console.error('Run "echoes-mcp-server help" for usage information');
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
main().catch(console.error);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@echoes-io/mcp-server",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.1.
|
|
4
|
+
"version": "4.1.1",
|
|
5
5
|
"description": "Model Context Protocol server for AI integration with Echoes storytelling platform",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"dev": "tsx cli/index.ts",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"clean": "rimraf --glob ./{cli,src,test}/**/*.{d.ts,js} ./{drizzle,vitest}*.{d.ts,js}",
|
|
25
25
|
"prebuild": "npm run clean",
|
|
26
26
|
"build": "tsc",
|
|
27
|
+
"prerelease": "npm run build",
|
|
27
28
|
"release": "semantic-release"
|
|
28
29
|
},
|
|
29
30
|
"bin": {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
|
2
|
+
import * as schema from './schema.js';
|
|
3
|
+
export type DatabaseType = ReturnType<typeof drizzle<typeof schema>>;
|
|
4
|
+
export declare function initDatabase(dbPath: string): Promise<DatabaseType>;
|
|
5
|
+
export { relations } from './relations.js';
|
|
6
|
+
export * from './schema.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
|
3
|
+
import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
|
|
4
|
+
import * as sqliteVec from 'sqlite-vec';
|
|
5
|
+
import { relations } from './relations.js';
|
|
6
|
+
import * as schema from './schema.js';
|
|
7
|
+
export async function initDatabase(dbPath) {
|
|
8
|
+
const client = new Database(dbPath);
|
|
9
|
+
// Enable WAL mode for better concurrency
|
|
10
|
+
client.pragma('journal_mode = WAL');
|
|
11
|
+
// Load sqlite-vec extension
|
|
12
|
+
sqliteVec.load(client);
|
|
13
|
+
const db = drizzle({ client, relations, schema });
|
|
14
|
+
// Auto-migrate on startup
|
|
15
|
+
try {
|
|
16
|
+
await migrate(db, { migrationsFolder: './db' });
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
console.error('❌ Database migration failed:', error);
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
return db;
|
|
23
|
+
}
|
|
24
|
+
export { relations } from './relations.js';
|
|
25
|
+
// Re-export all schema
|
|
26
|
+
export * from './schema.js';
|