test-mcp.ts•6.47 kB
#!/usr/bin/env node
import 'dotenv/config';
import { spawn, ChildProcess } from 'child_process';
import { randomUUID } from 'crypto';
interface MCPMessage {
jsonrpc: '2.0';
id?: string | number;
method?: string;
params?: any;
result?: any;
error?: any;
}
class MCPTestClient {
private server: ChildProcess;
private messageQueue: Promise<any>[] = [];
private responses: Map<string | number, any> = new Map();
constructor() {
console.log('🚀 啟動 Notion MCP 伺服器測試...');
this.server = spawn('node', ['dist/index.js'], {
stdio: ['pipe', 'pipe', 'pipe'],
env: process.env
});
this.server.stderr?.on('data', (data) => {
console.log('📋 伺服器日誌:', data.toString().trim());
});
this.server.stdout?.on('data', (data) => {
const lines = data.toString().trim().split('\n');
for (const line of lines) {
if (line.trim()) {
try {
const message: MCPMessage = JSON.parse(line);
if (message.id !== undefined) {
this.responses.set(message.id, message);
}
} catch (error) {
console.log('📨 伺服器輸出:', line);
}
}
}
});
this.server.on('error', (error) => {
console.error('❌ 伺服器錯誤:', error);
});
this.server.on('exit', (code) => {
console.log(`🔄 伺服器結束,退出碼: ${code}`);
});
}
private async sendMessage(message: MCPMessage): Promise<any> {
const messageStr = JSON.stringify(message) + '\n';
this.server.stdin?.write(messageStr);
if (message.id !== undefined) {
// 等待回應
return new Promise((resolve, reject) => {
const checkResponse = () => {
if (this.responses.has(message.id!)) {
const response = this.responses.get(message.id!);
this.responses.delete(message.id!);
resolve(response);
} else {
setTimeout(checkResponse, 100);
}
};
setTimeout(() => reject(new Error('Response timeout')), 10000);
checkResponse();
});
}
}
async initialize(): Promise<void> {
console.log('\n🔌 初始化 MCP 連接...');
const response = await this.sendMessage({
jsonrpc: '2.0',
id: 1,
method: 'initialize',
params: {
protocolVersion: '2024-11-05',
capabilities: {
roots: {
listChanged: true
}
},
clientInfo: {
name: 'notion-mcp-test-client',
version: '1.0.0'
}
}
});
if (response.error) {
throw new Error(`初始化失敗: ${response.error.message}`);
}
console.log('✅ MCP 連接初始化成功');
console.log('📋 伺服器能力:', JSON.stringify(response.result.capabilities, null, 2));
}
async listTools(): Promise<void> {
console.log('\n🛠️ 列出可用工具...');
const response = await this.sendMessage({
jsonrpc: '2.0',
id: 2,
method: 'tools/list'
});
if (response.error) {
throw new Error(`列出工具失敗: ${response.error.message}`);
}
console.log('✅ 可用工具:');
response.result.tools.forEach((tool: any, index: number) => {
console.log(` ${index + 1}. ${tool.name} - ${tool.description}`);
});
}
async listResources(): Promise<void> {
console.log('\n📚 列出可用資源...');
const response = await this.sendMessage({
jsonrpc: '2.0',
id: 3,
method: 'resources/list'
});
if (response.error) {
throw new Error(`列出資源失敗: ${response.error.message}`);
}
console.log('✅ 可用資源:');
response.result.resources.forEach((resource: any, index: number) => {
console.log(` ${index + 1}. ${resource.name} (${resource.uri})`);
});
}
async testSearchPages(): Promise<void> {
console.log('\n🔍 測試搜尋頁面功能...');
try {
const response = await this.sendMessage({
jsonrpc: '2.0',
id: 4,
method: 'tools/call',
params: {
name: 'search-pages',
arguments: {
query: 'test'
}
}
});
if (response.error) {
console.log('⚠️ 搜尋頁面失敗:', response.error.message);
} else {
console.log('✅ 搜尋頁面成功');
if (response.result.content[0].text) {
const searchResult = JSON.parse(response.result.content[0].text);
console.log(` 找到 ${searchResult.results?.length || 0} 個結果`);
}
}
} catch (error) {
console.log('⚠️ 搜尋頁面測試失敗:', (error as Error).message);
}
}
async testGetRecentPages(): Promise<void> {
console.log('\n📄 測試取得最近頁面資源...');
try {
const response = await this.sendMessage({
jsonrpc: '2.0',
id: 5,
method: 'resources/read',
params: {
uri: 'notion://recent-pages'
}
});
if (response.error) {
console.log('⚠️ 取得最近頁面失敗:', response.error.message);
} else {
console.log('✅ 取得最近頁面成功');
if (response.result.contents[0].text) {
const pages = JSON.parse(response.result.contents[0].text);
console.log(` 找到 ${pages.results?.length || 0} 個最近頁面`);
}
}
} catch (error) {
console.log('⚠️ 取得最近頁面測試失敗:', (error as Error).message);
}
}
close(): void {
console.log('\n🔚 關閉連接...');
this.server.kill('SIGTERM');
}
}
async function runTests() {
const client = new MCPTestClient();
try {
// 等待伺服器啟動
await new Promise(resolve => setTimeout(resolve, 1000));
// 執行測試
await client.initialize();
await client.listTools();
await client.listResources();
await client.testSearchPages();
await client.testGetRecentPages();
console.log('\n🎉 所有測試完成!');
} catch (error) {
console.error('❌ 測試失敗:', (error as Error).message);
} finally {
client.close();
process.exit(0);
}
}
// 處理程序退出
process.on('SIGINT', () => {
console.log('\n👋 收到中斷信號,正在退出...');
process.exit(0);
});
// 執行測試
runTests().catch(console.error);