xiaozhi-client 0.0.1-beta.0

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.
@@ -0,0 +1,354 @@
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.string().optional().describe("Time format: 'iso' (default), 'timestamp', 'locale', 'time-only'")
41
+ },
42
+ async ({ format = 'iso' }) => {
43
+ try {
44
+ const now = new Date();
45
+ let result;
46
+
47
+ switch (format) {
48
+ case 'timestamp':
49
+ result = now.getTime();
50
+ break;
51
+ case 'locale':
52
+ result = now.toLocaleString();
53
+ break;
54
+ case 'time-only':
55
+ result = now.toLocaleTimeString();
56
+ break;
57
+ case 'iso':
58
+ default:
59
+ result = now.toISOString();
60
+ break;
61
+ }
62
+
63
+ logger.info(`Getting current time in format: ${format}, result: ${result}`);
64
+
65
+ return {
66
+ content: [
67
+ {
68
+ type: "text",
69
+ text: JSON.stringify({
70
+ success: true,
71
+ result: result,
72
+ format: format
73
+ })
74
+ }
75
+ ]
76
+ };
77
+ } catch (error) {
78
+ logger.error(`Get current time error: ${error.message}`);
79
+ return {
80
+ content: [
81
+ {
82
+ type: "text",
83
+ text: JSON.stringify({
84
+ success: false,
85
+ error: error.message
86
+ })
87
+ }
88
+ ],
89
+ isError: true
90
+ };
91
+ }
92
+ }
93
+ );
94
+
95
+ // Register get_current_date tool
96
+ server.tool(
97
+ "get_current_date",
98
+ "Get the current date in various formats",
99
+ {
100
+ format: z.string().optional().describe("Date format: 'iso' (default), 'locale', 'date-only', 'yyyy-mm-dd'")
101
+ },
102
+ async ({ format = 'iso' }) => {
103
+ try {
104
+ const now = new Date();
105
+ let result;
106
+
107
+ switch (format) {
108
+ case 'locale':
109
+ result = now.toLocaleDateString();
110
+ break;
111
+ case 'date-only':
112
+ result = now.toDateString();
113
+ break;
114
+ case 'yyyy-mm-dd':
115
+ result = now.toISOString().split('T')[0];
116
+ break;
117
+ case 'iso':
118
+ default:
119
+ result = now.toISOString();
120
+ break;
121
+ }
122
+
123
+ logger.info(`Getting current date in format: ${format}, result: ${result}`);
124
+
125
+ return {
126
+ content: [
127
+ {
128
+ type: "text",
129
+ text: JSON.stringify({
130
+ success: true,
131
+ result: result,
132
+ format: format
133
+ })
134
+ }
135
+ ]
136
+ };
137
+ } catch (error) {
138
+ logger.error(`Get current date error: ${error.message}`);
139
+ return {
140
+ content: [
141
+ {
142
+ type: "text",
143
+ text: JSON.stringify({
144
+ success: false,
145
+ error: error.message
146
+ })
147
+ }
148
+ ],
149
+ isError: true
150
+ };
151
+ }
152
+ }
153
+ );
154
+
155
+ // Register format_datetime tool
156
+ server.tool(
157
+ "format_datetime",
158
+ "Format a given date/time string or timestamp into specified format",
159
+ {
160
+ datetime: z.string().describe("Date/time string or timestamp to format"),
161
+ format: z.string().optional().describe("Output format: 'iso', 'locale', 'timestamp', 'yyyy-mm-dd', 'custom'"),
162
+ custom_format: z.string().optional().describe("Custom format string (when format is 'custom')")
163
+ },
164
+ async ({ datetime, format = 'iso', custom_format }) => {
165
+ try {
166
+ let date;
167
+
168
+ // Try to parse the input datetime
169
+ if (!isNaN(Number(datetime))) {
170
+ // It's a timestamp
171
+ date = new Date(Number(datetime));
172
+ } else {
173
+ // It's a date string
174
+ date = new Date(datetime);
175
+ }
176
+
177
+ if (isNaN(date.getTime())) {
178
+ throw new Error("Invalid date/time format");
179
+ }
180
+
181
+ let result;
182
+ switch (format) {
183
+ case 'timestamp':
184
+ result = date.getTime();
185
+ break;
186
+ case 'locale':
187
+ result = date.toLocaleString();
188
+ break;
189
+ case 'yyyy-mm-dd':
190
+ result = date.toISOString().split('T')[0];
191
+ break;
192
+ case 'custom':
193
+ if (custom_format) {
194
+ // Simple custom formatting (can be extended)
195
+ result = custom_format
196
+ .replace('YYYY', date.getFullYear())
197
+ .replace('MM', String(date.getMonth() + 1).padStart(2, '0'))
198
+ .replace('DD', String(date.getDate()).padStart(2, '0'))
199
+ .replace('HH', String(date.getHours()).padStart(2, '0'))
200
+ .replace('mm', String(date.getMinutes()).padStart(2, '0'))
201
+ .replace('ss', String(date.getSeconds()).padStart(2, '0'));
202
+ } else {
203
+ result = date.toISOString();
204
+ }
205
+ break;
206
+ case 'iso':
207
+ default:
208
+ result = date.toISOString();
209
+ break;
210
+ }
211
+
212
+ logger.info(`Formatting datetime: ${datetime} to format: ${format}, result: ${result}`);
213
+
214
+ return {
215
+ content: [
216
+ {
217
+ type: "text",
218
+ text: JSON.stringify({
219
+ success: true,
220
+ result: result,
221
+ original: datetime,
222
+ format: format
223
+ })
224
+ }
225
+ ]
226
+ };
227
+ } catch (error) {
228
+ logger.error(`Format datetime error: ${error.message}`);
229
+ return {
230
+ content: [
231
+ {
232
+ type: "text",
233
+ text: JSON.stringify({
234
+ success: false,
235
+ error: error.message
236
+ })
237
+ }
238
+ ],
239
+ isError: true
240
+ };
241
+ }
242
+ }
243
+ );
244
+
245
+ // Register add_time tool
246
+ server.tool(
247
+ "add_time",
248
+ "Add or subtract time from a given date/time",
249
+ {
250
+ datetime: z.string().describe("Base date/time string or timestamp"),
251
+ amount: z.number().describe("Amount to add (positive) or subtract (negative)"),
252
+ unit: z.string().describe("Time unit: 'milliseconds', 'seconds', 'minutes', 'hours', 'days', 'weeks', 'months', 'years'")
253
+ },
254
+ async ({ datetime, amount, unit }) => {
255
+ try {
256
+ let date;
257
+
258
+ // Try to parse the input datetime
259
+ if (!isNaN(Number(datetime))) {
260
+ date = new Date(Number(datetime));
261
+ } else {
262
+ date = new Date(datetime);
263
+ }
264
+
265
+ if (isNaN(date.getTime())) {
266
+ throw new Error("Invalid date/time format");
267
+ }
268
+
269
+ // Calculate the new date based on unit
270
+ let newDate = new Date(date);
271
+
272
+ switch (unit.toLowerCase()) {
273
+ case 'milliseconds':
274
+ newDate.setTime(newDate.getTime() + amount);
275
+ break;
276
+ case 'seconds':
277
+ newDate.setTime(newDate.getTime() + (amount * 1000));
278
+ break;
279
+ case 'minutes':
280
+ newDate.setTime(newDate.getTime() + (amount * 60 * 1000));
281
+ break;
282
+ case 'hours':
283
+ newDate.setTime(newDate.getTime() + (amount * 60 * 60 * 1000));
284
+ break;
285
+ case 'days':
286
+ newDate.setDate(newDate.getDate() + amount);
287
+ break;
288
+ case 'weeks':
289
+ newDate.setDate(newDate.getDate() + (amount * 7));
290
+ break;
291
+ case 'months':
292
+ newDate.setMonth(newDate.getMonth() + amount);
293
+ break;
294
+ case 'years':
295
+ newDate.setFullYear(newDate.getFullYear() + amount);
296
+ break;
297
+ default:
298
+ throw new Error(`Unsupported time unit: ${unit}`);
299
+ }
300
+
301
+ const result = newDate.toISOString();
302
+ logger.info(`Adding ${amount} ${unit} to ${datetime}, result: ${result}`);
303
+
304
+ return {
305
+ content: [
306
+ {
307
+ type: "text",
308
+ text: JSON.stringify({
309
+ success: true,
310
+ result: result,
311
+ original: datetime,
312
+ amount: amount,
313
+ unit: unit
314
+ })
315
+ }
316
+ ]
317
+ };
318
+ } catch (error) {
319
+ logger.error(`Add time error: ${error.message}`);
320
+ return {
321
+ content: [
322
+ {
323
+ type: "text",
324
+ text: JSON.stringify({
325
+ success: false,
326
+ error: error.message
327
+ })
328
+ }
329
+ ],
330
+ isError: true
331
+ };
332
+ }
333
+ }
334
+ );
335
+
336
+ // Start the server if this file is run directly
337
+ async function main() {
338
+ logger.info("Starting MCP DateTime server with SDK");
339
+
340
+ const transport = new StdioServerTransport();
341
+ await server.connect(transport);
342
+
343
+ logger.info("MCP DateTime server is running on stdio");
344
+ }
345
+
346
+ // Run the server if this file is executed directly
347
+ if (import.meta.url === `file://${process.argv[1]}`) {
348
+ main().catch((error) => {
349
+ logger.error(`Failed to start server: ${error.message}`);
350
+ process.exit(1);
351
+ });
352
+ }
353
+
354
+ export default server;
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "xiaozhi-client",
3
+ "version": "0.0.1-beta.0",
4
+ "description": "小智 AI 客户端 命令行工具",
5
+ "main": "dist/cli.cjs",
6
+ "files": [
7
+ "dist",
8
+ "README.md",
9
+ "LICENSE"
10
+ ],
11
+ "bin": {
12
+ "xiaozhi": "./dist/cli.cjs",
13
+ "xiaozhi-client": "./dist/cli.cjs"
14
+ },
15
+ "keywords": [
16
+ "mcp",
17
+ "calculator",
18
+ "websocket",
19
+ "ai",
20
+ "tools"
21
+ ],
22
+ "author": "shenjingnan(sjn.code@gmail.com)",
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "@modelcontextprotocol/sdk": "^1.12.1",
26
+ "chalk": "^5.4.1",
27
+ "commander": "^14.0.0",
28
+ "dotenv": "^16.3.1",
29
+ "ora": "^8.2.0",
30
+ "ws": "^8.14.2",
31
+ "zod": "^3.25.62"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^20.8.0",
35
+ "@types/ws": "^8.18.1",
36
+ "pkg": "^5.8.1",
37
+ "tsup": "^8.5.0",
38
+ "typescript": "^5.8.3"
39
+ },
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "scripts": {
44
+ "build": "tsup && sed -i '' 's/\\.js\"/\\.cjs\"/g' dist/*.cjs && sed -i '' '/const __dirname = /d' dist/*.cjs",
45
+ "build:raw": "tsup",
46
+ "start": "node dist/mcpPipe.cjs calculator.js",
47
+ "calculator": "node calculator.js",
48
+ "pipe": "node dist/mcpPipe.cjs",
49
+ "dev": "node --inspect dist/mcpPipe.cjs calculator.js",
50
+ "test": "node test.js",
51
+ "install-deps": "npm install"
52
+ }
53
+ }