#!/usr/bin/env -S node --loader tsx import fs from 'fs'; import os from 'os'; import path from 'path'; import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; /** Supported server types */ type ServerType = 'filesystem' | 'github' | 'postgres' | 'sqlite' | 'custom'; interface FilesystemConfig { type: 'filesystem'; rootPath: string } interface GithubConfig { type: 'github'; token: string } interface PostgresConfig { type: 'postgres'; host: string; port: number; database: string; username: string; password: string } interface SqliteConfig { type: 'sqlite'; path: string } interface CustomConfig { type: 'custom'; command: string; args?: string[]; env?: Record } type ConfigValue = FilesystemConfig | GithubConfig | PostgresConfig | SqliteConfig | CustomConfig; interface ServerConfig { id: string; name: string; type: ServerType; enabled: boolean; status?: string; config: ConfigValue; } function buildCommand(server: ServerConfig): { command: string; args: string[]; env: Record } { const env: Record = {}; switch (server.type) { case 'filesystem': { const cfg = server.config as FilesystemConfig; return { command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', cfg.rootPath || process.cwd()], env }; } case 'github': { const cfg = server.config as GithubConfig; env.GITHUB_PERSONAL_ACCESS_TOKEN = cfg.token; return { command: 'npx', args: ['-y', '@modelcontextprotocol/server-github'], env }; } case 'postgres': { const cfg = server.config as PostgresConfig; env.POSTGRES_CONNECTION_STRING = `postgresql://${cfg.username}:${cfg.password}@${cfg.host}:${cfg.port}/${cfg.database}`; return { command: 'npx', args: ['-y', '@modelcontextprotocol/server-postgres'], env }; } case 'sqlite': { const cfg = server.config as SqliteConfig; return { command: 'npx', args: ['-y', '@modelcontextprotocol/server-sqlite', cfg.path], env }; } case 'custom': { const cfg = server.config as CustomConfig; if (cfg.command === 'npx') { return { command: 'npx', args: cfg.args || [], env: { ...env, ...(cfg.env || {}) } }; } const looksLikePackage = cfg.command.startsWith('@') || (!cfg.command.includes('/') && !cfg.command.includes('\\')); if (looksLikePackage) { return { command: 'npx', args: [cfg.command, ...(cfg.args || [])], env: { ...env, ...(cfg.env || {}) } }; } return { command: cfg.command, args: cfg.args || [], env: { ...env, ...(cfg.env || {}) } }; } } } /** * Verify enabled MCP servers by connecting with the official SDK and listing tools. */ async function verify() { const configPath = path.join(os.homedir(), '.config', 'hashgraph-online', 'mcp-servers.json'); console.log(`Reading: ${configPath}`); if (!fs.existsSync(configPath)) { console.error('Config file not found'); process.exit(1); } const servers: ServerConfig[] = JSON.parse(fs.readFileSync(configPath, 'utf8')); const enabled = servers.filter(s => s.enabled); if (enabled.length === 0) { console.log('No enabled servers. Nothing to verify.'); return; } for (const s of enabled) { const { command, args, env } = buildCommand(s); console.log(`\nServer: ${s.name} (${s.type})`); console.log(`Command: ${command} ${args.join(' ')}`); try { const transport = new StdioClientTransport({ command, args, env: { ...process.env, ...env } }); const client = new Client({ name: 'hol-desktop-verify', version: '1.0.0' }); await client.connect(transport); const { tools } = await client.listTools(); console.log(`Tools: ${tools.length}`); tools.slice(0, 5).forEach(t => console.log(` - ${t.name}${t.title ? `: ${t.title}` : ''}`)); await client.close(); } catch (e) { console.error('Failed:', e); } } } verify().catch(err => { console.error(err); process.exit(1); });