client.js•1.85 kB
// client.js (ESM) - 暴露 HTTP API,内部长连接到 MCP server
import express from 'express';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
const app = express();
app.use(express.json());
// 启动即建立到本地 MCP server(server.js)的长连接
const client = new Client({ name: 'DemoClient', version: '0.1.0' });
const transport = new StdioClientTransport({
command: 'node',
args: ['server.js'],
stderr: 'inherit',
cwd: process.cwd(),
});
await client.connect(transport);
console.log('✅ MCP client connected to local server via stdio');
// 健康检查
app.get('/health', (_req, res) => {
res.json({ status: 'ok' });
});
// 列出工具
app.get('/tools', async (_req, res) => {
try {
const tools = await client.listTools({});
res.json(tools);
} catch (e) {
res.status(500).json({ error: String(e) });
}
});
// 调用工具
app.post('/tools/:name', async (req, res) => {
try {
const result = await client.callTool({
name: req.params.name,
arguments: req.body || {},
});
res.json(result);
} catch (e) {
res.status(500).json({ error: String(e) });
}
});
const PORT = process.env.PORT ? Number(process.env.PORT) : 3000;
const server = app.listen(PORT, () => {
console.log(`HTTP API listening on http://localhost:${PORT}`);
});
// 优雅关闭
async function shutdown() {
try {
console.log('Shutting down...');
await client.close();
await transport.close();
} catch (e) {
// 忽略关闭中的异常,尽可能退出
} finally {
server.close(() => process.exit(0));
// 双保险:若 3 秒未退出则强退
setTimeout(() => process.exit(0), 3000).unref();
}
}
process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);