#!/usr/bin/env node
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { spawn } from 'child_process';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
class TestClient {
constructor() {
this.client = null;
this.serverProcess = null;
}
async start() {
console.log('๐ Markdown MCP Server ํ
์คํธ ํด๋ผ์ด์ธํธ ์์...\n');
// ์๋ฒ ํ๋ก์ธ์ค ์์
this.serverProcess = spawn('node', ['src/index.js'], {
stdio: ['pipe', 'pipe', 'pipe'],
cwd: __dirname
});
// ์๋ฒ ๋ก๊ทธ ์ถ๋ ฅ
this.serverProcess.stderr.on('data', (data) => {
console.log(`[์๋ฒ] ${data.toString().trim()}`);
});
// ํด๋ผ์ด์ธํธ ์์ฑ
const transport = new StdioClientTransport(
this.serverProcess.stdout,
this.serverProcess.stdin
);
this.client = new Client({
name: 'test-client',
version: '1.0.0'
}, {
capabilities: {
tools: {}
}
});
await this.client.connect(transport);
console.log('โ
์๋ฒ์ ์ฐ๊ฒฐ๋์์ต๋๋ค.\n');
}
async testBasicOperations() {
console.log('๐ ๊ธฐ๋ณธ CRUD ์์
ํ
์คํธ...\n');
// 1. ํ์ผ ์์ฑ
console.log('1. ํ์ผ ์์ฑ ํ
์คํธ');
try {
const createResult = await this.client.callTool('create_markdown', {
file_path: 'test-file.md',
content: '# ํ
์คํธ ํ์ผ\n\n์ด๊ฒ์ ํ
์คํธ ํ์ผ์
๋๋ค.\n\n## ์น์
1\n\n๋ด์ฉ์ด ์ฌ๊ธฐ์ ์์ต๋๋ค.\n\n#tag1 #tag2'
});
console.log('โ
ํ์ผ ์์ฑ ์ฑ๊ณต:', createResult.content[0].text);
} catch (error) {
console.log('โ ํ์ผ ์์ฑ ์คํจ:', error.message);
}
// 2. ํ์ผ ์ฝ๊ธฐ
console.log('\n2. ํ์ผ ์ฝ๊ธฐ ํ
์คํธ');
try {
const readResult = await this.client.callTool('read_markdown', {
file_path: 'test-file.md'
});
console.log('โ
ํ์ผ ์ฝ๊ธฐ ์ฑ๊ณต:', readResult.content[0].text.substring(0, 100) + '...');
} catch (error) {
console.log('โ ํ์ผ ์ฝ๊ธฐ ์คํจ:', error.message);
}
// 3. ํ์ผ ๋ชฉ๋ก ์กฐํ
console.log('\n3. ํ์ผ ๋ชฉ๋ก ์กฐํ ํ
์คํธ');
try {
const listResult = await this.client.callTool('list_markdown_files', {
directory: '.',
recursive: false
});
console.log('โ
ํ์ผ ๋ชฉ๋ก ์กฐํ ์ฑ๊ณต:', listResult.content[0].text);
} catch (error) {
console.log('โ ํ์ผ ๋ชฉ๋ก ์กฐํ ์คํจ:', error.message);
}
// 4. ๊ฒ์ ํ
์คํธ
console.log('\n4. ๊ฒ์ ํ
์คํธ');
try {
const searchResult = await this.client.callTool('search_markdown', {
directory: '.',
query: 'ํ
์คํธ'
});
console.log('โ
๊ฒ์ ์ฑ๊ณต:', searchResult.content[0].text);
} catch (error) {
console.log('โ ๊ฒ์ ์คํจ:', error.message);
}
// 5. Obsidian ๋งํฌ ์ถ์ถ
console.log('\n5. Obsidian ๋งํฌ ์ถ์ถ ํ
์คํธ');
try {
const linksResult = await this.client.callTool('extract_obsidian_links', {
file_path: 'test-file.md'
});
console.log('โ
๋งํฌ ์ถ์ถ ์ฑ๊ณต:', linksResult.content[0].text);
} catch (error) {
console.log('โ ๋งํฌ ์ถ์ถ ์คํจ:', error.message);
}
// 6. ํ๊ทธ๋ก ํ์ผ ๊ฒ์
console.log('\n6. ํ๊ทธ ๊ฒ์ ํ
์คํธ');
try {
const tagResult = await this.client.callTool('find_files_by_tag', {
tag: 'tag1'
});
console.log('โ
ํ๊ทธ ๊ฒ์ ์ฑ๊ณต:', tagResult.content[0].text);
} catch (error) {
console.log('โ ํ๊ทธ ๊ฒ์ ์คํจ:', error.message);
}
// 7. ๊ทธ๋ํ ๋ฐ์ดํฐ ์์ฑ
console.log('\n7. ๊ทธ๋ํ ๋ฐ์ดํฐ ์์ฑ ํ
์คํธ');
try {
const graphResult = await this.client.callTool('generate_graph_data', {});
console.log('โ
๊ทธ๋ํ ๋ฐ์ดํฐ ์์ฑ ์ฑ๊ณต:', graphResult.content[0].text.substring(0, 200) + '...');
} catch (error) {
console.log('โ ๊ทธ๋ํ ๋ฐ์ดํฐ ์์ฑ ์คํจ:', error.message);
}
// 8. Vault ํต๊ณ
console.log('\n8. Vault ํต๊ณ ํ
์คํธ');
try {
const statsResult = await this.client.callTool('generate_vault_stats', {});
console.log('โ
Vault ํต๊ณ ์์ฑ ์ฑ๊ณต:', statsResult.content[0].text.substring(0, 200) + '...');
} catch (error) {
console.log('โ Vault ํต๊ณ ์์ฑ ์คํจ:', error.message);
}
// 9. ํ์ผ ์
๋ฐ์ดํธ
console.log('\n9. ํ์ผ ์
๋ฐ์ดํธ ํ
์คํธ');
try {
const updateResult = await this.client.callTool('update_markdown', {
file_path: 'test-file.md',
content: '# ์
๋ฐ์ดํธ๋ ํ
์คํธ ํ์ผ\n\n์ด ํ์ผ์ ์
๋ฐ์ดํธ๋์์ต๋๋ค.\n\n## ์๋ก์ด ์น์
\n\n์๋ก์ด ๋ด์ฉ์
๋๋ค.\n\n#updated #test',
append: false
});
console.log('โ
ํ์ผ ์
๋ฐ์ดํธ ์ฑ๊ณต:', updateResult.content[0].text);
} catch (error) {
console.log('โ ํ์ผ ์
๋ฐ์ดํธ ์คํจ:', error.message);
}
// 10. ํ์ผ ์ญ์
console.log('\n10. ํ์ผ ์ญ์ ํ
์คํธ');
try {
const deleteResult = await this.client.callTool('delete_markdown', {
file_path: 'test-file.md'
});
console.log('โ
ํ์ผ ์ญ์ ์ฑ๊ณต:', deleteResult.content[0].text);
} catch (error) {
console.log('โ ํ์ผ ์ญ์ ์คํจ:', error.message);
}
}
async testAdvancedFeatures() {
console.log('\n๐ง ๊ณ ๊ธ ๊ธฐ๋ฅ ํ
์คํธ...\n');
// 1. ๋ฐ์ผ๋ฆฌ ๋
ธํธ ์์ฑ
console.log('1. ๋ฐ์ผ๋ฆฌ ๋
ธํธ ์์ฑ ํ
์คํธ');
try {
const dailyResult = await this.client.callTool('create_daily_note', {
date: '2024-01-15',
template: '## ์ค๋์ ํ ์ผ\n\n- [ ] \n\n## ๋ฉ๋ชจ\n\n',
folder: 'daily'
});
console.log('โ
๋ฐ์ผ๋ฆฌ ๋
ธํธ ์์ฑ ์ฑ๊ณต:', dailyResult.content[0].text);
} catch (error) {
console.log('โ ๋ฐ์ผ๋ฆฌ ๋
ธํธ ์์ฑ ์คํจ:', error.message);
}
// 2. ํ
ํ๋ฆฟ ๊ด๋ฆฌ
console.log('\n2. ํ
ํ๋ฆฟ ๊ด๋ฆฌ ํ
์คํธ');
try {
const templateResult = await this.client.callTool('manage_template', {
action: 'create',
template_name: 'meeting',
content: '# ํ์๋ก\n\n## ์ฐธ์์\n\n## ์๊ฑด\n\n## ๊ฒฐ์ ์ฌํญ\n\n## ๋ค์ ์ก์
์์ดํ
\n\n'
});
console.log('โ
ํ
ํ๋ฆฟ ์์ฑ ์ฑ๊ณต:', templateResult.content[0].text);
} catch (error) {
console.log('โ ํ
ํ๋ฆฟ ์์ฑ ์คํจ:', error.message);
}
// 3. Frontmatter ๊ฒ์
console.log('\n3. Frontmatter ๊ฒ์ ํ
์คํธ');
try {
const frontmatterResult = await this.client.callTool('search_by_frontmatter', {
filters: [
{ field: 'title', value: 'Test', operator: 'contains' }
]
});
console.log('โ
Frontmatter ๊ฒ์ ์ฑ๊ณต:', frontmatterResult.content[0].text);
} catch (error) {
console.log('โ Frontmatter ๊ฒ์ ์คํจ:', error.message);
}
// 4. TODO ์ถ์ถ
console.log('\n4. TODO ์ถ์ถ ํ
์คํธ');
try {
const todoResult = await this.client.callTool('extract_todos', {
status: 'all'
});
console.log('โ
TODO ์ถ์ถ ์ฑ๊ณต:', todoResult.content[0].text);
} catch (error) {
console.log('โ TODO ์ถ์ถ ์คํจ:', error.message);
}
// 5. ๋
ธํธ ์ ์ฌ์ฑ
console.log('\n5. ๋
ธํธ ์ ์ฌ์ฑ ํ
์คํธ');
try {
const similarityResult = await this.client.callTool('find_similar_notes', {
file_path: 'daily/2024-01-15.md',
limit: 3
});
console.log('โ
๋
ธํธ ์ ์ฌ์ฑ ๊ฒ์ ์ฑ๊ณต:', similarityResult.content[0].text);
} catch (error) {
console.log('โ ๋
ธํธ ์ ์ฌ์ฑ ๊ฒ์ ์คํจ:', error.message);
}
}
async stop() {
if (this.client) {
await this.client.close();
}
if (this.serverProcess) {
this.serverProcess.kill();
}
console.log('\n๐ ํ
์คํธ ํด๋ผ์ด์ธํธ ์ข
๋ฃ');
}
async run() {
try {
await this.start();
await this.testBasicOperations();
await this.testAdvancedFeatures();
} catch (error) {
console.error('โ ํ
์คํธ ์ค ์ค๋ฅ ๋ฐ์:', error);
} finally {
await this.stop();
}
}
}
// ํ
์คํธ ์คํ
const testClient = new TestClient();
testClient.run();