@echoes-io/mcp-server 2.2.0 → 4.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.
- package/README.md +2 -2
- package/package.json +23 -12
- package/cli/index.d.ts +0 -2
- package/cli/index.js +0 -6
- package/lib/prompts/handlers.d.ts +0 -21
- package/lib/prompts/handlers.js +0 -107
- package/lib/prompts/index.d.ts +0 -2
- package/lib/prompts/index.js +0 -2
- package/lib/prompts/substitution.d.ts +0 -2
- package/lib/prompts/substitution.js +0 -45
- package/lib/prompts/validation.d.ts +0 -8
- package/lib/prompts/validation.js +0 -20
- package/lib/server.d.ts +0 -55
- package/lib/server.js +0 -305
- package/lib/tools/book-generate.d.ts +0 -20
- package/lib/tools/book-generate.js +0 -36
- package/lib/tools/chapter-delete.d.ts +0 -15
- package/lib/tools/chapter-delete.js +0 -48
- package/lib/tools/chapter-info.d.ts +0 -14
- package/lib/tools/chapter-info.js +0 -47
- package/lib/tools/chapter-insert.d.ts +0 -21
- package/lib/tools/chapter-insert.js +0 -104
- package/lib/tools/chapter-refresh.d.ts +0 -12
- package/lib/tools/chapter-refresh.js +0 -78
- package/lib/tools/episode-info.d.ts +0 -13
- package/lib/tools/episode-info.js +0 -45
- package/lib/tools/episode-update.d.ts +0 -16
- package/lib/tools/episode-update.js +0 -42
- package/lib/tools/index.d.ts +0 -14
- package/lib/tools/index.js +0 -14
- package/lib/tools/rag-characters.d.ts +0 -12
- package/lib/tools/rag-characters.js +0 -26
- package/lib/tools/rag-context.d.ts +0 -16
- package/lib/tools/rag-context.js +0 -54
- package/lib/tools/rag-index.d.ts +0 -18
- package/lib/tools/rag-index.js +0 -89
- package/lib/tools/rag-search.d.ts +0 -17
- package/lib/tools/rag-search.js +0 -58
- package/lib/tools/stats.d.ts +0 -14
- package/lib/tools/stats.js +0 -132
- package/lib/tools/timeline-sync.d.ts +0 -15
- package/lib/tools/timeline-sync.js +0 -217
- package/lib/tools/words-count.d.ts +0 -10
- package/lib/tools/words-count.js +0 -30
- package/lib/utils.d.ts +0 -1
- package/lib/utils.js +0 -2
package/README.md
CHANGED
|
@@ -229,8 +229,8 @@ npm run lint:format
|
|
|
229
229
|
### Tech Stack
|
|
230
230
|
|
|
231
231
|
- **Language**: TypeScript (strict mode)
|
|
232
|
-
- **Testing**: Vitest (
|
|
233
|
-
- **Linting**: Biome
|
|
232
|
+
- **Testing**: Vitest (90.71% coverage, 82 tests)
|
|
233
|
+
- **Linting**: Biome (0 warnings)
|
|
234
234
|
- **Build**: TypeScript compiler
|
|
235
235
|
|
|
236
236
|
### Architecture
|
package/package.json
CHANGED
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@echoes-io/mcp-server",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.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",
|
|
8
|
-
"
|
|
8
|
+
"db:generate": "drizzle-kit generate",
|
|
9
|
+
"db:migrate": "drizzle-kit migrate",
|
|
10
|
+
"db:studio": "drizzle-kit studio",
|
|
11
|
+
"prelint": "npm run build",
|
|
9
12
|
"lint": "concurrently npm:lint:* --prefixColors auto",
|
|
13
|
+
"postlint": "npm run clean",
|
|
10
14
|
"lint:format": "biome check --write",
|
|
11
15
|
"lint:lockfile": "lockfile-lint --path package-lock.json",
|
|
12
16
|
"lint:engines": "ls-engines",
|
|
13
17
|
"lint:publish": "publint --strict",
|
|
18
|
+
"pretest": "npm run clean",
|
|
14
19
|
"test": "vitest run",
|
|
20
|
+
"pretest:coverage": "npm run clean",
|
|
15
21
|
"test:coverage": "vitest run --coverage",
|
|
16
|
-
"check": "npm run
|
|
22
|
+
"check": "npm run test:coverage && npm run lint",
|
|
17
23
|
"prepare": "[ \"$CI\" = \"true\" ] || [ \"$GITHUB_ACTIONS\" = \"true\" ] && echo 'Skipping husky' && exit 0 || husky",
|
|
18
|
-
"clean": "rimraf --glob ./{cli,
|
|
24
|
+
"clean": "rimraf --glob ./{cli,src,test}/**/*.{d.ts,js} ./{drizzle,vitest}*.{d.ts,js}",
|
|
19
25
|
"prebuild": "npm run clean",
|
|
20
26
|
"build": "tsc",
|
|
21
27
|
"release": "semantic-release"
|
|
@@ -24,11 +30,12 @@
|
|
|
24
30
|
"echoes-mcp-server": "./cli/index.js"
|
|
25
31
|
},
|
|
26
32
|
"exports": {
|
|
27
|
-
".": "./
|
|
33
|
+
".": "./src/database/index.js"
|
|
28
34
|
},
|
|
29
35
|
"files": [
|
|
30
36
|
"cli/**/*.{d.ts,js}",
|
|
31
|
-
"lib/**/*.{d.ts,js}"
|
|
37
|
+
"lib/**/*.{d.ts,js}",
|
|
38
|
+
"src/**/*.{d.ts,js}"
|
|
32
39
|
],
|
|
33
40
|
"engines": {
|
|
34
41
|
"node": ">= 20.3"
|
|
@@ -67,9 +74,12 @@
|
|
|
67
74
|
"@semantic-release/changelog": "^6.0.3",
|
|
68
75
|
"@semantic-release/git": "^10.0.1",
|
|
69
76
|
"@tsconfig/node22": "^22.0.5",
|
|
77
|
+
"@types/better-sqlite3": "^7.6.11",
|
|
70
78
|
"@types/node": "^24.10.1",
|
|
71
79
|
"@vitest/coverage-v8": "^4.0.15",
|
|
72
80
|
"concurrently": "^9.2.1",
|
|
81
|
+
"drizzle-kit": "^1.0.0-beta.3-36e9b9e",
|
|
82
|
+
"fast-check": "^4.4.0",
|
|
73
83
|
"husky": "^9.1.7",
|
|
74
84
|
"lint-staged": "^16.2.7",
|
|
75
85
|
"lockfile-lint": "^4.14.1",
|
|
@@ -82,11 +92,12 @@
|
|
|
82
92
|
"vitest": "^4.0.15"
|
|
83
93
|
},
|
|
84
94
|
"dependencies": {
|
|
85
|
-
"@
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
95
|
+
"@modelcontextprotocol/sdk": "^1.24.2",
|
|
96
|
+
"better-sqlite3": "^11.0.0",
|
|
97
|
+
"drizzle-orm": "^1.0.0-beta.3-36e9b9e",
|
|
98
|
+
"gray-matter": "^4.0.3",
|
|
99
|
+
"remove-markdown": "^0.6.2",
|
|
100
|
+
"sqlite-vec": "^0.1.7-alpha.2",
|
|
101
|
+
"zod": "^4.1.12"
|
|
91
102
|
}
|
|
92
103
|
}
|
package/cli/index.d.ts
DELETED
package/cli/index.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { Tracker } from '@echoes-io/tracker';
|
|
2
|
-
export declare function listPrompts(): {
|
|
3
|
-
prompts: {
|
|
4
|
-
name: string;
|
|
5
|
-
description: string;
|
|
6
|
-
arguments: {
|
|
7
|
-
name: string;
|
|
8
|
-
description: string;
|
|
9
|
-
required: boolean;
|
|
10
|
-
}[];
|
|
11
|
-
}[];
|
|
12
|
-
};
|
|
13
|
-
export declare function getPrompt(name: string, args: Record<string, string>, timeline: string, tracker: Tracker): Promise<{
|
|
14
|
-
messages: {
|
|
15
|
-
role: "user";
|
|
16
|
-
content: {
|
|
17
|
-
type: "text";
|
|
18
|
-
text: string;
|
|
19
|
-
};
|
|
20
|
-
}[];
|
|
21
|
-
}>;
|
package/lib/prompts/handlers.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { readFile } from 'node:fs/promises';
|
|
3
|
-
import { join, resolve } from 'node:path';
|
|
4
|
-
import { substitutePlaceholders } from './substitution.js';
|
|
5
|
-
import { validateGitHubRepo } from './validation.js';
|
|
6
|
-
const PROMPTS = [
|
|
7
|
-
{
|
|
8
|
-
name: 'new-chapter',
|
|
9
|
-
description: 'Create a new chapter for a timeline arc',
|
|
10
|
-
arguments: [
|
|
11
|
-
{ name: 'arc', description: 'Arc name (e.g., "work", "anima")', required: true },
|
|
12
|
-
{ name: 'chapter', description: 'Chapter number (e.g., "1", "12")', required: true },
|
|
13
|
-
],
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
name: 'revise-chapter',
|
|
17
|
-
description: 'Revise an existing chapter with specific improvements',
|
|
18
|
-
arguments: [
|
|
19
|
-
{ name: 'arc', description: 'Arc name', required: true },
|
|
20
|
-
{ name: 'chapter', description: 'Chapter number', required: true },
|
|
21
|
-
],
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
name: 'expand-chapter',
|
|
25
|
-
description: 'Expand a chapter to reach target word count',
|
|
26
|
-
arguments: [
|
|
27
|
-
{ name: 'arc', description: 'Arc name', required: true },
|
|
28
|
-
{ name: 'chapter', description: 'Chapter number', required: true },
|
|
29
|
-
{ name: 'target', description: 'Target word count (e.g., "4000")', required: true },
|
|
30
|
-
],
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
name: 'new-character',
|
|
34
|
-
description: 'Create a new character sheet',
|
|
35
|
-
arguments: [{ name: 'name', description: 'Character name', required: true }],
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
name: 'new-episode',
|
|
39
|
-
description: 'Create a new episode outline',
|
|
40
|
-
arguments: [
|
|
41
|
-
{ name: 'arc', description: 'Arc name', required: true },
|
|
42
|
-
{ name: 'episode', description: 'Episode number', required: true },
|
|
43
|
-
],
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
name: 'new-arc',
|
|
47
|
-
description: 'Create a new story arc',
|
|
48
|
-
arguments: [{ name: 'name', description: 'Arc name (lowercase, no spaces)', required: true }],
|
|
49
|
-
},
|
|
50
|
-
];
|
|
51
|
-
export function listPrompts() {
|
|
52
|
-
return { prompts: PROMPTS };
|
|
53
|
-
}
|
|
54
|
-
export async function getPrompt(name, args, timeline, tracker) {
|
|
55
|
-
try {
|
|
56
|
-
// Validate .github repo exists
|
|
57
|
-
const { exists: githubExists, path: githubPath } = validateGitHubRepo();
|
|
58
|
-
if (!githubExists) {
|
|
59
|
-
throw new Error('.github repository not found.\n' +
|
|
60
|
-
'Clone it as sibling: git clone https://github.com/echoes-io/.github ../.github');
|
|
61
|
-
}
|
|
62
|
-
// Read base template (required)
|
|
63
|
-
const basePath = join(githubPath, `${name}.md`);
|
|
64
|
-
if (!existsSync(basePath)) {
|
|
65
|
-
throw new Error(`Prompt template not found: ${name}.md\n` +
|
|
66
|
-
`Expected location: ../.github/.kiro/prompts/${name}.md`);
|
|
67
|
-
}
|
|
68
|
-
const basePrompt = await readFile(basePath, 'utf-8');
|
|
69
|
-
// Check for timeline override (optional)
|
|
70
|
-
const timelinePromptsPath = resolve(process.cwd(), '.kiro/prompts');
|
|
71
|
-
const overridePath = join(timelinePromptsPath, `${name}.md`);
|
|
72
|
-
let overridePrompt = '';
|
|
73
|
-
if (existsSync(overridePath)) {
|
|
74
|
-
overridePrompt = await readFile(overridePath, 'utf-8');
|
|
75
|
-
}
|
|
76
|
-
// Concatenate (base first, then override)
|
|
77
|
-
const combinedPrompt = overridePrompt
|
|
78
|
-
? `${basePrompt}\n\n---\n\n${overridePrompt}`
|
|
79
|
-
: basePrompt;
|
|
80
|
-
// Substitute placeholders
|
|
81
|
-
const finalPrompt = await substitutePlaceholders(name, combinedPrompt, args, timeline, tracker);
|
|
82
|
-
return {
|
|
83
|
-
messages: [
|
|
84
|
-
{
|
|
85
|
-
role: 'user',
|
|
86
|
-
content: {
|
|
87
|
-
type: 'text',
|
|
88
|
-
text: finalPrompt,
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
],
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
catch (error) {
|
|
95
|
-
return {
|
|
96
|
-
messages: [
|
|
97
|
-
{
|
|
98
|
-
role: 'user',
|
|
99
|
-
content: {
|
|
100
|
-
type: 'text',
|
|
101
|
-
text: `❌ Error loading prompt "${name}":\n\n${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
],
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
}
|
package/lib/prompts/index.d.ts
DELETED
package/lib/prompts/index.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { getAvailableArcs, validateArcExists, validateArcNotExists } from './validation.js';
|
|
2
|
-
export async function substitutePlaceholders(promptName, template, args, timeline, tracker) {
|
|
3
|
-
const replacements = {
|
|
4
|
-
TIMELINE: timeline,
|
|
5
|
-
...args,
|
|
6
|
-
};
|
|
7
|
-
// Prompt-specific validations
|
|
8
|
-
if (['new-chapter', 'revise-chapter', 'expand-chapter'].includes(promptName)) {
|
|
9
|
-
const { arc, chapter } = args;
|
|
10
|
-
if (!arc) {
|
|
11
|
-
throw new Error('Missing required argument: arc');
|
|
12
|
-
}
|
|
13
|
-
if (!chapter) {
|
|
14
|
-
throw new Error('Missing required argument: chapter');
|
|
15
|
-
}
|
|
16
|
-
// Validate arc exists
|
|
17
|
-
const arcExists = await validateArcExists(arc, tracker, timeline);
|
|
18
|
-
if (!arcExists) {
|
|
19
|
-
const available = await getAvailableArcs(tracker, timeline);
|
|
20
|
-
throw new Error(`Arc "${arc}" not found in tracker.\nAvailable arcs: ${available.join(', ') || 'none'}`);
|
|
21
|
-
}
|
|
22
|
-
// Validate chapter is a number
|
|
23
|
-
if (!/^\d+$/.test(chapter)) {
|
|
24
|
-
throw new Error(`Chapter must be a number, got: "${chapter}"`);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
if (promptName === 'new-arc') {
|
|
28
|
-
const { name } = args;
|
|
29
|
-
if (!name) {
|
|
30
|
-
throw new Error('Missing required argument: name');
|
|
31
|
-
}
|
|
32
|
-
// Validate arc doesn't exist
|
|
33
|
-
const arcNotExists = await validateArcNotExists(name, tracker, timeline);
|
|
34
|
-
if (!arcNotExists) {
|
|
35
|
-
throw new Error(`Arc "${name}" already exists in tracker.`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
// Replace all placeholders
|
|
39
|
-
let result = template;
|
|
40
|
-
for (const [key, value] of Object.entries(replacements)) {
|
|
41
|
-
const placeholder = `{${key.toUpperCase()}}`;
|
|
42
|
-
result = result.replace(new RegExp(placeholder.replace(/[{}]/g, '\\$&'), 'g'), value);
|
|
43
|
-
}
|
|
44
|
-
return result;
|
|
45
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { Tracker } from '@echoes-io/tracker';
|
|
2
|
-
export declare function validateGitHubRepo(): {
|
|
3
|
-
exists: boolean;
|
|
4
|
-
path: string;
|
|
5
|
-
};
|
|
6
|
-
export declare function validateArcExists(arc: string, tracker: Tracker, timeline: string): Promise<boolean>;
|
|
7
|
-
export declare function validateArcNotExists(arc: string, tracker: Tracker, timeline: string): Promise<boolean>;
|
|
8
|
-
export declare function getAvailableArcs(tracker: Tracker, timeline: string): Promise<string[]>;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
3
|
-
export function validateGitHubRepo() {
|
|
4
|
-
const githubPath = resolve(process.cwd(), '../.github/.kiro/prompts');
|
|
5
|
-
return {
|
|
6
|
-
exists: existsSync(githubPath),
|
|
7
|
-
path: githubPath,
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
export async function validateArcExists(arc, tracker, timeline) {
|
|
11
|
-
const arcs = await tracker.getArcs(timeline);
|
|
12
|
-
return arcs.some((a) => a.name === arc);
|
|
13
|
-
}
|
|
14
|
-
export async function validateArcNotExists(arc, tracker, timeline) {
|
|
15
|
-
return !(await validateArcExists(arc, tracker, timeline));
|
|
16
|
-
}
|
|
17
|
-
export async function getAvailableArcs(tracker, timeline) {
|
|
18
|
-
const arcs = await tracker.getArcs(timeline);
|
|
19
|
-
return arcs.map((a) => a.name);
|
|
20
|
-
}
|
package/lib/server.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { RAGSystem } from '@echoes-io/rag';
|
|
2
|
-
import { Tracker } from '@echoes-io/tracker';
|
|
3
|
-
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
-
interface TimelineContext {
|
|
5
|
-
tracker: Tracker;
|
|
6
|
-
rag: RAGSystem;
|
|
7
|
-
contentPath: string;
|
|
8
|
-
}
|
|
9
|
-
export declare function createServer(timelines: Map<string, TimelineContext>): Server<{
|
|
10
|
-
method: string;
|
|
11
|
-
params?: {
|
|
12
|
-
[x: string]: unknown;
|
|
13
|
-
task?: {
|
|
14
|
-
[x: string]: unknown;
|
|
15
|
-
ttl?: number | null | undefined;
|
|
16
|
-
pollInterval?: number | undefined;
|
|
17
|
-
} | undefined;
|
|
18
|
-
_meta?: {
|
|
19
|
-
[x: string]: unknown;
|
|
20
|
-
progressToken?: string | number | undefined;
|
|
21
|
-
"io.modelcontextprotocol/related-task"?: {
|
|
22
|
-
[x: string]: unknown;
|
|
23
|
-
taskId: string;
|
|
24
|
-
} | undefined;
|
|
25
|
-
} | undefined;
|
|
26
|
-
} | undefined;
|
|
27
|
-
}, {
|
|
28
|
-
method: string;
|
|
29
|
-
params?: {
|
|
30
|
-
[x: string]: unknown;
|
|
31
|
-
_meta?: {
|
|
32
|
-
[x: string]: unknown;
|
|
33
|
-
"io.modelcontextprotocol/related-task"?: {
|
|
34
|
-
[x: string]: unknown;
|
|
35
|
-
taskId: string;
|
|
36
|
-
} | undefined;
|
|
37
|
-
} | undefined;
|
|
38
|
-
} | undefined;
|
|
39
|
-
}, {
|
|
40
|
-
[x: string]: unknown;
|
|
41
|
-
_meta?: {
|
|
42
|
-
[x: string]: unknown;
|
|
43
|
-
"io.modelcontextprotocol/related-task"?: {
|
|
44
|
-
[x: string]: unknown;
|
|
45
|
-
taskId: string;
|
|
46
|
-
} | undefined;
|
|
47
|
-
} | undefined;
|
|
48
|
-
}>;
|
|
49
|
-
interface TimelineContext {
|
|
50
|
-
tracker: Tracker;
|
|
51
|
-
rag: RAGSystem;
|
|
52
|
-
contentPath: string;
|
|
53
|
-
}
|
|
54
|
-
export declare function runServer(): Promise<void>;
|
|
55
|
-
export {};
|