xiaozhi-client 1.6.3-beta.1 → 1.6.3-beta.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xiaozhi-client",
3
- "version": "1.6.3-beta.1",
3
+ "version": "1.6.3-beta.2",
4
4
  "description": "小智 AI 客户端 命令行工具",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",
@@ -92,7 +92,7 @@
92
92
  "test:ui": "vitest --ui",
93
93
  "format": "biome format --write .",
94
94
  "lint": "biome lint --write .",
95
- "type:check": "tsc --noEmit",
95
+ "type:check": "tsc --project tsconfig.typecheck.json",
96
96
  "check": "biome check .",
97
97
  "check:fix": "biome check --write --unsafe .",
98
98
  "check:all": "pnpm check && pnpm type:check && pnpm spell:check && pnpm duplicate:check",
@@ -0,0 +1,106 @@
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
+ import { fileURLToPath } from 'node:url';
94
+ import { resolve } from 'node:path';
95
+
96
+ const currentFile = fileURLToPath(import.meta.url);
97
+ const argFile = process.argv[1] ? resolve(process.argv[1]) : null;
98
+
99
+ if (argFile && currentFile === argFile) {
100
+ main().catch((error) => {
101
+ logger.error(`Failed to start server: ${error.message}`);
102
+ process.exit(1);
103
+ });
104
+ }
105
+
106
+ export default server;
@@ -0,0 +1,390 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * MCP DateTime Server - JavaScript Implementation
5
+ * Provides date and time 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} - DateTime - INFO - ${message}`);
18
+ },
19
+ error: (message) => {
20
+ const timestamp = new Date().toISOString();
21
+ console.error(`${timestamp} - DateTime - ERROR - ${message}`);
22
+ },
23
+ debug: (message) => {
24
+ const timestamp = new Date().toISOString();
25
+ console.error(`${timestamp} - DateTime - DEBUG - ${message}`);
26
+ },
27
+ };
28
+
29
+ // Create MCP server instance using the official SDK
30
+ const server = new McpServer({
31
+ name: "DateTime",
32
+ version: "0.2.0",
33
+ });
34
+
35
+ // Register get_current_time tool
36
+ server.tool(
37
+ "get_current_time",
38
+ "Get the current time in various formats",
39
+ {
40
+ format: z
41
+ .string()
42
+ .optional()
43
+ .describe(
44
+ "Time format: 'iso' (default), 'timestamp', 'locale', 'time-only'"
45
+ ),
46
+ },
47
+ async ({ format = "iso" }) => {
48
+ try {
49
+ const now = new Date();
50
+ let result;
51
+
52
+ switch (format) {
53
+ case "timestamp":
54
+ result = now.getTime();
55
+ break;
56
+ case "locale":
57
+ result = now.toLocaleString();
58
+ break;
59
+ case "time-only":
60
+ result = now.toLocaleTimeString();
61
+ break;
62
+ case "iso":
63
+ default:
64
+ result = now.toISOString();
65
+ break;
66
+ }
67
+
68
+ logger.info(
69
+ `Getting current time in format: ${format}, result: ${result}`
70
+ );
71
+
72
+ return {
73
+ content: [
74
+ {
75
+ type: "text",
76
+ text: JSON.stringify({
77
+ success: true,
78
+ result: result,
79
+ format: format,
80
+ }),
81
+ },
82
+ ],
83
+ };
84
+ } catch (error) {
85
+ logger.error(`Get current time error: ${error.message}`);
86
+ return {
87
+ content: [
88
+ {
89
+ type: "text",
90
+ text: JSON.stringify({
91
+ success: false,
92
+ error: error.message,
93
+ }),
94
+ },
95
+ ],
96
+ isError: true,
97
+ };
98
+ }
99
+ }
100
+ );
101
+
102
+ // Register get_current_date tool
103
+ server.tool(
104
+ "get_current_date",
105
+ "Get the current date in various formats",
106
+ {
107
+ format: z
108
+ .string()
109
+ .optional()
110
+ .describe(
111
+ "Date format: 'iso' (default), 'locale', 'date-only', 'yyyy-mm-dd'"
112
+ ),
113
+ },
114
+ async ({ format = "iso" }) => {
115
+ try {
116
+ const now = new Date();
117
+ let result;
118
+
119
+ switch (format) {
120
+ case "locale":
121
+ result = now.toLocaleDateString();
122
+ break;
123
+ case "date-only":
124
+ result = now.toDateString();
125
+ break;
126
+ case "yyyy-mm-dd":
127
+ result = now.toISOString().split("T")[0];
128
+ break;
129
+ case "iso":
130
+ default:
131
+ result = now.toISOString();
132
+ break;
133
+ }
134
+
135
+ logger.info(
136
+ `Getting current date in format: ${format}, result: ${result}`
137
+ );
138
+
139
+ return {
140
+ content: [
141
+ {
142
+ type: "text",
143
+ text: JSON.stringify({
144
+ success: true,
145
+ result: result,
146
+ format: format,
147
+ }),
148
+ },
149
+ ],
150
+ };
151
+ } catch (error) {
152
+ logger.error(`Get current date error: ${error.message}`);
153
+ return {
154
+ content: [
155
+ {
156
+ type: "text",
157
+ text: JSON.stringify({
158
+ success: false,
159
+ error: error.message,
160
+ }),
161
+ },
162
+ ],
163
+ isError: true,
164
+ };
165
+ }
166
+ }
167
+ );
168
+
169
+ // Register format_datetime tool
170
+ server.tool(
171
+ "format_datetime",
172
+ "Format a given date/time string or timestamp into specified format",
173
+ {
174
+ datetime: z.string().describe("Date/time string or timestamp to format"),
175
+ format: z
176
+ .string()
177
+ .optional()
178
+ .describe(
179
+ "Output format: 'iso', 'locale', 'timestamp', 'yyyy-mm-dd', 'custom'"
180
+ ),
181
+ custom_format: z
182
+ .string()
183
+ .optional()
184
+ .describe("Custom format string (when format is 'custom')"),
185
+ },
186
+ async ({ datetime, format = "iso", custom_format }) => {
187
+ try {
188
+ let date;
189
+
190
+ // Try to parse the input datetime
191
+ if (!isNaN(Number(datetime))) {
192
+ // It's a timestamp
193
+ date = new Date(Number(datetime));
194
+ } else {
195
+ // It's a date string
196
+ date = new Date(datetime);
197
+ }
198
+
199
+ if (isNaN(date.getTime())) {
200
+ throw new Error("Invalid date/time format");
201
+ }
202
+
203
+ let result;
204
+ switch (format) {
205
+ case "timestamp":
206
+ result = date.getTime();
207
+ break;
208
+ case "locale":
209
+ result = date.toLocaleString();
210
+ break;
211
+ case "yyyy-mm-dd":
212
+ result = date.toISOString().split("T")[0];
213
+ break;
214
+ case "custom":
215
+ if (custom_format) {
216
+ // Simple custom formatting (can be extended)
217
+ result = custom_format
218
+ .replace("YYYY", date.getFullYear())
219
+ .replace("MM", String(date.getMonth() + 1).padStart(2, "0"))
220
+ .replace("DD", String(date.getDate()).padStart(2, "0"))
221
+ .replace("HH", String(date.getHours()).padStart(2, "0"))
222
+ .replace("mm", String(date.getMinutes()).padStart(2, "0"))
223
+ .replace("ss", String(date.getSeconds()).padStart(2, "0"));
224
+ } else {
225
+ result = date.toISOString();
226
+ }
227
+ break;
228
+ case "iso":
229
+ default:
230
+ result = date.toISOString();
231
+ break;
232
+ }
233
+
234
+ logger.info(
235
+ `Formatting datetime: ${datetime} to format: ${format}, result: ${result}`
236
+ );
237
+
238
+ return {
239
+ content: [
240
+ {
241
+ type: "text",
242
+ text: JSON.stringify({
243
+ success: true,
244
+ result: result,
245
+ original: datetime,
246
+ format: format,
247
+ }),
248
+ },
249
+ ],
250
+ };
251
+ } catch (error) {
252
+ logger.error(`Format datetime error: ${error.message}`);
253
+ return {
254
+ content: [
255
+ {
256
+ type: "text",
257
+ text: JSON.stringify({
258
+ success: false,
259
+ error: error.message,
260
+ }),
261
+ },
262
+ ],
263
+ isError: true,
264
+ };
265
+ }
266
+ }
267
+ );
268
+
269
+ // Register add_time tool
270
+ server.tool(
271
+ "add_time",
272
+ "Add or subtract time from a given date/time",
273
+ {
274
+ datetime: z.string().describe("Base date/time string or timestamp"),
275
+ amount: z
276
+ .number()
277
+ .describe("Amount to add (positive) or subtract (negative)"),
278
+ unit: z
279
+ .string()
280
+ .describe(
281
+ "Time unit: 'milliseconds', 'seconds', 'minutes', 'hours', 'days', 'weeks', 'months', 'years'"
282
+ ),
283
+ },
284
+ async ({ datetime, amount, unit }) => {
285
+ try {
286
+ let date;
287
+
288
+ // Try to parse the input datetime
289
+ if (!isNaN(Number(datetime))) {
290
+ date = new Date(Number(datetime));
291
+ } else {
292
+ date = new Date(datetime);
293
+ }
294
+
295
+ if (isNaN(date.getTime())) {
296
+ throw new Error("Invalid date/time format");
297
+ }
298
+
299
+ // Calculate the new date based on unit
300
+ const newDate = new Date(date);
301
+
302
+ switch (unit.toLowerCase()) {
303
+ case "milliseconds":
304
+ newDate.setTime(newDate.getTime() + amount);
305
+ break;
306
+ case "seconds":
307
+ newDate.setTime(newDate.getTime() + amount * 1000);
308
+ break;
309
+ case "minutes":
310
+ newDate.setTime(newDate.getTime() + amount * 60 * 1000);
311
+ break;
312
+ case "hours":
313
+ newDate.setTime(newDate.getTime() + amount * 60 * 60 * 1000);
314
+ break;
315
+ case "days":
316
+ newDate.setDate(newDate.getDate() + amount);
317
+ break;
318
+ case "weeks":
319
+ newDate.setDate(newDate.getDate() + amount * 7);
320
+ break;
321
+ case "months":
322
+ newDate.setMonth(newDate.getMonth() + amount);
323
+ break;
324
+ case "years":
325
+ newDate.setFullYear(newDate.getFullYear() + amount);
326
+ break;
327
+ default:
328
+ throw new Error(`Unsupported time unit: ${unit}`);
329
+ }
330
+
331
+ const result = newDate.toISOString();
332
+ logger.info(`Adding ${amount} ${unit} to ${datetime}, result: ${result}`);
333
+
334
+ return {
335
+ content: [
336
+ {
337
+ type: "text",
338
+ text: JSON.stringify({
339
+ success: true,
340
+ result: result,
341
+ original: datetime,
342
+ amount: amount,
343
+ unit: unit,
344
+ }),
345
+ },
346
+ ],
347
+ };
348
+ } catch (error) {
349
+ logger.error(`Add time error: ${error.message}`);
350
+ return {
351
+ content: [
352
+ {
353
+ type: "text",
354
+ text: JSON.stringify({
355
+ success: false,
356
+ error: error.message,
357
+ }),
358
+ },
359
+ ],
360
+ isError: true,
361
+ };
362
+ }
363
+ }
364
+ );
365
+
366
+ // Start the server if this file is run directly
367
+ async function main() {
368
+ logger.info("Starting MCP DateTime server with SDK");
369
+
370
+ const transport = new StdioServerTransport();
371
+ await server.connect(transport);
372
+
373
+ logger.info("MCP DateTime server is running on stdio");
374
+ }
375
+
376
+ // Run the server if this file is executed directly
377
+ import { fileURLToPath } from 'node:url';
378
+ import { resolve } from 'node:path';
379
+
380
+ const currentFile = fileURLToPath(import.meta.url);
381
+ const argFile = process.argv[1] ? resolve(process.argv[1]) : null;
382
+
383
+ if (argFile && currentFile === argFile) {
384
+ main().catch((error) => {
385
+ logger.error(`Failed to start server: ${error.message}`);
386
+ process.exit(1);
387
+ });
388
+ }
389
+
390
+ export default server;
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "hello-world",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "",
6
+ "keywords": [],
7
+ "author": "shenjingnan <sjn.code@gmail.com>",
8
+ "license": "MIT",
9
+ "dependencies": {
10
+ "@modelcontextprotocol/sdk": "^1.12.1",
11
+ "zod": "^3.25.64"
12
+ }
13
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "mcpEndpoint": "<请填写你的接入点地址(获取地址在 xiaozhi.me)>",
3
+ "mcpServers": {
4
+ "calculator": {
5
+ "command": "node",
6
+ "args": ["./mcpServers/calculator.js"]
7
+ },
8
+ "datetime": {
9
+ "command": "node",
10
+ "args": ["./mcpServers/datetime.js"]
11
+ }
12
+ },
13
+ "connection": {
14
+ "heartbeatInterval": 30000,
15
+ "heartbeatTimeout": 10000,
16
+ "reconnectInterval": 5000
17
+ },
18
+ "webUI": {
19
+ "port": 9999
20
+ }
21
+ }