Files
NewTube/mcp/server.test.mjs
T
bruno 1812b86dd4
CI / build-and-test (push) Successful in 14m3s
feat(mcp): serveur MCP stdio 7 outils + guide API/MCP + couverture tests
- mcp/server.mjs : search, suggest, details, trending, transcript,
  transcript_text, health_check (client fin vers API REST)
- docs/API_MCP_GUIDE.md : reference complete REST + MCP + transcript
- tests : server/tests/api_coverage.test.mjs (17 cas HTTP),
  mcp/tools.test.mjs (7 outils sur stub), scripts test:mcp/test:api
- fix(db): DELETE playlist 500 FK -> metrique avant delete + cleanup
  enfants + recordPlaylistMetric tolerant (observabilite)
2026-09-27 18:39:26 -04:00

63 lines
2.3 KiB
JavaScript

import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { spawn } from 'node:child_process';
function rpc(proc, obj) {
return new Promise((resolve) => {
const onData = (buf) => {
const lines = String(buf).split('\n').filter(Boolean);
for (const l of lines) {
try {
const msg = JSON.parse(l);
if (msg.id === obj.id) {
proc.stdout.off('data', onData);
resolve(msg);
return;
}
} catch {}
}
};
proc.stdout.on('data', onData);
proc.stdin.write(JSON.stringify(obj) + '\n');
});
}
describe('NewTube MCP server (stdio)', () => {
it('initialize + tools/list expose 7 outils dont transcript', async () => {
const proc = spawn(process.execPath, ['./mcp/server.mjs'], { env: { ...process.env, NEWTUBE_API_URL: 'http://127.0.0.1:9/api' } });
try {
const init = await rpc(proc, { jsonrpc: '2.0', id: 1, method: 'initialize', params: {} });
assert.equal(init.result.serverInfo.name, 'newtube');
assert.ok(init.result.capabilities.tools);
const list = await rpc(proc, { jsonrpc: '2.0', id: 2, method: 'tools/list', params: {} });
const names = list.result.tools.map((t) => t.name);
for (const expected of ['search_videos', 'get_video_details', 'get_trending', 'get_transcript', 'get_transcript_text', 'health_check']) {
assert.ok(names.includes(expected), `outil manquant: ${expected}`);
}
const tr = list.result.tools.find((t) => t.name === 'get_transcript');
assert.ok(tr.inputSchema.properties.provider);
assert.ok(tr.inputSchema.properties.videoId);
const ping = await rpc(proc, { jsonrpc: '2.0', id: 3, method: 'ping', params: {} });
assert.deepEqual(ping.result, {});
} finally {
proc.kill();
}
});
it('validation locale sans API (q trop court -> isError)', async () => {
const proc = spawn(process.execPath, ['./mcp/server.mjs'], { env: { ...process.env, NEWTUBE_API_URL: 'http://127.0.0.1:9/api' } });
try {
const call = await rpc(proc, {
jsonrpc: '2.0', id: 10, method: 'tools/call',
params: { name: 'search_videos', arguments: { q: 'x' } },
});
assert.equal(call.result.isError, true);
assert.match(call.result.content[0].text, /min 2/);
} finally {
proc.kill();
}
});
});