feat(lib): bundle MCP servers from .common/lib into factory/lib/
Copies source (no node_modules, dist, .tasks, .wiki, __pycache__) for: - projects-meta-mcp v2.25.0 (TypeScript/Node) - wiki-graph v0.3.1 (TypeScript/Node) - interns-mcp v0.3.3 (Python/FastMCP) .gitignore: exclude lib build artefacts (node_modules, dist, .venv, __pycache__, *.pyc) bootstrap.ps1: add MCP build step — npm install+build for TS servers, venv+pip for Python Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
81
lib/wiki-graph/tests/tools.test.ts
Normal file
81
lib/wiki-graph/tests/tools.test.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { makeWikiGraphTools } from '../src/tools.js';
|
||||
import { GraphCache } from '../src/cache.js';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const FIXTURE = join(here, 'fixtures', 'wiki');
|
||||
|
||||
function toolMap() {
|
||||
const tools = makeWikiGraphTools(new GraphCache());
|
||||
return new Map(tools.map((t) => [t.name, t]));
|
||||
}
|
||||
|
||||
function textOf(res: { content: Array<{ type: string; text: string }>; isError?: boolean }) {
|
||||
return res.content.map((c) => c.text).join('\n');
|
||||
}
|
||||
|
||||
describe('wiki-graph MCP tools', () => {
|
||||
const tools = toolMap();
|
||||
|
||||
test('exposes exactly the five v1 tools', () => {
|
||||
expect([...tools.keys()].sort()).toEqual([
|
||||
'backlinks',
|
||||
'neighbors',
|
||||
'orphans',
|
||||
'path',
|
||||
'stats',
|
||||
]);
|
||||
});
|
||||
|
||||
test('every tool requires a corpus argument', () => {
|
||||
for (const t of tools.values()) {
|
||||
expect(t.inputSchema.required).toContain('corpus');
|
||||
}
|
||||
});
|
||||
|
||||
test('path: returns the chain', () => {
|
||||
const res = tools.get('path')!.handler({ corpus: FIXTURE, from: 'a', to: 'c' });
|
||||
expect(textOf(res)).toContain('a → b → c');
|
||||
});
|
||||
|
||||
test('path: reports absence', () => {
|
||||
const res = tools.get('path')!.handler({ corpus: FIXTURE, from: 'a', to: 'e' });
|
||||
expect(textOf(res).toLowerCase()).toContain('no path');
|
||||
});
|
||||
|
||||
test('neighbors: honors depth', () => {
|
||||
const res = tools.get('neighbors')!.handler({ corpus: FIXTURE, node: 'a', depth: 2 });
|
||||
const txt = textOf(res);
|
||||
expect(txt).toContain('b');
|
||||
expect(txt).toContain('c');
|
||||
});
|
||||
|
||||
test('backlinks: lists incoming', () => {
|
||||
const res = tools.get('backlinks')!.handler({ corpus: FIXTURE, node: 'c' });
|
||||
const txt = textOf(res);
|
||||
expect(txt).toContain('b');
|
||||
expect(txt).toContain('d');
|
||||
});
|
||||
|
||||
test('orphans: lists unlinked pages and dangling targets', () => {
|
||||
const res = tools.get('orphans')!.handler({ corpus: FIXTURE });
|
||||
const txt = textOf(res);
|
||||
expect(txt).toContain('e');
|
||||
expect(txt).toContain('<todo-module>');
|
||||
});
|
||||
|
||||
test('stats: reports counts', () => {
|
||||
const res = tools.get('stats')!.handler({ corpus: FIXTURE });
|
||||
const txt = textOf(res);
|
||||
expect(txt).toContain('5');
|
||||
expect(txt).toContain('nodes');
|
||||
});
|
||||
|
||||
test('missing corpus is a clean error, not a throw', () => {
|
||||
const res = tools.get('stats')!.handler({});
|
||||
expect(res.isError).toBe(true);
|
||||
expect(textOf(res).toLowerCase()).toContain('corpus');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user