@echoes-io/mcp-server 1.1.0 → 1.2.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.
- package/README.md +21 -2
- package/lib/server.d.ts +2 -1
- package/lib/server.js +34 -3
- package/lib/tools/index.d.ts +3 -0
- package/lib/tools/index.js +3 -0
- package/lib/tools/rag-context.d.ts +24 -0
- package/lib/tools/rag-context.js +49 -0
- package/lib/tools/rag-index.d.ts +19 -0
- package/lib/tools/rag-index.js +56 -0
- package/lib/tools/rag-search.d.ts +24 -0
- package/lib/tools/rag-search.js +48 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -38,7 +38,9 @@ Then configure:
|
|
|
38
38
|
"echoes": {
|
|
39
39
|
"command": "echoes-mcp-server",
|
|
40
40
|
"env": {
|
|
41
|
-
"ECHOES_TIMELINE": "your-timeline-name"
|
|
41
|
+
"ECHOES_TIMELINE": "your-timeline-name",
|
|
42
|
+
"ECHOES_RAG_PROVIDER": "e5-small",
|
|
43
|
+
"ECHOES_CHROMA_URL": "./rag_data"
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
}
|
|
@@ -47,6 +49,11 @@ Then configure:
|
|
|
47
49
|
|
|
48
50
|
**Important:** The `ECHOES_TIMELINE` environment variable must be set to specify which timeline to work with. All tools operate on this timeline.
|
|
49
51
|
|
|
52
|
+
**Optional RAG Configuration:**
|
|
53
|
+
- `ECHOES_RAG_PROVIDER`: Embedding provider (`e5-small`, `e5-large`, or `gemini`). Default: `e5-small`
|
|
54
|
+
- `ECHOES_GEMINI_API_KEY`: Required if using `gemini` provider
|
|
55
|
+
- `ECHOES_CHROMA_URL`: ChromaDB storage path. Default: `./rag_data`
|
|
56
|
+
|
|
50
57
|
## Available Tools
|
|
51
58
|
|
|
52
59
|
All tools operate on the timeline specified by the `ECHOES_TIMELINE` environment variable.
|
|
@@ -88,6 +95,19 @@ All tools operate on the timeline specified by the `ECHOES_TIMELINE` environment
|
|
|
88
95
|
- `arc: "arc1", episode: 1`: Statistics for specific episode
|
|
89
96
|
- `pov: "Alice"`: Statistics for specific POV across timeline
|
|
90
97
|
|
|
98
|
+
### RAG (Semantic Search)
|
|
99
|
+
- **`rag-index`** - Index chapters into vector database for semantic search
|
|
100
|
+
- Input: optional: `arc`, `episode` (to index specific content)
|
|
101
|
+
- Output: Number of chapters indexed
|
|
102
|
+
|
|
103
|
+
- **`rag-search`** - Semantic search across timeline content
|
|
104
|
+
- Input: `query`, optional: `arc`, `pov`, `maxResults`
|
|
105
|
+
- Output: Relevant chapters with similarity scores and previews
|
|
106
|
+
|
|
107
|
+
- **`rag-context`** - Retrieve relevant context for AI interactions
|
|
108
|
+
- Input: `query`, optional: `arc`, `pov`, `maxChapters`
|
|
109
|
+
- Output: Full chapter content for AI context
|
|
110
|
+
|
|
91
111
|
## Development
|
|
92
112
|
|
|
93
113
|
### Scripts
|
|
@@ -128,7 +148,6 @@ npm run lint:fix
|
|
|
128
148
|
|
|
129
149
|
### Planned Features
|
|
130
150
|
- **Book generation** - LaTeX/PDF compilation tools for creating publishable books from timeline content
|
|
131
|
-
- **RAG system** - Retrieval-Augmented Generation integration for AI-assisted writing and content analysis
|
|
132
151
|
|
|
133
152
|
## License
|
|
134
153
|
|
package/lib/server.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { RAGSystem } from '@echoes-io/rag';
|
|
1
2
|
import { Tracker } from '@echoes-io/tracker';
|
|
2
3
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
-
export declare function createServer(tracker: Tracker): Server<{
|
|
4
|
+
export declare function createServer(tracker: Tracker, rag: RAGSystem): Server<{
|
|
4
5
|
method: string;
|
|
5
6
|
params?: {
|
|
6
7
|
[x: string]: unknown;
|
package/lib/server.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { RAGSystem } from '@echoes-io/rag';
|
|
4
5
|
import { Tracker } from '@echoes-io/tracker';
|
|
5
6
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
6
7
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
7
8
|
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
8
9
|
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
9
|
-
import { chapterDelete, chapterDeleteSchema, chapterInfo, chapterInfoSchema, chapterInsert, chapterInsertSchema, chapterRefresh, chapterRefreshSchema, episodeInfo, episodeInfoSchema, episodeUpdate, episodeUpdateSchema, stats, statsSchema, timelineSync, timelineSyncSchema, wordsCount, wordsCountSchema, } from './tools/index.js';
|
|
10
|
+
import { chapterDelete, chapterDeleteSchema, chapterInfo, chapterInfoSchema, chapterInsert, chapterInsertSchema, chapterRefresh, chapterRefreshSchema, episodeInfo, episodeInfoSchema, episodeUpdate, episodeUpdateSchema, ragContext, ragContextSchema, ragIndex, ragIndexSchema, ragSearch, ragSearchSchema, stats, statsSchema, timelineSync, timelineSyncSchema, wordsCount, wordsCountSchema, } from './tools/index.js';
|
|
10
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
12
|
const pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
|
|
12
|
-
export function createServer(tracker) {
|
|
13
|
+
export function createServer(tracker, rag) {
|
|
13
14
|
const server = new Server({
|
|
14
15
|
name: pkg.name,
|
|
15
16
|
version: pkg.version,
|
|
@@ -66,6 +67,21 @@ export function createServer(tracker) {
|
|
|
66
67
|
description: 'Get statistics for timeline, arc, episode, or POV',
|
|
67
68
|
inputSchema: zodToJsonSchema(statsSchema),
|
|
68
69
|
},
|
|
70
|
+
{
|
|
71
|
+
name: 'rag-index',
|
|
72
|
+
description: 'Index chapters into RAG vector database for semantic search',
|
|
73
|
+
inputSchema: zodToJsonSchema(ragIndexSchema),
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'rag-search',
|
|
77
|
+
description: 'Semantic search across timeline content',
|
|
78
|
+
inputSchema: zodToJsonSchema(ragSearchSchema),
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'rag-context',
|
|
82
|
+
description: 'Retrieve relevant context for AI interactions',
|
|
83
|
+
inputSchema: zodToJsonSchema(ragContextSchema),
|
|
84
|
+
},
|
|
69
85
|
],
|
|
70
86
|
};
|
|
71
87
|
});
|
|
@@ -90,6 +106,12 @@ export function createServer(tracker) {
|
|
|
90
106
|
return await timelineSync(timelineSyncSchema.parse(args), tracker);
|
|
91
107
|
case 'stats':
|
|
92
108
|
return await stats(statsSchema.parse(args), tracker);
|
|
109
|
+
case 'rag-index':
|
|
110
|
+
return await ragIndex(ragIndexSchema.parse(args), tracker, rag);
|
|
111
|
+
case 'rag-search':
|
|
112
|
+
return await ragSearch(ragSearchSchema.parse(args), rag);
|
|
113
|
+
case 'rag-context':
|
|
114
|
+
return await ragContext(ragContextSchema.parse(args), rag);
|
|
93
115
|
default:
|
|
94
116
|
throw new Error(`Unknown tool: ${name}`);
|
|
95
117
|
}
|
|
@@ -102,7 +124,16 @@ export async function runServer() {
|
|
|
102
124
|
const tracker = new Tracker(dbPath);
|
|
103
125
|
await tracker.init();
|
|
104
126
|
console.error(`Tracker database initialized: ${dbPath}`);
|
|
105
|
-
|
|
127
|
+
// Initialize RAG system
|
|
128
|
+
const chromaUrl = process.env.ECHOES_CHROMA_URL || (process.env.NODE_ENV === 'test' ? ':memory:' : './rag_data');
|
|
129
|
+
const provider = (process.env.ECHOES_RAG_PROVIDER || 'e5-small');
|
|
130
|
+
const rag = new RAGSystem({
|
|
131
|
+
provider,
|
|
132
|
+
chromaUrl,
|
|
133
|
+
geminiApiKey: process.env.ECHOES_GEMINI_API_KEY,
|
|
134
|
+
});
|
|
135
|
+
console.error(`RAG system initialized: ${chromaUrl} (provider: ${provider})`);
|
|
136
|
+
const server = createServer(tracker, rag);
|
|
106
137
|
const transport = new StdioServerTransport();
|
|
107
138
|
await server.connect(transport);
|
|
108
139
|
console.error('Echoes MCP Server running on stdio');
|
package/lib/tools/index.d.ts
CHANGED
|
@@ -4,6 +4,9 @@ export { chapterInsert, chapterInsertSchema } from './chapter-insert.js';
|
|
|
4
4
|
export { chapterRefresh, chapterRefreshSchema } from './chapter-refresh.js';
|
|
5
5
|
export { episodeInfo, episodeInfoSchema } from './episode-info.js';
|
|
6
6
|
export { episodeUpdate, episodeUpdateSchema } from './episode-update.js';
|
|
7
|
+
export { ragContext, ragContextSchema } from './rag-context.js';
|
|
8
|
+
export { ragIndex, ragIndexSchema } from './rag-index.js';
|
|
9
|
+
export { ragSearch, ragSearchSchema } from './rag-search.js';
|
|
7
10
|
export { stats, statsSchema } from './stats.js';
|
|
8
11
|
export { timelineSync, timelineSyncSchema } from './timeline-sync.js';
|
|
9
12
|
export { wordsCount, wordsCountSchema } from './words-count.js';
|
package/lib/tools/index.js
CHANGED
|
@@ -4,6 +4,9 @@ export { chapterInsert, chapterInsertSchema } from './chapter-insert.js';
|
|
|
4
4
|
export { chapterRefresh, chapterRefreshSchema } from './chapter-refresh.js';
|
|
5
5
|
export { episodeInfo, episodeInfoSchema } from './episode-info.js';
|
|
6
6
|
export { episodeUpdate, episodeUpdateSchema } from './episode-update.js';
|
|
7
|
+
export { ragContext, ragContextSchema } from './rag-context.js';
|
|
8
|
+
export { ragIndex, ragIndexSchema } from './rag-index.js';
|
|
9
|
+
export { ragSearch, ragSearchSchema } from './rag-search.js';
|
|
7
10
|
export { stats, statsSchema } from './stats.js';
|
|
8
11
|
export { timelineSync, timelineSyncSchema } from './timeline-sync.js';
|
|
9
12
|
export { wordsCount, wordsCountSchema } from './words-count.js';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RAGSystem } from '@echoes-io/rag';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare const ragContextSchema: z.ZodObject<{
|
|
4
|
+
query: z.ZodString;
|
|
5
|
+
arc: z.ZodOptional<z.ZodString>;
|
|
6
|
+
pov: z.ZodOptional<z.ZodString>;
|
|
7
|
+
maxChapters: z.ZodOptional<z.ZodNumber>;
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
query: string;
|
|
10
|
+
arc?: string | undefined;
|
|
11
|
+
pov?: string | undefined;
|
|
12
|
+
maxChapters?: number | undefined;
|
|
13
|
+
}, {
|
|
14
|
+
query: string;
|
|
15
|
+
arc?: string | undefined;
|
|
16
|
+
pov?: string | undefined;
|
|
17
|
+
maxChapters?: number | undefined;
|
|
18
|
+
}>;
|
|
19
|
+
export declare function ragContext(args: z.infer<typeof ragContextSchema>, rag: RAGSystem): Promise<{
|
|
20
|
+
content: {
|
|
21
|
+
type: "text";
|
|
22
|
+
text: string;
|
|
23
|
+
}[];
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { getTimeline } from '../utils.js';
|
|
3
|
+
export const ragContextSchema = z.object({
|
|
4
|
+
query: z.string().describe('Context query'),
|
|
5
|
+
arc: z.string().optional().describe('Filter by arc name'),
|
|
6
|
+
pov: z.string().optional().describe('Filter by POV character'),
|
|
7
|
+
maxChapters: z.number().optional().describe('Maximum number of chapters (default: 5)'),
|
|
8
|
+
});
|
|
9
|
+
export async function ragContext(args, rag) {
|
|
10
|
+
try {
|
|
11
|
+
const timeline = getTimeline();
|
|
12
|
+
const results = await rag.getContext({
|
|
13
|
+
query: args.query,
|
|
14
|
+
timeline,
|
|
15
|
+
arc: args.arc,
|
|
16
|
+
pov: args.pov,
|
|
17
|
+
maxChapters: args.maxChapters,
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
content: [
|
|
21
|
+
{
|
|
22
|
+
type: 'text',
|
|
23
|
+
text: JSON.stringify({
|
|
24
|
+
query: args.query,
|
|
25
|
+
timeline,
|
|
26
|
+
filters: {
|
|
27
|
+
arc: args.arc || null,
|
|
28
|
+
pov: args.pov || null,
|
|
29
|
+
},
|
|
30
|
+
context: results.map((r) => ({
|
|
31
|
+
chapter: {
|
|
32
|
+
arc: r.metadata.arcName,
|
|
33
|
+
episode: r.metadata.episodeNumber,
|
|
34
|
+
chapter: r.metadata.number,
|
|
35
|
+
pov: r.metadata.pov,
|
|
36
|
+
title: r.metadata.title,
|
|
37
|
+
},
|
|
38
|
+
similarity: r.similarity,
|
|
39
|
+
content: r.content,
|
|
40
|
+
})),
|
|
41
|
+
}, null, 2),
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
throw new Error(`Failed to get context: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { RAGSystem } from '@echoes-io/rag';
|
|
2
|
+
import type { Tracker } from '@echoes-io/tracker';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
export declare const ragIndexSchema: z.ZodObject<{
|
|
5
|
+
arc: z.ZodOptional<z.ZodString>;
|
|
6
|
+
episode: z.ZodOptional<z.ZodNumber>;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
arc?: string | undefined;
|
|
9
|
+
episode?: number | undefined;
|
|
10
|
+
}, {
|
|
11
|
+
arc?: string | undefined;
|
|
12
|
+
episode?: number | undefined;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function ragIndex(args: z.infer<typeof ragIndexSchema>, tracker: Tracker, rag: RAGSystem): Promise<{
|
|
15
|
+
content: {
|
|
16
|
+
type: "text";
|
|
17
|
+
text: string;
|
|
18
|
+
}[];
|
|
19
|
+
}>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { getTimeline } from '../utils.js';
|
|
3
|
+
export const ragIndexSchema = z.object({
|
|
4
|
+
arc: z.string().optional().describe('Index specific arc only'),
|
|
5
|
+
episode: z.number().optional().describe('Index specific episode only (requires arc)'),
|
|
6
|
+
});
|
|
7
|
+
export async function ragIndex(args, tracker, rag) {
|
|
8
|
+
try {
|
|
9
|
+
const timeline = getTimeline();
|
|
10
|
+
let chapters = [];
|
|
11
|
+
// Get chapters based on filters
|
|
12
|
+
if (args.arc && args.episode) {
|
|
13
|
+
chapters = await tracker.getChapters(timeline, args.arc, args.episode);
|
|
14
|
+
}
|
|
15
|
+
else if (args.arc) {
|
|
16
|
+
const episodes = await tracker.getEpisodes(timeline, args.arc);
|
|
17
|
+
for (const ep of episodes) {
|
|
18
|
+
const epChapters = await tracker.getChapters(timeline, args.arc, ep.number);
|
|
19
|
+
chapters.push(...epChapters);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const arcs = await tracker.getArcs(timeline);
|
|
24
|
+
for (const arc of arcs) {
|
|
25
|
+
const episodes = await tracker.getEpisodes(timeline, arc.name);
|
|
26
|
+
for (const ep of episodes) {
|
|
27
|
+
const epChapters = await tracker.getChapters(timeline, arc.name, ep.number);
|
|
28
|
+
chapters.push(...epChapters);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Convert to embedding format and add to RAG
|
|
33
|
+
const embeddingChapters = chapters.map((ch) => ({
|
|
34
|
+
id: `${ch.timelineName}-${ch.arcName}-${ch.episodeNumber}-${ch.number}`,
|
|
35
|
+
metadata: ch,
|
|
36
|
+
content: '', // Content will be loaded by RAG system if needed
|
|
37
|
+
}));
|
|
38
|
+
await rag.addChapters(embeddingChapters);
|
|
39
|
+
return {
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: 'text',
|
|
43
|
+
text: JSON.stringify({
|
|
44
|
+
indexed: embeddingChapters.length,
|
|
45
|
+
timeline,
|
|
46
|
+
arc: args.arc || 'all',
|
|
47
|
+
episode: args.episode || 'all',
|
|
48
|
+
}, null, 2),
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new Error(`Failed to index chapters: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RAGSystem } from '@echoes-io/rag';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare const ragSearchSchema: z.ZodObject<{
|
|
4
|
+
query: z.ZodString;
|
|
5
|
+
arc: z.ZodOptional<z.ZodString>;
|
|
6
|
+
pov: z.ZodOptional<z.ZodString>;
|
|
7
|
+
maxResults: z.ZodOptional<z.ZodNumber>;
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
query: string;
|
|
10
|
+
arc?: string | undefined;
|
|
11
|
+
pov?: string | undefined;
|
|
12
|
+
maxResults?: number | undefined;
|
|
13
|
+
}, {
|
|
14
|
+
query: string;
|
|
15
|
+
arc?: string | undefined;
|
|
16
|
+
pov?: string | undefined;
|
|
17
|
+
maxResults?: number | undefined;
|
|
18
|
+
}>;
|
|
19
|
+
export declare function ragSearch(args: z.infer<typeof ragSearchSchema>, rag: RAGSystem): Promise<{
|
|
20
|
+
content: {
|
|
21
|
+
type: "text";
|
|
22
|
+
text: string;
|
|
23
|
+
}[];
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { getTimeline } from '../utils.js';
|
|
3
|
+
export const ragSearchSchema = z.object({
|
|
4
|
+
query: z.string().describe('Search query'),
|
|
5
|
+
arc: z.string().optional().describe('Filter by arc name'),
|
|
6
|
+
pov: z.string().optional().describe('Filter by POV character'),
|
|
7
|
+
maxResults: z.number().optional().describe('Maximum number of results (default: 10)'),
|
|
8
|
+
});
|
|
9
|
+
export async function ragSearch(args, rag) {
|
|
10
|
+
try {
|
|
11
|
+
const timeline = getTimeline();
|
|
12
|
+
const results = await rag.search(args.query, {
|
|
13
|
+
timeline,
|
|
14
|
+
arc: args.arc,
|
|
15
|
+
pov: args.pov,
|
|
16
|
+
maxResults: args.maxResults,
|
|
17
|
+
});
|
|
18
|
+
return {
|
|
19
|
+
content: [
|
|
20
|
+
{
|
|
21
|
+
type: 'text',
|
|
22
|
+
text: JSON.stringify({
|
|
23
|
+
query: args.query,
|
|
24
|
+
timeline,
|
|
25
|
+
filters: {
|
|
26
|
+
arc: args.arc || null,
|
|
27
|
+
pov: args.pov || null,
|
|
28
|
+
},
|
|
29
|
+
results: results.map((r) => ({
|
|
30
|
+
chapter: {
|
|
31
|
+
arc: r.metadata.arcName,
|
|
32
|
+
episode: r.metadata.episodeNumber,
|
|
33
|
+
chapter: r.metadata.number,
|
|
34
|
+
pov: r.metadata.pov,
|
|
35
|
+
title: r.metadata.title,
|
|
36
|
+
},
|
|
37
|
+
similarity: r.similarity,
|
|
38
|
+
preview: r.content.substring(0, 200) + '...',
|
|
39
|
+
})),
|
|
40
|
+
}, null, 2),
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
throw new Error(`Failed to search: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@echoes-io/mcp-server",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"description": "Model Context Protocol server for AI integration with Echoes storytelling platform",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"dev": "tsx cli/index.ts",
|
|
@@ -81,9 +81,10 @@
|
|
|
81
81
|
"vitest": "^3.2.4"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@echoes-io/utils": "^1.1.1",
|
|
85
84
|
"@echoes-io/models": "^1.0.0",
|
|
85
|
+
"@echoes-io/rag": "^1.0.0",
|
|
86
86
|
"@echoes-io/tracker": "^1.0.0",
|
|
87
|
+
"@echoes-io/utils": "^1.1.1",
|
|
87
88
|
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
88
89
|
}
|
|
89
90
|
}
|