yt-dlp-mcp/test-bilibili.mjs
kevinwatt 26b2137751 chore: release v0.7.0 - MCP Best Practices & Quality Improvements
Major release with comprehensive MCP best practices implementation:

 Added:
- Tool name prefixes (ytdlp_) for all 8 tools to avoid naming conflicts
- Zod schema validation with runtime input validation
- Tool annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)
- Response format options (JSON/Markdown) for search tools
- Pagination support with offset parameter
- Character limits (25K standard, 50K for transcripts) with smart truncation
- Actionable error messages with platform-specific guidance

🔧 Improved:
- Comprehensive tool descriptions with usage examples
- Enhanced configuration system with limits
- Better TypeScript type safety
- Professional README with badges and tables

🐛 Fixed:
- JSON parsing issue in metadata truncation
- Maintained valid JSON structure when truncated

🧪 Tested:
-  YouTube platform (Rick Astley video)
-  Bilibili platform (Chinese content)
-  Multi-language support verified
-  All 8 tools tested with real API calls

📖 Documentation:
- Created comprehensive CHANGELOG.md
- Redesigned README.md with professional formatting
- Added migration guide for v0.6.x users

🌍 Platform Support:
- Verified: YouTube, Bilibili
- Theory: 1000+ platforms via yt-dlp
2025-10-19 01:52:22 +08:00

225 lines
6.9 KiB
JavaScript
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* Test MCP server with Bilibili video
* Tests cross-platform support with https://www.bilibili.com/video/BV17YdXY4Ewj/
*/
import { spawn } from 'child_process';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const serverPath = join(__dirname, 'lib', 'index.mjs');
const TEST_VIDEO = 'https://www.bilibili.com/video/BV17YdXY4Ewj/?spm_id_from=333.1387.homepage.video_card.click&vd_source=bc7bf10259efd682c452b5ce8426b945';
console.log('🎬 Testing yt-dlp MCP Server with Bilibili Video\n');
console.log('Video:', TEST_VIDEO);
console.log('Platform: Bilibili (哔哩哔哩)\n');
const server = spawn('node', [serverPath]);
let testsPassed = 0;
let testsFailed = 0;
let responseBuffer = '';
let requestId = 0;
let currentTest = '';
const timeout = setTimeout(() => {
console.log('\n⏱ Test timeout - killing server');
server.kill();
printResults();
}, 60000);
function printResults() {
clearTimeout(timeout);
console.log(`\n${'='.repeat(60)}`);
console.log(`📊 Bilibili Test Results:`);
console.log(` ✅ Passed: ${testsPassed}`);
console.log(` ❌ Failed: ${testsFailed}`);
console.log(`${'='.repeat(60)}`);
if (testsPassed > 0) {
console.log('\n✨ Bilibili platform is supported!');
} else {
console.log('\n⚠ Bilibili support may be limited');
}
process.exit(testsFailed > 0 ? 1 : 0);
}
server.stdout.on('data', (data) => {
responseBuffer += data.toString();
const lines = responseBuffer.split('\n');
responseBuffer = lines.pop() || '';
lines.forEach(line => {
if (line.trim()) {
try {
const response = JSON.parse(line);
if (response.error) {
console.log(`${currentTest} - ERROR`);
console.log(' Error:', response.error.message);
console.log(' This may indicate limited Bilibili support\n');
testsFailed++;
} else if (response.result) {
handleTestResult(response);
}
} catch (e) {
// Not JSON
}
}
});
});
server.stderr.on('data', (data) => {
const output = data.toString().trim();
if (output && !output.includes('ExperimentalWarning')) {
console.log('🔧 Server:', output);
}
});
server.on('close', (code) => {
printResults();
});
function handleTestResult(response) {
const content = response.result.content?.[0]?.text || JSON.stringify(response.result);
if (currentTest === 'Initialize') {
console.log('✅ Initialize - PASSED\n');
testsPassed++;
}
else if (currentTest === 'Get Bilibili Metadata Summary') {
// Check if we got any content
if (content && content.length > 50 && !content.includes('Error')) {
console.log('✅ Get Bilibili Metadata Summary - PASSED');
console.log(' Response preview:');
const lines = content.split('\n').slice(0, 8);
lines.forEach(line => console.log(` ${line}`));
if (content.split('\n').length > 8) {
console.log(' ...');
}
console.log();
testsPassed++;
} else if (content.includes('Error') || content.includes('Unsupported')) {
console.log('⚠️ Get Bilibili Metadata Summary - PARTIAL');
console.log(' Platform may have limited support');
console.log(' Response:', content.substring(0, 150));
console.log();
testsFailed++;
} else {
console.log('❌ Get Bilibili Metadata Summary - FAILED');
console.log(' Response too short or invalid');
console.log();
testsFailed++;
}
}
else if (currentTest === 'List Bilibili Subtitle Languages') {
if (content.length > 50 && !content.includes('Error')) {
console.log('✅ List Bilibili Subtitle Languages - PASSED');
console.log(' Subtitle info retrieved\n');
testsPassed++;
} else if (content.includes('No subtitle') || content.includes('not found')) {
console.log('⚠️ List Bilibili Subtitle Languages - NO SUBTITLES');
console.log(' Video may not have subtitles available\n');
testsPassed++; // Not an error, just no subs
} else {
console.log('❌ List Bilibili Subtitle Languages - FAILED');
console.log(' Response:', content.substring(0, 200));
console.log();
testsFailed++;
}
}
else if (currentTest === 'Get Bilibili Metadata (Filtered)') {
try {
const metadata = JSON.parse(content);
if (metadata.id || metadata.title) {
console.log('✅ Get Bilibili Metadata (Filtered) - PASSED');
if (metadata.title) console.log(` Title: ${metadata.title}`);
if (metadata.uploader) console.log(` Uploader: ${metadata.uploader}`);
if (metadata.duration) console.log(` Duration: ${metadata.duration}s`);
console.log();
testsPassed++;
} else {
console.log('❌ Get Bilibili Metadata (Filtered) - FAILED');
console.log(' Missing expected fields');
console.log();
testsFailed++;
}
} catch (e) {
// Maybe it's an error message
if (content.includes('Error') || content.includes('Unsupported')) {
console.log('⚠️ Get Bilibili Metadata (Filtered) - PLATFORM ISSUE');
console.log(' Response:', content.substring(0, 200));
console.log();
testsFailed++;
} else {
console.log('❌ Get Bilibili Metadata (Filtered) - FAILED');
console.log(' Invalid response format');
console.log();
testsFailed++;
}
}
}
}
function sendRequest(method, params, testName) {
requestId++;
currentTest = testName;
console.log(`🔍 Test ${requestId}: ${testName}`);
if (testName.includes('Metadata') || testName.includes('Subtitle')) {
console.log(' (Testing Bilibili platform support...)\n');
}
const request = {
jsonrpc: '2.0',
id: requestId,
method: method,
params: params
};
server.stdin.write(JSON.stringify(request) + '\n');
}
// Run tests
setTimeout(() => {
sendRequest('initialize', {
protocolVersion: '2024-11-05',
capabilities: {},
clientInfo: { name: 'bilibili-test', version: '1.0.0' }
}, 'Initialize');
setTimeout(() => {
sendRequest('tools/call', {
name: 'ytdlp_get_video_metadata_summary',
arguments: { url: TEST_VIDEO }
}, 'Get Bilibili Metadata Summary');
setTimeout(() => {
sendRequest('tools/call', {
name: 'ytdlp_list_subtitle_languages',
arguments: { url: TEST_VIDEO }
}, 'List Bilibili Subtitle Languages');
setTimeout(() => {
sendRequest('tools/call', {
name: 'ytdlp_get_video_metadata',
arguments: {
url: TEST_VIDEO,
fields: ['id', 'title', 'uploader', 'duration', 'description']
}
}, 'Get Bilibili Metadata (Filtered)');
setTimeout(() => {
console.log('\n✅ All Bilibili tests completed!');
server.kill();
}, 8000);
}, 5000);
}, 5000);
}, 2000);
}, 1000);