xiaozhi-client 0.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -55
- package/dist/cli.cjs +5 -450
- package/dist/cli.cjs.map +1 -1
- package/dist/configManager.cjs +1 -233
- package/dist/configManager.cjs.map +1 -1
- package/dist/configManager.d.ts +33 -2
- package/dist/mcpCommands.cjs +2 -0
- package/dist/mcpCommands.cjs.map +1 -0
- package/dist/mcpCommands.d.ts +19 -0
- package/dist/mcpPipe.cjs +6 -262
- package/dist/mcpPipe.cjs.map +1 -1
- package/dist/mcpServerProxy.cjs +6 -491
- package/dist/mcpServerProxy.cjs.map +1 -1
- package/docs/CLI.md +189 -0
- package/docs/SettingManager.md +122 -0
- package/docs/images/preview.png +0 -0
- package/package.json +44 -22
- package/templates/hello-world/mcpServers/calculator.js +100 -0
- package/templates/hello-world/mcpServers/datetime.js +384 -0
- package/templates/hello-world/package.json +12 -0
- package/dist/mcpServers/calculator.js +0 -96
- package/dist/mcpServers/datetime.js +0 -354
- /package/dist/{config.default.json → xiaozhi.config.default.json} +0 -0
- /package/{dist/config.json → templates/hello-world/xiaozhi.config.json} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcpServerProxy.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * MCP Server Proxy - JavaScript Implementation\n * Provides a proxy to aggregate multiple MCP servers dynamically from configuration\n * Version: 0.3.0 - Manual JSON-RPC 2.0 implementation (no SDK) with dynamic config\n */\n\nimport { spawn, ChildProcess } from 'child_process';\nimport { readFileSync } from 'fs';\nimport { resolve, dirname } from 'path';\nimport process from 'process';\nimport { configManager, MCPServerConfig } from './configManager.js';\n\n// CommonJS 兼容的 __dirname\nconst __dirname = dirname(__filename);\n\n// Simple logger utility\nconst logger = {\n info: (message: string): void => {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - MCPProxy - INFO - ${message}`);\n },\n error: (message: string): void => {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - MCPProxy - ERROR - ${message}`);\n },\n debug: (message: string): void => {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - MCPProxy - DEBUG - ${message}`);\n }\n};\n\n// Type definitions\n\ninterface Tool {\n name: string;\n description?: string;\n inputSchema?: any;\n}\n\ninterface PendingRequest {\n resolve: (value: any) => void;\n reject: (reason: any) => void;\n}\n\n/**\n * MCP Client for communicating with child MCP servers\n */\nclass MCPClient {\n private name: string;\n private config: MCPServerConfig;\n private process: ChildProcess | null;\n public initialized: boolean;\n public tools: Tool[];\n private requestId: number;\n private pendingRequests: Map<number, PendingRequest>;\n private messageBuffer: string;\n\n constructor(name: string, config: MCPServerConfig) {\n this.name = name;\n this.config = config;\n this.process = null;\n this.initialized = false;\n this.tools = [];\n this.requestId = 1;\n this.pendingRequests = new Map();\n this.messageBuffer = '';\n }\n\n async start() {\n logger.info(`Starting MCP client for ${this.name}`);\n\n const { command, args, env } = this.config;\n const spawnOptions: any = {\n stdio: ['pipe', 'pipe', 'pipe']\n };\n\n // Add environment variables if specified\n if (env) {\n spawnOptions.env = { ...process.env, ...env };\n }\n\n this.process = spawn(command, args, spawnOptions);\n\n // Handle process stdout - parse JSON-RPC messages\n this.process.stdout?.on('data', (data: Buffer) => {\n this.handleStdoutData(data.toString());\n });\n\n // Handle process stderr - log errors\n this.process.stderr?.on('data', (data: Buffer) => {\n logger.debug(`${this.name} stderr: ${data.toString().trim()}`);\n });\n\n // Handle process exit\n this.process.on('exit', (code: number | null, signal: NodeJS.Signals | null) => {\n logger.error(`${this.name} process exited with code ${code}, signal ${signal}`);\n this.initialized = false;\n });\n\n // Handle process error\n this.process.on('error', (error: Error) => {\n logger.error(`${this.name} process error: ${error.message}`);\n this.initialized = false;\n });\n\n // Initialize the MCP connection\n await this.initialize();\n }\n\n handleStdoutData(data: string): void {\n this.messageBuffer += data;\n\n // Split by newlines and process complete messages\n const lines = this.messageBuffer.split('\\n');\n this.messageBuffer = lines.pop() || ''; // Keep incomplete line in buffer\n\n for (const line of lines) {\n if (line.trim()) {\n try {\n const message = JSON.parse(line.trim());\n this.handleMessage(message);\n } catch (error) {\n logger.error(`${this.name} failed to parse message: ${line.trim()}`);\n }\n }\n }\n }\n\n handleMessage(message: any): void {\n logger.debug(`${this.name} received: ${JSON.stringify(message).substring(0, 200)}...`);\n\n if (message.id && this.pendingRequests.has(message.id)) {\n // This is a response to our request\n const pendingRequest = this.pendingRequests.get(message.id);\n if (pendingRequest) {\n const { resolve, reject } = pendingRequest;\n this.pendingRequests.delete(message.id);\n\n if (message.error) {\n reject(new Error(`${message.error.message} (code: ${message.error.code})`));\n } else {\n resolve(message.result);\n }\n }\n }\n // Note: We don't handle notifications or requests from child servers in this proxy\n }\n\n async sendRequest(method: string, params: any = {}): Promise<any> {\n if (!this.process || !this.process.stdin) {\n throw new Error(`${this.name} process not available`);\n }\n\n const id = this.requestId++;\n const request = {\n jsonrpc: \"2.0\",\n id: id,\n method: method,\n params: params\n };\n\n return new Promise((resolve, reject) => {\n this.pendingRequests.set(id, { resolve, reject });\n\n // Set timeout for request\n setTimeout(() => {\n if (this.pendingRequests.has(id)) {\n this.pendingRequests.delete(id);\n reject(new Error(`Request timeout for ${method}`));\n }\n }, 30000); // 30 second timeout\n\n const message = JSON.stringify(request) + '\\n';\n logger.debug(`${this.name} sending: ${message.trim()}`);\n this.process!.stdin!.write(message);\n });\n }\n\n async initialize() {\n try {\n // Send initialize request\n const initResult = await this.sendRequest('initialize', {\n protocolVersion: \"2024-11-05\",\n capabilities: {},\n clientInfo: {\n name: \"MCPProxy\",\n version: \"0.3.0\"\n }\n });\n\n logger.info(`${this.name} initialized with capabilities: ${JSON.stringify((initResult as any).capabilities)}`);\n\n // Send initialized notification\n const notification = {\n jsonrpc: \"2.0\",\n method: \"notifications/initialized\"\n };\n this.process!.stdin!.write(JSON.stringify(notification) + '\\n');\n\n // Get tools list\n await this.refreshTools();\n\n this.initialized = true;\n logger.info(`${this.name} client ready with ${this.tools.length} tools`);\n } catch (error) {\n logger.error(`Failed to initialize ${this.name}: ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n }\n\n async refreshTools(): Promise<void> {\n try {\n const result = await this.sendRequest('tools/list');\n this.tools = (result as any).tools || [];\n logger.info(`${this.name} loaded ${this.tools.length} tools: ${this.tools.map(t => t.name).join(', ')}`);\n } catch (error) {\n logger.error(`Failed to get tools from ${this.name}: ${error instanceof Error ? error.message : String(error)}`);\n this.tools = [];\n }\n }\n\n async callTool(name: string, arguments_: any): Promise<any> {\n try {\n const result = await this.sendRequest('tools/call', {\n name: name,\n arguments: arguments_\n });\n return result;\n } catch (error) {\n logger.error(`Failed to call tool ${name} on ${this.name}: ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n }\n\n stop(): void {\n if (this.process) {\n logger.info(`Stopping ${this.name} client`);\n this.process.kill('SIGTERM');\n this.process = null;\n }\n this.initialized = false;\n }\n}\n\n/**\n * Configuration loader for MCP servers\n */\nfunction loadMCPConfig(): Record<string, MCPServerConfig> {\n try {\n // 首先尝试从配置管理器读取\n if (configManager.configExists()) {\n const mcpServers = configManager.getMcpServers();\n logger.info(`从配置文件加载了 ${Object.keys(mcpServers).length} 个 MCP 服务`);\n return mcpServers as Record<string, MCPServerConfig>;\n }\n\n // 如果配置文件不存在,尝试从旧的 mcp_server.json 读取(向后兼容)\n const legacyConfigPath = resolve(__dirname, 'mcp_server.json');\n if (readFileSync) { // 检查是否可以读取文件\n try {\n const configData = readFileSync(legacyConfigPath, 'utf8');\n const config = JSON.parse(configData);\n\n if (!config.mcpServers || typeof config.mcpServers !== 'object') {\n throw new Error('Invalid configuration: mcpServers section not found or invalid');\n }\n\n logger.info(`从旧配置文件加载了 ${Object.keys(config.mcpServers).length} 个 MCP 服务(建议迁移到新配置格式)`);\n return config.mcpServers;\n } catch (legacyError) {\n // 旧配置文件也不存在或无效\n logger.error('配置文件不存在,请运行 \"xiaozhi init\" 初始化配置');\n throw new Error('配置文件不存在,请运行 \"xiaozhi init\" 初始化配置');\n }\n }\n\n throw new Error('配置文件不存在,请运行 \"xiaozhi init\" 初始化配置');\n } catch (error) {\n logger.error(`Failed to load MCP configuration: ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n}\n\n/**\n * MCP Server Proxy - Main proxy server implementation\n */\nclass MCPServerProxy {\n private clients: Map<string, MCPClient>;\n private toolMap: Map<string, string>; // Maps tool name to client name\n public initialized: boolean;\n private config: Record<string, MCPServerConfig> | null;\n\n constructor() {\n this.clients = new Map();\n this.toolMap = new Map(); // Maps tool name to client name\n this.initialized = false;\n this.config = null;\n }\n\n async start() {\n logger.info(\"Starting MCP Server Proxy\");\n\n // Load configuration\n this.config = loadMCPConfig();\n\n // Initialize child MCP clients from configuration\n const clientPromises = [];\n\n for (const [serverName, serverConfig] of Object.entries(this.config)) {\n logger.info(`Initializing MCP client: ${serverName}`);\n const client = new MCPClient(serverName, serverConfig);\n this.clients.set(serverName, client);\n clientPromises.push(client.start());\n }\n\n // Start all clients\n try {\n const results = await Promise.allSettled(clientPromises);\n\n // Check for failed clients\n let successCount = 0;\n for (let i = 0; i < results.length; i++) {\n const result = results[i];\n const serverName = Object.keys(this.config)[i];\n\n if (result.status === 'fulfilled') {\n successCount++;\n logger.info(`Successfully started MCP client: ${serverName}`);\n } else {\n logger.error(`Failed to start MCP client ${serverName}: ${result.reason.message}`);\n // Remove failed client from clients map\n this.clients.delete(serverName);\n }\n }\n\n if (successCount === 0) {\n throw new Error(\"No MCP clients started successfully\");\n }\n\n // Build tool mapping\n this.buildToolMap();\n this.initialized = true;\n\n logger.info(`MCP Server Proxy initialized successfully with ${successCount}/${Object.keys(this.config).length} clients`);\n } catch (error) {\n logger.error(`Failed to start MCP clients: ${error instanceof Error ? error.message : String(error)}`);\n throw error;\n }\n }\n\n buildToolMap() {\n this.toolMap.clear();\n\n for (const [clientName, client] of this.clients) {\n for (const tool of client.tools) {\n if (this.toolMap.has(tool.name)) {\n logger.error(`Duplicate tool name: ${tool.name} (from ${clientName} and ${this.toolMap.get(tool.name)})`);\n } else {\n this.toolMap.set(tool.name, clientName);\n }\n }\n }\n\n logger.info(`Built tool map with ${this.toolMap.size} tools`);\n }\n\n getAllTools(): Tool[] {\n const allTools: Tool[] = [];\n for (const client of this.clients.values()) {\n allTools.push(...client.tools);\n }\n return allTools;\n }\n\n async callTool(toolName: string, arguments_: any): Promise<any> {\n const clientName = this.toolMap.get(toolName);\n if (!clientName) {\n throw new Error(`Unknown tool: ${toolName}`);\n }\n\n const client = this.clients.get(clientName);\n if (!client || !client.initialized) {\n throw new Error(`Client ${clientName} not available`);\n }\n\n return await client.callTool(toolName, arguments_);\n }\n\n stop() {\n logger.info(\"Stopping MCP Server Proxy\");\n for (const client of this.clients.values()) {\n client.stop();\n }\n this.initialized = false;\n }\n}\n\n/**\n * Manual JSON-RPC 2.0 Server Implementation\n */\nclass JSONRPCServer {\n private proxy: MCPServerProxy;\n private requestId: number;\n\n constructor(proxy: MCPServerProxy) {\n this.proxy = proxy;\n this.requestId = 1;\n }\n\n async handleMessage(message: string): Promise<string | null> {\n try {\n const parsedMessage = JSON.parse(message);\n logger.debug(`Received request: ${JSON.stringify(parsedMessage).substring(0, 200)}...`);\n\n if (parsedMessage.method) {\n if (parsedMessage.id !== undefined) {\n // This is a request\n const response = await this.handleRequest(parsedMessage);\n return JSON.stringify(response);\n } else {\n // This is a notification\n await this.handleNotification(parsedMessage);\n return null; // No response for notifications\n }\n } else {\n throw new Error(\"Invalid JSON-RPC message\");\n }\n } catch (error) {\n logger.error(`Error handling message: ${error instanceof Error ? error.message : String(error)}`);\n return JSON.stringify({\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32700,\n message: \"Parse error\"\n }\n });\n }\n }\n\n async handleRequest(request: any): Promise<any> {\n const { id, method, params = {} } = request;\n\n try {\n let result: any;\n\n switch (method) {\n case 'initialize':\n result = await this.handleInitialize(params);\n break;\n case 'tools/list':\n result = await this.handleToolsList(params);\n break;\n case 'tools/call':\n result = await this.handleToolsCall(params);\n break;\n case 'ping':\n result = await this.handlePing(params);\n break;\n default:\n throw new Error(`Unknown method: ${method}`);\n }\n\n return {\n jsonrpc: \"2.0\",\n id: id,\n result: result\n };\n } catch (error) {\n logger.error(`Error handling request ${method}: ${error instanceof Error ? error.message : String(error)}`);\n return {\n jsonrpc: \"2.0\",\n id: id,\n error: {\n code: -32603,\n message: error instanceof Error ? error.message : String(error)\n }\n };\n }\n }\n\n async handleNotification(notification: any): Promise<void> {\n const { method } = notification;\n\n switch (method) {\n case 'notifications/initialized':\n logger.info(\"Client sent initialized notification\");\n break;\n default:\n logger.debug(`Received notification: ${method}`);\n break;\n }\n }\n\n async handleInitialize(params: any): Promise<any> {\n logger.info(`Initialize request from client: ${JSON.stringify(params.clientInfo)}`);\n\n return {\n protocolVersion: \"2024-11-05\",\n capabilities: {\n tools: {\n listChanged: false\n }\n },\n serverInfo: {\n name: \"MCPServerProxy\",\n version: \"0.3.0\"\n }\n };\n }\n\n async handleToolsList(_params: any): Promise<any> {\n if (!this.proxy.initialized) {\n throw new Error(\"Proxy not initialized\");\n }\n\n const tools = this.proxy.getAllTools();\n logger.info(`Returning ${tools.length} tools`);\n\n return {\n tools: tools\n };\n }\n\n async handleToolsCall(params: any): Promise<any> {\n const { name, arguments: args } = params;\n\n if (!name) {\n throw new Error(\"Tool name is required\");\n }\n\n logger.info(`Calling tool: ${name} with args: ${JSON.stringify(args)}`);\n\n const result = await this.proxy.callTool(name, args || {});\n return result;\n }\n\n async handlePing(_params: any): Promise<any> {\n logger.debug(\"Received ping request\");\n return {}; // Empty response for ping\n }\n}\n\n/**\n * Main function to start the MCP Server Proxy\n */\nasync function main() {\n logger.info(\"Starting MCP Server Proxy\");\n\n // Create and start the proxy\n const proxy = new MCPServerProxy();\n const jsonrpcServer = new JSONRPCServer(proxy);\n\n // Setup graceful shutdown\n const cleanup = () => {\n logger.info(\"Shutting down MCP Server Proxy\");\n proxy.stop();\n process.exit(0);\n };\n\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n\n try {\n // Start the proxy (initialize child clients)\n await proxy.start();\n\n // Handle stdin/stdout communication\n process.stdin.setEncoding('utf8');\n\n let messageBuffer = '';\n\n process.stdin.on('data', async (data) => {\n messageBuffer += data;\n\n // Split by newlines and process complete messages\n const lines = messageBuffer.split('\\n');\n messageBuffer = lines.pop() || ''; // Keep incomplete line in buffer\n\n for (const line of lines) {\n if (line.trim()) {\n try {\n const response = await jsonrpcServer.handleMessage(line.trim());\n if (response) {\n process.stdout.write(response + '\\n');\n }\n } catch (error) {\n logger.error(`Error processing message: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n }\n });\n\n process.stdin.on('end', () => {\n logger.info(\"stdin closed, shutting down\");\n cleanup();\n });\n\n logger.info(\"MCP Server Proxy is running on stdio\");\n\n } catch (error) {\n logger.error(`Failed to start MCP Server Proxy: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n}\n\n// Run the server if this file is executed directly\nif (require.main === module) {\n main().catch((error) => {\n logger.error(`Unhandled error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n });\n}\n"],"mappings":"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","names":["process","resolve"]}
|
|
1
|
+
{"version":3,"sources":["../src/mcpServerProxy.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * MCP Server Proxy - JavaScript Implementation\n * Provides a proxy to aggregate multiple MCP servers dynamically from configuration\n * Version: 0.3.0 - Manual JSON-RPC 2.0 implementation (no SDK) with dynamic config\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport process from \"node:process\";\nimport {\n type MCPServerConfig,\n type MCPToolConfig,\n configManager,\n} from \"./configManager.js\";\n\n// CommonJS 兼容的 __dirname\nconst __dirname = dirname(__filename);\n\n// Simple logger utility\nconst logger = {\n info: (message: string): void => {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - MCPProxy - INFO - ${message}`);\n },\n error: (message: string): void => {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - MCPProxy - ERROR - ${message}`);\n },\n debug: (message: string): void => {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - MCPProxy - DEBUG - ${message}`);\n },\n};\n\n// Type definitions\n\ninterface Tool {\n name: string;\n description?: string;\n inputSchema?: any;\n}\n\ninterface PendingRequest {\n resolve: (value: any) => void;\n reject: (reason: any) => void;\n}\n\n/**\n * MCP Client for communicating with child MCP servers\n */\nclass MCPClient {\n private name: string;\n private config: MCPServerConfig;\n private process: ChildProcess | null;\n public initialized: boolean;\n public tools: Tool[];\n public originalTools: Tool[]; // 存储原始工具名称\n private requestId: number;\n private pendingRequests: Map<number, PendingRequest>;\n private messageBuffer: string;\n\n constructor(name: string, config: MCPServerConfig) {\n this.name = name;\n this.config = config;\n this.process = null;\n this.initialized = false;\n this.tools = [];\n this.originalTools = [];\n this.requestId = 1;\n this.pendingRequests = new Map();\n this.messageBuffer = \"\";\n }\n\n /**\n * 生成带前缀的工具名称\n * 将服务器名称中的中划线替换为下划线,并添加 xzcli 前缀\n */\n private generatePrefixedToolName(originalToolName: string): string {\n const normalizedServerName = this.name.replace(/-/g, \"_\");\n return `${normalizedServerName}_xzcli_${originalToolName}`;\n }\n\n /**\n * 根据前缀工具名称获取原始工具名称\n */\n getOriginalToolName(prefixedToolName: string): string | null {\n const normalizedServerName = this.name.replace(/-/g, \"_\");\n const prefix = `${normalizedServerName}_xzcli_`;\n\n if (prefixedToolName.startsWith(prefix)) {\n return prefixedToolName.substring(prefix.length);\n }\n\n return null;\n }\n\n async start() {\n logger.info(`Starting MCP client for ${this.name}`);\n\n const { command, args, env } = this.config;\n const spawnOptions: any = {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n };\n\n // Set working directory to user's current working directory\n // This ensures relative paths in MCP server configs are resolved correctly\n const userWorkingDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n spawnOptions.cwd = userWorkingDir;\n\n // Add environment variables if specified\n if (env) {\n spawnOptions.env = { ...process.env, ...env };\n } else {\n spawnOptions.env = { ...process.env };\n }\n\n this.process = spawn(command, args, spawnOptions);\n\n // Handle process stdout - parse JSON-RPC messages\n this.process.stdout?.on(\"data\", (data: Buffer) => {\n this.handleStdoutData(data.toString());\n });\n\n // Handle process stderr - log errors\n this.process.stderr?.on(\"data\", (data: Buffer) => {\n logger.debug(`${this.name} stderr: ${data.toString().trim()}`);\n });\n\n // Handle process exit\n this.process.on(\n \"exit\",\n (code: number | null, signal: NodeJS.Signals | null) => {\n logger.error(\n `${this.name} process exited with code ${code}, signal ${signal}`\n );\n this.initialized = false;\n }\n );\n\n // Handle process error\n this.process.on(\"error\", (error: Error) => {\n logger.error(`${this.name} process error: ${error.message}`);\n this.initialized = false;\n });\n\n // Initialize the MCP connection\n await this.initialize();\n }\n\n handleStdoutData(data: string): void {\n this.messageBuffer = `${this.messageBuffer}${data}`;\n\n // Split by newlines and process complete messages\n const lines = this.messageBuffer.split(\"\\n\");\n this.messageBuffer = lines.pop() || \"\"; // Keep incomplete line in buffer\n\n for (const line of lines) {\n if (line.trim()) {\n try {\n const message = JSON.parse(line.trim());\n this.handleMessage(message);\n } catch (error) {\n logger.error(`${this.name} failed to parse message: ${line.trim()}`);\n }\n }\n }\n }\n\n handleMessage(message: any): void {\n logger.debug(\n `${this.name} received: ${JSON.stringify(message).substring(0, 200)}...`\n );\n\n if (message.id && this.pendingRequests.has(message.id)) {\n // This is a response to our request\n const pendingRequest = this.pendingRequests.get(message.id);\n if (pendingRequest) {\n const { resolve, reject } = pendingRequest;\n this.pendingRequests.delete(message.id);\n\n if (message.error) {\n reject(\n new Error(`${message.error.message} (code: ${message.error.code})`)\n );\n } else {\n resolve(message.result);\n }\n }\n }\n // Note: We don't handle notifications or requests from child servers in this proxy\n }\n\n async sendRequest(method: string, params: any = {}): Promise<any> {\n if (!this.process || !this.process.stdin) {\n throw new Error(`${this.name} process not available`);\n }\n\n const id = this.requestId++;\n const request = {\n jsonrpc: \"2.0\",\n id: id,\n method: method,\n params: params,\n };\n\n return new Promise((resolve, reject) => {\n this.pendingRequests.set(id, { resolve, reject });\n\n // Set timeout for request\n setTimeout(() => {\n if (this.pendingRequests.has(id)) {\n this.pendingRequests.delete(id);\n reject(new Error(`Request timeout for ${method}`));\n }\n }, 30000); // 30 second timeout\n\n const message = `${JSON.stringify(request)}\\n`;\n logger.debug(`${this.name} sending: ${message.trim()}`);\n this.process?.stdin?.write(message);\n });\n }\n\n async initialize() {\n try {\n // Send initialize request\n const initResult = await this.sendRequest(\"initialize\", {\n protocolVersion: \"2024-11-05\",\n capabilities: {},\n clientInfo: {\n name: \"MCPProxy\",\n version: \"0.3.0\",\n },\n });\n\n logger.info(\n `${this.name} initialized with capabilities: ${JSON.stringify((initResult as any).capabilities)}`\n );\n\n // Send initialized notification\n const notification = {\n jsonrpc: \"2.0\",\n method: \"notifications/initialized\",\n };\n this.process?.stdin?.write(`${JSON.stringify(notification)}\\n`);\n\n // Get tools list\n await this.refreshTools();\n\n this.initialized = true;\n logger.info(`${this.name} client ready with ${this.tools.length} tools`);\n } catch (error) {\n logger.error(\n `Failed to initialize ${this.name}: ${error instanceof Error ? error.message : String(error)}`\n );\n throw error;\n }\n }\n\n async refreshTools(): Promise<void> {\n try {\n const result = await this.sendRequest(\"tools/list\");\n this.originalTools = (result as any).tools || [];\n\n // 为每个工具生成带前缀的名称,并应用过滤\n const allPrefixedTools = this.originalTools.map((tool) => ({\n ...tool,\n name: this.generatePrefixedToolName(tool.name),\n }));\n\n // 根据配置过滤工具\n this.tools = this.filterEnabledTools(allPrefixedTools);\n\n // 更新配置文件中的工具列表(如果需要)\n await this.updateToolsConfig();\n\n logger.info(\n `${this.name} loaded ${this.originalTools.length} tools: ${this.originalTools.map((t) => t.name).join(\", \")}`\n );\n logger.info(\n `${this.name} enabled ${this.tools.length} tools: ${this.tools.map((t) => t.name).join(\", \")}`\n );\n } catch (error) {\n logger.error(\n `Failed to get tools from ${this.name}: ${error instanceof Error ? error.message : String(error)}`\n );\n this.tools = [];\n this.originalTools = [];\n }\n }\n\n /**\n * 过滤启用的工具\n */\n private filterEnabledTools(allTools: Tool[]): Tool[] {\n return allTools.filter((tool) => {\n const originalName = this.getOriginalToolName(tool.name);\n if (!originalName) return true; // 如果无法解析原始名称,默认启用\n\n return configManager.isToolEnabled(this.name, originalName);\n });\n }\n\n /**\n * 更新配置文件中的工具列表\n */\n private async updateToolsConfig(): Promise<void> {\n try {\n const currentConfig = configManager.getServerToolsConfig(this.name);\n const toolsConfig: Record<string, MCPToolConfig> = {};\n\n // 为每个工具创建配置项\n for (const tool of this.originalTools) {\n const existingConfig = currentConfig[tool.name];\n toolsConfig[tool.name] = {\n description: tool.description || \"\",\n enable: existingConfig?.enable !== false, // 默认启用\n };\n }\n\n // 只有当配置发生变化时才更新\n const hasChanges = Object.keys(toolsConfig).some((toolName) => {\n const existing = currentConfig[toolName];\n const newConfig = toolsConfig[toolName];\n return (\n !existing ||\n existing.enable !== newConfig.enable ||\n existing.description !== newConfig.description\n );\n });\n\n if (hasChanges || Object.keys(currentConfig).length === 0) {\n configManager.updateServerToolsConfig(this.name, toolsConfig);\n logger.info(`${this.name} updated tools configuration`);\n }\n } catch (error) {\n logger.error(\n `Failed to update tools config for ${this.name}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n async callTool(prefixedName: string, arguments_: any): Promise<any> {\n try {\n // 将前缀名称转换回原始名称\n const originalName = this.getOriginalToolName(prefixedName);\n if (!originalName) {\n throw new Error(`Invalid tool name format: ${prefixedName}`);\n }\n\n const result = await this.sendRequest(\"tools/call\", {\n name: originalName,\n arguments: arguments_,\n });\n return result;\n } catch (error) {\n logger.error(\n `Failed to call tool ${prefixedName} (original: ${this.getOriginalToolName(prefixedName)}) on ${this.name}: ${error instanceof Error ? error.message : String(error)}`\n );\n throw error;\n }\n }\n\n stop(): void {\n if (this.process) {\n logger.info(`Stopping ${this.name} client`);\n this.process.kill(\"SIGTERM\");\n this.process = null;\n }\n this.initialized = false;\n }\n}\n\n/**\n * Configuration loader for MCP servers\n */\nfunction loadMCPConfig(): Record<string, MCPServerConfig> {\n try {\n // 首先尝试从配置管理器读取\n if (configManager.configExists()) {\n const mcpServers = configManager.getMcpServers();\n logger.info(\n `从配置文件加载了 ${Object.keys(mcpServers).length} 个 MCP 服务`\n );\n return mcpServers as Record<string, MCPServerConfig>;\n }\n\n // 如果配置文件不存在,尝试从旧的 mcp_server.json 读取(向后兼容)\n const legacyConfigPath = resolve(__dirname, \"mcp_server.json\");\n if (readFileSync) {\n // 检查是否可以读取文件\n try {\n const configData = readFileSync(legacyConfigPath, \"utf8\");\n const config = JSON.parse(configData);\n\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n throw new Error(\n \"Invalid configuration: mcpServers section not found or invalid\"\n );\n }\n\n logger.info(\n `从旧配置文件加载了 ${Object.keys(config.mcpServers).length} 个 MCP 服务(建议迁移到新配置格式)`\n );\n return config.mcpServers;\n } catch (legacyError) {\n // 旧配置文件也不存在或无效\n logger.error('配置文件不存在,请运行 \"xiaozhi init\" 初始化配置');\n throw new Error('配置文件不存在,请运行 \"xiaozhi init\" 初始化配置');\n }\n }\n\n throw new Error('配置文件不存在,请运行 \"xiaozhi init\" 初始化配置');\n } catch (error) {\n logger.error(\n `Failed to load MCP configuration: ${error instanceof Error ? error.message : String(error)}`\n );\n throw error;\n }\n}\n\n/**\n * MCP Server Proxy - Main proxy server implementation\n */\nclass MCPServerProxy {\n private clients: Map<string, MCPClient>;\n private toolMap: Map<string, string>; // Maps tool name to client name\n public initialized: boolean;\n private config: Record<string, MCPServerConfig> | null;\n\n constructor() {\n this.clients = new Map();\n this.toolMap = new Map(); // Maps tool name to client name\n this.initialized = false;\n this.config = null;\n }\n\n async start() {\n logger.info(\"Starting MCP Server Proxy\");\n\n // Load configuration\n this.config = loadMCPConfig();\n\n // Initialize child MCP clients from configuration\n const clientPromises = [];\n\n for (const [serverName, serverConfig] of Object.entries(this.config)) {\n logger.info(`Initializing MCP client: ${serverName}`);\n const client = new MCPClient(serverName, serverConfig);\n this.clients.set(serverName, client);\n clientPromises.push(client.start());\n }\n\n // Start all clients\n try {\n const results = await Promise.allSettled(clientPromises);\n\n // Check for failed clients\n let successCount = 0;\n for (let i = 0; i < results.length; i++) {\n const result = results[i];\n const serverName = Object.keys(this.config)[i];\n\n if (result.status === \"fulfilled\") {\n successCount++;\n logger.info(`Successfully started MCP client: ${serverName}`);\n } else {\n logger.error(\n `Failed to start MCP client ${serverName}: ${result.reason.message}`\n );\n // Remove failed client from clients map\n this.clients.delete(serverName);\n }\n }\n\n if (successCount === 0) {\n throw new Error(\"No MCP clients started successfully\");\n }\n\n // Build tool mapping\n this.buildToolMap();\n this.initialized = true;\n\n logger.info(\n `MCP Server Proxy initialized successfully with ${successCount}/${Object.keys(this.config).length} clients`\n );\n } catch (error) {\n logger.error(\n `Failed to start MCP clients: ${error instanceof Error ? error.message : String(error)}`\n );\n throw error;\n }\n }\n\n buildToolMap() {\n this.toolMap.clear();\n\n for (const [clientName, client] of this.clients) {\n for (const tool of client.tools) {\n // 工具名称现在已经带有前缀,应该不会有重复\n // 但我们仍然检查以防万一\n if (this.toolMap.has(tool.name)) {\n logger.error(\n `Duplicate tool name: ${tool.name} (from ${clientName} and ${this.toolMap.get(tool.name)})`\n );\n } else {\n this.toolMap.set(tool.name, clientName);\n }\n }\n }\n\n logger.info(`Built tool map with ${this.toolMap.size} tools`);\n logger.debug(`Tool map: ${Array.from(this.toolMap.keys()).join(\", \")}`);\n }\n\n getAllTools(): Tool[] {\n const allTools: Tool[] = [];\n for (const client of this.clients.values()) {\n allTools.push(...client.tools);\n }\n return allTools;\n }\n\n /**\n * 获取所有服务器的信息\n */\n getAllServers(): Array<{\n name: string;\n toolCount: number;\n enabledToolCount: number;\n }> {\n const servers: Array<{\n name: string;\n toolCount: number;\n enabledToolCount: number;\n }> = [];\n\n for (const [serverName, client] of this.clients) {\n servers.push({\n name: serverName,\n toolCount: client.originalTools.length,\n enabledToolCount: client.tools.length,\n });\n }\n\n return servers;\n }\n\n /**\n * 获取指定服务器的工具信息\n */\n getServerTools(\n serverName: string\n ): Array<{ name: string; description: string; enabled: boolean }> {\n const client = this.clients.get(serverName);\n if (!client) {\n throw new Error(`Server ${serverName} not found`);\n }\n\n return client.originalTools.map((tool) => ({\n name: tool.name,\n description: tool.description || \"\",\n enabled: configManager.isToolEnabled(serverName, tool.name),\n }));\n }\n\n /**\n * 刷新指定服务器的工具列表\n */\n async refreshServerTools(serverName: string): Promise<void> {\n const client = this.clients.get(serverName);\n if (!client) {\n throw new Error(`Server ${serverName} not found`);\n }\n\n await client.refreshTools();\n this.buildToolMap(); // 重新构建工具映射\n }\n\n /**\n * 刷新所有服务器的工具列表\n */\n async refreshAllTools(): Promise<void> {\n const refreshPromises = Array.from(this.clients.values()).map((client) =>\n client.refreshTools()\n );\n await Promise.allSettled(refreshPromises);\n this.buildToolMap(); // 重新构建工具映射\n }\n\n async callTool(toolName: string, arguments_: any): Promise<any> {\n const clientName = this.toolMap.get(toolName);\n if (!clientName) {\n throw new Error(`Unknown tool: ${toolName}`);\n }\n\n const client = this.clients.get(clientName);\n if (!client || !client.initialized) {\n throw new Error(`Client ${clientName} not available`);\n }\n\n return await client.callTool(toolName, arguments_);\n }\n\n stop() {\n logger.info(\"Stopping MCP Server Proxy\");\n for (const client of this.clients.values()) {\n client.stop();\n }\n this.initialized = false;\n }\n}\n\n/**\n * Manual JSON-RPC 2.0 Server Implementation\n */\nclass JSONRPCServer {\n private proxy: MCPServerProxy;\n private requestId: number;\n\n constructor(proxy: MCPServerProxy) {\n this.proxy = proxy;\n this.requestId = 1;\n }\n\n async handleMessage(message: string): Promise<string | null> {\n try {\n const parsedMessage = JSON.parse(message);\n logger.debug(\n `Received request: ${JSON.stringify(parsedMessage).substring(0, 200)}...`\n );\n\n if (parsedMessage.method) {\n if (parsedMessage.id !== undefined) {\n // This is a request\n const response = await this.handleRequest(parsedMessage);\n return JSON.stringify(response);\n }\n // This is a notification\n await this.handleNotification(parsedMessage);\n return null; // No response for notifications\n }\n throw new Error(\"Invalid JSON-RPC message\");\n } catch (error) {\n logger.error(\n `Error handling message: ${error instanceof Error ? error.message : String(error)}`\n );\n return JSON.stringify({\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32700,\n message: \"Parse error\",\n },\n });\n }\n }\n\n async handleRequest(request: any): Promise<any> {\n const { id, method, params = {} } = request;\n\n try {\n let result: any;\n\n switch (method) {\n case \"initialize\":\n result = await this.handleInitialize(params);\n break;\n case \"tools/list\":\n result = await this.handleToolsList(params);\n break;\n case \"tools/call\":\n result = await this.handleToolsCall(params);\n break;\n case \"ping\":\n result = await this.handlePing(params);\n break;\n default:\n throw new Error(`Unknown method: ${method}`);\n }\n\n return {\n jsonrpc: \"2.0\",\n id: id,\n result: result,\n };\n } catch (error) {\n logger.error(\n `Error handling request ${method}: ${error instanceof Error ? error.message : String(error)}`\n );\n return {\n jsonrpc: \"2.0\",\n id: id,\n error: {\n code: -32603,\n message: error instanceof Error ? error.message : String(error),\n },\n };\n }\n }\n\n async handleNotification(notification: any): Promise<void> {\n const { method } = notification;\n\n switch (method) {\n case \"notifications/initialized\":\n logger.info(\"Client sent initialized notification\");\n break;\n default:\n logger.debug(`Received notification: ${method}`);\n break;\n }\n }\n\n async handleInitialize(params: any): Promise<any> {\n logger.info(\n `Initialize request from client: ${JSON.stringify(params.clientInfo)}`\n );\n\n return {\n protocolVersion: \"2024-11-05\",\n capabilities: {\n tools: {\n listChanged: false,\n },\n },\n serverInfo: {\n name: \"MCPServerProxy\",\n version: \"0.3.0\",\n },\n };\n }\n\n async handleToolsList(_params: any): Promise<any> {\n if (!this.proxy.initialized) {\n throw new Error(\"Proxy not initialized\");\n }\n\n const tools = this.proxy.getAllTools();\n logger.info(`Returning ${tools.length} tools`);\n\n return {\n tools: tools,\n };\n }\n\n async handleToolsCall(params: any): Promise<any> {\n const { name, arguments: args } = params;\n\n if (!name) {\n throw new Error(\"Tool name is required\");\n }\n\n logger.info(`Calling tool: ${name} with args: ${JSON.stringify(args)}`);\n\n const result = await this.proxy.callTool(name, args || {});\n return result;\n }\n\n async handlePing(_params: any): Promise<any> {\n logger.debug(\"Received ping request\");\n return {}; // Empty response for ping\n }\n}\n\n/**\n * Main function to start the MCP Server Proxy\n */\nasync function main() {\n logger.info(\"Starting MCP Server Proxy\");\n\n // Create and start the proxy\n const proxy = new MCPServerProxy();\n const jsonrpcServer = new JSONRPCServer(proxy);\n\n // Setup graceful shutdown\n const cleanup = () => {\n logger.info(\"Shutting down MCP Server Proxy\");\n proxy.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n\n try {\n // Start the proxy (initialize child clients)\n await proxy.start();\n\n // Handle stdin/stdout communication\n process.stdin.setEncoding(\"utf8\");\n\n let messageBuffer = \"\";\n\n process.stdin.on(\"data\", async (data) => {\n messageBuffer = `${messageBuffer}${data}`;\n\n // Split by newlines and process complete messages\n const lines = messageBuffer.split(\"\\n\");\n messageBuffer = lines.pop() || \"\"; // Keep incomplete line in buffer\n\n for (const line of lines) {\n if (line.trim()) {\n try {\n const response = await jsonrpcServer.handleMessage(line.trim());\n if (response) {\n process.stdout.write(`${response}\\n`);\n }\n } catch (error) {\n logger.error(\n `Error processing message: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n }\n });\n\n process.stdin.on(\"end\", () => {\n logger.info(\"stdin closed, shutting down\");\n cleanup();\n });\n\n logger.info(\"MCP Server Proxy is running on stdio\");\n } catch (error) {\n logger.error(\n `Failed to start MCP Server Proxy: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n}\n\n// Run the server if this file is executed directly\nif (require.main === module) {\n main().catch((error) => {\n logger.error(\n `Unhandled error: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n });\n}\n"],"mappings":"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","names":["import_node_child_process","import_node_fs","import_node_path","import_node_process","import_configManager","__dirname","logger","__name","message","timestamp","MCPClient","name","config","originalToolName","prefixedToolName","prefix","command","args","env","spawnOptions","userWorkingDir","process","data","code","signal","error","lines","line","pendingRequest","resolve","reject","method","params","id","request","initResult","notification","result","allPrefixedTools","tool","t","allTools","originalName","currentConfig","toolsConfig","existingConfig","toolName","existing","newConfig","prefixedName","arguments_","loadMCPConfig","mcpServers","legacyConfigPath","configData","MCPServerProxy","clientPromises","serverName","serverConfig","client","results","successCount","i","clientName","servers","refreshPromises","JSONRPCServer","proxy","parsedMessage","response","_params","tools","main","jsonrpcServer","cleanup","messageBuffer"]}
|
package/docs/CLI.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Xiaozhi CLI 使用文档
|
|
2
|
+
|
|
3
|
+
`xiaozhi` 是小智AI客户端的命令行工具,提供配置管理和服务管理功能。
|
|
4
|
+
|
|
5
|
+
## 概述
|
|
6
|
+
|
|
7
|
+
小智的架构比较特别:它将您的个人电脑作为AI服务端,远端的小智服务器实际上是客户端。当您启动小智服务后,您的电脑就成为了AI的"大脑",为远端提供各种工具和能力。
|
|
8
|
+
|
|
9
|
+
## 安装
|
|
10
|
+
|
|
11
|
+
在项目根目录下运行:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 使用方法
|
|
18
|
+
|
|
19
|
+
### 基本命令
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
xiaozhi --help # 显示帮助信息
|
|
23
|
+
xiaozhi --version # 显示版本信息
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 服务管理
|
|
27
|
+
|
|
28
|
+
#### 启动服务
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
xiaozhi start # 在前台启动服务
|
|
32
|
+
xiaozhi start -d # 在后台启动服务(守护进程模式)
|
|
33
|
+
xiaozhi start --daemon # 同上,完整参数形式
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**示例:**
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# 前台启动(按 Ctrl+C 停止)
|
|
40
|
+
xiaozhi start
|
|
41
|
+
|
|
42
|
+
# 后台启动
|
|
43
|
+
xiaozhi start -d
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
#### 停止服务
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
xiaozhi stop # 停止后台运行的服务
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### 查看服务状态
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
xiaozhi status # 查看服务运行状态和配置信息
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### 重启服务
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
xiaozhi restart # 重启服务(前台模式)
|
|
62
|
+
xiaozhi restart -d # 重启服务(后台模式)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
#### 前台/后台切换
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
xiaozhi attach # 将后台服务转到前台运行
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**注意:** `attach` 命令会先停止后台服务,然后在前台重新启动。
|
|
72
|
+
|
|
73
|
+
### 配置管理
|
|
74
|
+
|
|
75
|
+
#### 设置配置项
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
xiaozhi set-config <key>=<value>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**示例:**
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# 设置小智API端点
|
|
85
|
+
xiaozhi set-config xiaozhi.endpoint=wss://api.xiaozhi.me/mcp
|
|
86
|
+
|
|
87
|
+
# 设置嵌套配置
|
|
88
|
+
xiaozhi set-config mcpServers.myserver.command=node
|
|
89
|
+
|
|
90
|
+
# 包含特殊字符的值需要用引号包围
|
|
91
|
+
xiaozhi set-config "xiaozhi.endpoint=wss://api.xiaozhi.me/mcp/?token=abc123"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
#### 获取配置项
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
xiaozhi get-config [key]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**示例:**
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# 获取特定配置项
|
|
104
|
+
xiaozhi get-config xiaozhi.endpoint
|
|
105
|
+
|
|
106
|
+
# 获取所有配置
|
|
107
|
+
xiaozhi get-config
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 配置文件
|
|
111
|
+
|
|
112
|
+
配置文件位于 `.xiaozhi/settings.json`,支持嵌套结构:
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"xiaozhi": {
|
|
117
|
+
"endpoint": "wss://api.xiaozhi.me/mcp/?token=..."
|
|
118
|
+
},
|
|
119
|
+
"mcpServers": {
|
|
120
|
+
"amap-maps": {
|
|
121
|
+
"command": "npx",
|
|
122
|
+
"args": ["-y", "@amap/amap-maps-mcp-server"],
|
|
123
|
+
"env": {
|
|
124
|
+
"AMAP_MAPS_API_KEY": "your-api-key"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## 支持的配置键
|
|
132
|
+
|
|
133
|
+
- `xiaozhi.endpoint` - 小智API WebSocket端点地址
|
|
134
|
+
- `mcpServers.*` - MCP服务器配置
|
|
135
|
+
|
|
136
|
+
## 服务管理详解
|
|
137
|
+
|
|
138
|
+
### 前台 vs 后台模式
|
|
139
|
+
|
|
140
|
+
- **前台模式**: 服务在当前终端窗口运行,可以看到实时日志,按 `Ctrl+C` 停止
|
|
141
|
+
- **后台模式**: 服务在后台运行,不占用终端,需要使用 `xiaozhi stop` 停止
|
|
142
|
+
|
|
143
|
+
### 进程管理
|
|
144
|
+
|
|
145
|
+
小智使用 PID 文件(`.xiaozhi/xiaozhi.pid`)来跟踪后台进程:
|
|
146
|
+
|
|
147
|
+
- 启动服务时会检查是否已有服务在运行,防止重复启动
|
|
148
|
+
- 停止服务时会清理 PID 文件
|
|
149
|
+
- 如果进程异常退出,下次启动时会自动清理无效的 PID 文件
|
|
150
|
+
|
|
151
|
+
### 常见使用场景
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# 开发调试:前台启动,查看实时日志
|
|
155
|
+
xiaozhi start
|
|
156
|
+
|
|
157
|
+
# 生产使用:后台启动,持续运行
|
|
158
|
+
xiaozhi start -d
|
|
159
|
+
|
|
160
|
+
# 检查服务状态
|
|
161
|
+
xiaozhi status
|
|
162
|
+
|
|
163
|
+
# 查看后台日志(需要转到前台)
|
|
164
|
+
xiaozhi attach
|
|
165
|
+
|
|
166
|
+
# 重启服务(比如更新配置后)
|
|
167
|
+
xiaozhi restart -d
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 注意事项
|
|
171
|
+
|
|
172
|
+
1. **引号使用**: 当配置值包含特殊字符(如 `?`, `&`, `=` 等)时,需要用引号包围整个参数
|
|
173
|
+
2. **嵌套键**: 使用点号分隔嵌套键,如 `xiaozhi.endpoint`
|
|
174
|
+
3. **自动保存**: 配置更改会立即保存到文件
|
|
175
|
+
4. **错误处理**: 命令会提供清晰的错误信息和使用示例
|
|
176
|
+
5. **服务检查**: 启动前会检查必要的配置项(endpoint 和 mcpServers)
|
|
177
|
+
6. **进程安全**: 防止重复启动,确保同时只有一个服务实例运行
|
|
178
|
+
|
|
179
|
+
## 开发
|
|
180
|
+
|
|
181
|
+
如果你想在开发环境中直接运行CLI工具:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# 直接运行
|
|
185
|
+
node bin/xiaozhi --help
|
|
186
|
+
|
|
187
|
+
# 或者使用src中的文件
|
|
188
|
+
node src/cli.js --help
|
|
189
|
+
```
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# SettingManager 使用文档
|
|
2
|
+
|
|
3
|
+
SettingManager 是一个单例配置管理器,用于管理 `.xiaozhi/settings.json` 配置文件。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- **单例模式**: 确保全局只有一个配置管理实例
|
|
8
|
+
- **只读访问**: 外部只能通过方法获取配置,不能直接修改
|
|
9
|
+
- **方法更新**: 必须通过提供的方法来更新配置
|
|
10
|
+
- **自动保存**: 配置更新后自动保存到文件
|
|
11
|
+
- **嵌套键支持**: 支持使用点号分隔的嵌套键,如 `xiaozhi.endpoint`
|
|
12
|
+
|
|
13
|
+
## 基本用法
|
|
14
|
+
|
|
15
|
+
### 获取实例
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import SettingManager from './src/settingManager.js';
|
|
19
|
+
|
|
20
|
+
const settings = SettingManager.getInstance();
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 读取配置
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
// 读取简单配置
|
|
27
|
+
const endpoint = settings.get('xiaozhi.endpoint');
|
|
28
|
+
|
|
29
|
+
// 读取嵌套配置
|
|
30
|
+
const command = settings.get('mcpServers.amap-maps.command');
|
|
31
|
+
|
|
32
|
+
// 获取所有配置(只读副本)
|
|
33
|
+
const allSettings = settings.getAll();
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 更新配置
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
// 更新现有配置
|
|
40
|
+
settings.set('xiaozhi.endpoint', 'wss://new-endpoint.com');
|
|
41
|
+
|
|
42
|
+
// 添加新配置
|
|
43
|
+
settings.set('myApp.newSetting', 'value');
|
|
44
|
+
|
|
45
|
+
// 创建嵌套配置
|
|
46
|
+
settings.set('myApp.nested.deep.setting', 'deep value');
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 检查配置是否存在
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
if (settings.has('xiaozhi.endpoint')) {
|
|
53
|
+
console.log('Endpoint is configured');
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 删除配置
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
// 删除配置项
|
|
61
|
+
settings.delete('myApp.temporarySetting');
|
|
62
|
+
|
|
63
|
+
// 删除嵌套配置
|
|
64
|
+
settings.delete('myApp.nested.deep.setting');
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 重新加载配置
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
// 从文件重新加载配置(如果文件被外部修改)
|
|
71
|
+
settings.reload();
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 配置文件结构
|
|
75
|
+
|
|
76
|
+
配置文件位于 `.xiaozhi/settings.json`,典型结构如下:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"xiaozhi": {
|
|
81
|
+
"endpoint": "wss://api.xiaozhi.me/mcp/?token=..."
|
|
82
|
+
},
|
|
83
|
+
"mcpServers": {
|
|
84
|
+
"amap-maps": {
|
|
85
|
+
"command": "npx",
|
|
86
|
+
"args": ["-y", "@amap/amap-maps-mcp-server"],
|
|
87
|
+
"env": {
|
|
88
|
+
"AMAP_MAPS_API_KEY": "your-api-key"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 在 mcpWebSocketClient.js 中的使用
|
|
96
|
+
|
|
97
|
+
原来的代码使用环境变量:
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
const endpointUrl = process.env.MCP_ENDPOINT;
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
现在使用 SettingManager:
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
import SettingManager from './settingManager.js';
|
|
107
|
+
|
|
108
|
+
const settingManager = SettingManager.getInstance();
|
|
109
|
+
const endpointUrl = settingManager.get('xiaozhi.endpoint');
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## 注意事项
|
|
113
|
+
|
|
114
|
+
1. **单例模式**: 无论在哪里调用 `SettingManager.getInstance()`,都会返回同一个实例
|
|
115
|
+
2. **自动保存**: 调用 `set()` 或 `delete()` 方法后,配置会立即保存到文件
|
|
116
|
+
3. **只读访问**: `get()` 和 `getAll()` 返回的是配置的副本,直接修改不会影响实际配置
|
|
117
|
+
4. **错误处理**: 如果配置文件损坏或无法访问,会抛出相应的错误
|
|
118
|
+
5. **目录创建**: 如果 `.xiaozhi` 目录不存在,会自动创建
|
|
119
|
+
|
|
120
|
+
## 示例
|
|
121
|
+
|
|
122
|
+
查看 `examples/setting_manager_usage.js` 文件获取完整的使用示例。
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,22 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xiaozhi-client",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "小智 AI 客户端 命令行工具",
|
|
5
5
|
"main": "dist/cli.cjs",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
8
|
+
"docs",
|
|
9
|
+
"templates",
|
|
8
10
|
"README.md",
|
|
9
11
|
"LICENSE"
|
|
10
12
|
],
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public",
|
|
15
|
+
"registry": "https://registry.npmjs.org"
|
|
16
|
+
},
|
|
11
17
|
"bin": {
|
|
12
|
-
"xiaozhi": "./dist/cli.cjs"
|
|
18
|
+
"xiaozhi": "./dist/cli.cjs",
|
|
19
|
+
"xiaozhi-client": "./dist/cli.cjs"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup && node scripts/postbuild.js",
|
|
23
|
+
"dev": "tsup --watch && node scripts/postbuild.js",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest",
|
|
26
|
+
"test:coverage": "vitest run --coverage",
|
|
27
|
+
"test:ui": "vitest --ui",
|
|
28
|
+
"format": "biome format --write .",
|
|
29
|
+
"lint": "biome lint --write .",
|
|
30
|
+
"type:check": "tsc --noEmit",
|
|
31
|
+
"check": "biome check .",
|
|
32
|
+
"check:write": "biome check --write .",
|
|
33
|
+
"release": "semantic-release"
|
|
13
34
|
},
|
|
14
35
|
"keywords": [
|
|
36
|
+
"xiaozhi",
|
|
15
37
|
"mcp",
|
|
16
|
-
"calculator",
|
|
17
38
|
"websocket",
|
|
18
|
-
"ai"
|
|
19
|
-
"tools"
|
|
39
|
+
"ai"
|
|
20
40
|
],
|
|
21
41
|
"author": "shenjingnan(sjn.code@gmail.com)",
|
|
22
42
|
"license": "MIT",
|
|
@@ -30,23 +50,25 @@
|
|
|
30
50
|
"zod": "^3.25.62"
|
|
31
51
|
},
|
|
32
52
|
"devDependencies": {
|
|
33
|
-
"@
|
|
53
|
+
"@biomejs/biome": "1.9.4",
|
|
54
|
+
"@codecov/vite-plugin": "^1.9.1",
|
|
55
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
56
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
57
|
+
"@semantic-release/git": "^10.0.1",
|
|
58
|
+
"@semantic-release/github": "^11.0.3",
|
|
59
|
+
"@semantic-release/npm": "^12.0.1",
|
|
60
|
+
"@semantic-release/release-notes-generator": "^14.0.3",
|
|
61
|
+
"@types/node": "^24.0.1",
|
|
34
62
|
"@types/ws": "^8.18.1",
|
|
35
|
-
"
|
|
63
|
+
"@vitest/coverage-v8": "^3.2.3",
|
|
64
|
+
"codecov": "^3.8.3",
|
|
65
|
+
"conventional-changelog-conventionalcommits": "^9.0.0",
|
|
66
|
+
"esbuild": "^0.25.5",
|
|
67
|
+
"glob": "^11.0.3",
|
|
68
|
+
"semantic-release": "^24.2.5",
|
|
69
|
+
"semver": "^7.7.2",
|
|
36
70
|
"tsup": "^8.5.0",
|
|
37
|
-
"typescript": "^5.8.3"
|
|
38
|
-
|
|
39
|
-
"engines": {
|
|
40
|
-
"node": ">=18.0.0"
|
|
41
|
-
},
|
|
42
|
-
"scripts": {
|
|
43
|
-
"build": "tsup && sed -i '' 's/\\.js\"/\\.cjs\"/g' dist/*.cjs && sed -i '' '/const __dirname = /d' dist/*.cjs",
|
|
44
|
-
"build:raw": "tsup",
|
|
45
|
-
"start": "node dist/mcpPipe.cjs calculator.js",
|
|
46
|
-
"calculator": "node calculator.js",
|
|
47
|
-
"pipe": "node dist/mcpPipe.cjs",
|
|
48
|
-
"dev": "node --inspect dist/mcpPipe.cjs calculator.js",
|
|
49
|
-
"test": "node test.js",
|
|
50
|
-
"install-deps": "npm install"
|
|
71
|
+
"typescript": "^5.8.3",
|
|
72
|
+
"vitest": "^3.2.3"
|
|
51
73
|
}
|
|
52
|
-
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MCP Calculator Server - JavaScript Implementation
|
|
5
|
+
* Provides mathematical calculation tools via MCP protocol
|
|
6
|
+
* Version: 0.2.0 - Using @modelcontextprotocol/sdk
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
|
|
13
|
+
// Simple logger utility
|
|
14
|
+
const logger = {
|
|
15
|
+
info: (message) => {
|
|
16
|
+
const timestamp = new Date().toISOString();
|
|
17
|
+
console.error(`${timestamp} - Calculator - INFO - ${message}`);
|
|
18
|
+
},
|
|
19
|
+
error: (message) => {
|
|
20
|
+
const timestamp = new Date().toISOString();
|
|
21
|
+
console.error(`${timestamp} - Calculator - ERROR - ${message}`);
|
|
22
|
+
},
|
|
23
|
+
debug: (message) => {
|
|
24
|
+
const timestamp = new Date().toISOString();
|
|
25
|
+
console.error(`${timestamp} - Calculator - DEBUG - ${message}`);
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Create MCP server instance using the official SDK
|
|
30
|
+
const server = new McpServer({
|
|
31
|
+
name: "Calculator",
|
|
32
|
+
version: "0.2.0",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Register calculator tool using the SDK
|
|
36
|
+
server.tool(
|
|
37
|
+
"calculator",
|
|
38
|
+
"For mathematical calculation, always use this tool to calculate the result of a JavaScript expression. Math object and basic operations are available.",
|
|
39
|
+
{
|
|
40
|
+
javascript_expression: z
|
|
41
|
+
.string()
|
|
42
|
+
.describe("JavaScript expression to evaluate"),
|
|
43
|
+
},
|
|
44
|
+
async ({ javascript_expression }) => {
|
|
45
|
+
try {
|
|
46
|
+
// Simple and direct evaluation like Python version
|
|
47
|
+
// Note: In a production environment, you might want to add more security measures
|
|
48
|
+
const result = eval(javascript_expression);
|
|
49
|
+
logger.info(
|
|
50
|
+
`Calculating formula: ${javascript_expression}, result: ${result}`
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
content: [
|
|
55
|
+
{
|
|
56
|
+
type: "text",
|
|
57
|
+
text: JSON.stringify({
|
|
58
|
+
success: true,
|
|
59
|
+
result: result,
|
|
60
|
+
}),
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
} catch (error) {
|
|
65
|
+
logger.error(`Calculation error: ${error.message}`);
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: "text",
|
|
70
|
+
text: JSON.stringify({
|
|
71
|
+
success: false,
|
|
72
|
+
error: error.message,
|
|
73
|
+
}),
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
isError: true,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Start the server if this file is run directly
|
|
83
|
+
async function main() {
|
|
84
|
+
logger.info("Starting MCP Calculator server with SDK");
|
|
85
|
+
|
|
86
|
+
const transport = new StdioServerTransport();
|
|
87
|
+
await server.connect(transport);
|
|
88
|
+
|
|
89
|
+
logger.info("MCP Calculator server is running on stdio");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Run the server if this file is executed directly
|
|
93
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
94
|
+
main().catch((error) => {
|
|
95
|
+
logger.error(`Failed to start server: ${error.message}`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export default server;
|