CI / build-and-test (push) Successful in 14m6s
- tests: server/tests/api_coverage2.test.mjs (23 cas offline-safe) : oauth (status/url/connections/preview), channels (validations), subscriptions batch + groupes CRUD, transcripts history, likes/history DELETE, playlists public/view/reorder, telemetry summary, downloads 401/403/400, ai 503, twitch-token, config.js, rumble 400 - mcp v1.1.0 : 4 outils authentifies (list_playlists/likes/ subscriptions/watch_history, NEWTUBE_TOKEN) + tests stub - openapi.json v1.1 : 15 chemins documentes (sante, recherche, details, trending, transcript, auth, prefs, likes, subs, downloads, oauth, playlists) ; guide maj (11 outils)
63 lines
2.4 KiB
JavaScript
63 lines
2.4 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 11 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', 'suggest_queries', 'get_video_details', 'get_trending', 'get_transcript', 'get_transcript_text', 'health_check', 'list_playlists', 'list_likes', 'list_subscriptions', 'list_watch_history']) {
|
|
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();
|
|
}
|
|
});
|
|
});
|