index.ts•7.56 kB
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
type CallToolRequest,
type Tool
} from '@modelcontextprotocol/sdk/types.js';
import { ConversationLogger } from './tools/conversationLogger.js';
class AIConversationLoggerServer {
private readonly server: Server;
private readonly conversationLogger: ConversationLogger;
constructor() {
this.server = new Server(
{
name: 'ai-conversation-logger-mcp',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
this.conversationLogger = new ConversationLogger();
this.setupToolHandlers();
}
private setupToolHandlers(): void {
this.server.setRequestHandler(ListToolsRequestSchema, async (): Promise<{ tools: Tool[] }> => {
return {
tools: [
{
name: 'log_conversation',
description: '记录AI对话 - 所有会话都要记录\n\n使用规范:\n• userRequest: 用户原始需求+上传文件说明\n• aiTodoList: 你的执行计划清单(即使只是查看也要列出)\n• aiSummary: 你的操作总结(3-5句话,包括解释、分析等)\n• fileOperations: 文件操作总结,格式:"动作 文件路径 - 说明"(可为空)\n• title: 对话标题(可选)\n• tags: 标签数组(可选)',
inputSchema: {
type: 'object',
properties: {
userRequest: {
type: 'string',
description: '用户原始需求 + 上传文件说明'
},
aiTodoList: {
type: 'array',
items: { type: 'string' },
description: 'AI的执行计划清单(即使只是查看也要列出)'
},
aiSummary: {
type: 'string',
description: 'AI的操作总结(3-5句话,包括解释、分析等)'
},
fileOperations: {
type: 'array',
items: { type: 'string' },
description: '文件操作总结,格式:"动作 文件路径 - 说明"(可为空)'
},
title: {
type: 'string',
description: '对话标题(可选)'
},
tags: {
type: 'array',
items: { type: 'string' },
description: '标签数组(可选)'
},
project: {
type: 'string',
description: '项目名(可选,自动检测)'
}
},
required: ['userRequest', 'aiTodoList', 'aiSummary']
}
},
{
name: 'search_conversations',
description: '搜索历史对话记录\n\n支持:\n• 关键词搜索\n• 文件名模式搜索\n• 时间范围筛选\n• 标签过滤',
inputSchema: {
type: 'object',
properties: {
keywords: {
type: 'array',
items: { type: 'string' },
description: '关键词搜索'
},
filePattern: {
type: 'string',
description: '文件名模式搜索'
},
days: {
type: 'number',
description: '最近N天'
},
project: {
type: 'string',
description: '项目过滤(默认当前)'
},
tags: {
type: 'array',
items: { type: 'string' },
description: '标签过滤'
},
limit: {
type: 'number',
description: '结果数量限制',
default: 10
}
}
}
},
{
name: 'get_context_suggestions',
description: '获取相关上下文建议\n\n基于当前输入和文件推荐历史记录',
inputSchema: {
type: 'object',
properties: {
currentInput: {
type: 'string',
description: '当前用户输入'
},
currentFiles: {
type: 'array',
items: { type: 'string' },
description: '当前涉及的文件'
},
project: {
type: 'string',
description: '项目过滤(可选)'
}
},
required: ['currentInput']
}
},
{
name: 'list_projects',
description: 'List all projects with optional statistics',
inputSchema: {
type: 'object',
properties: {
includeStats: {
type: 'boolean',
description: 'Include statistics for each project',
default: false
}
}
}
}
]
};
});
this.server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'log_conversation':
return await this.conversationLogger.logConversation(args || {});
case 'search_conversations':
return await this.conversationLogger.searchConversations(args || {});
case 'get_context_suggestions':
return await this.conversationLogger.getContextSuggestions(args || {});
case 'list_projects':
return await this.conversationLogger.listProjects(args || {});
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
console.error(`Error executing tool ${name}:`, error);
return {
content: [
{
type: 'text',
text: `Error executing ${name}: ${error instanceof Error ? error.message : String(error)}`
}
],
isError: true
};
}
});
}
async start(): Promise<void> {
try {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('AI Conversation Logger MCP Server started successfully');
} catch (error) {
console.error('Failed to start MCP server:', error);
throw error;
}
}
}
// Handle process signals gracefully
process.on('SIGINT', () => {
console.error('Received SIGINT, shutting down gracefully...');
process.exit(0);
});
process.on('SIGTERM', () => {
console.error('Received SIGTERM, shutting down gracefully...');
process.exit(0);
});
process.on('uncaughtException', (error) => {
console.error('Uncaught exception:', error);
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled rejection at:', promise, 'reason:', reason);
process.exit(1);
});
const server = new AIConversationLoggerServer();
server.start().catch((error) => {
console.error('Failed to start server:', error);
process.exit(1);
});