# Directory Structure
```
├── .gitignore
├── dist
│ └── server.js
├── LICENSE.txt
├── package-lock.json
├── package.json
├── README.md
├── src
│ ├── index.ts
│ └── server.ts
└── tsconfig.json
```
# Files
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
1 | node_modules/
2 | dist/
3 | *.log
4 |
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # mcp-time
2 |
3 | A simple MCP server for getting current time in various formats. This server is designed to work with Claude desktop app on macOS.
4 |
5 | ## Features
6 |
7 | - Get current time in YYYYMMDDHHMMSS format
8 | - Returns time in JST (Japan Standard Time)
9 | - Utilizes macOS system date command
10 |
11 | ## Installation
12 |
13 | ```bash
14 | npm install mcp-time
15 | ```
16 |
17 | ## Usage
18 |
19 | Start the server:
20 |
21 | ```bash
22 | npm start
23 | ```
24 |
25 | The server will start on port 3200 by default.
26 |
27 | ## Development
28 |
29 | 1. Clone the repository
30 | 2. Install dependencies
31 | ```bash
32 | npm install
33 | ```
34 | 3. Start development server
35 | ```bash
36 | npm run dev
37 | ```
38 |
39 | ## License
40 |
41 | MIT License - see [LICENSE](LICENSE.txt) for details
42 |
```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "module": "ES2020",
5 | "moduleResolution": "node",
6 | "outDir": "./dist",
7 | "rootDir": "./src",
8 | "strict": true,
9 | "esModuleInterop": true,
10 | "skipLibCheck": true,
11 | "forceConsistentCasingInFileNames": true
12 | },
13 | "include": ["src/**/*"],
14 | "exclude": ["node_modules", "**/*.test.ts"]
15 | }
```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "mcp-time",
3 | "version": "1.0.0",
4 | "description": "MCP server for getting current time",
5 | "main": "dist/server.js",
6 | "type": "module",
7 | "scripts": {
8 | "build": "tsc && chmod +x dist/server.js",
9 | "prepare": "npm run build"
10 | },
11 | "keywords": [
12 | "mcp",
13 | "time",
14 | "server"
15 | ],
16 | "author": "zepar",
17 | "license": "MIT",
18 | "dependencies": {
19 | "@modelcontextprotocol/sdk": "1.0.1",
20 | "zod-to-json-schema": "^3.23.5"
21 | },
22 | "devDependencies": {
23 | "@types/node": "^20.11.0",
24 | "ts-node": "^10.9.2",
25 | "typescript": "^5.7.3"
26 | },
27 | "bin": {
28 | "mcp-time": "dist/server.js"
29 | }
30 | }
```
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
```
1 | MIT License
2 |
3 | Copyright (c) 2024 zepar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
```
--------------------------------------------------------------------------------
/src/server.ts:
--------------------------------------------------------------------------------
```typescript
1 | #!/usr/bin/env node
2 | import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4 | import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
5 | import { z } from "zod";
6 | import { zodToJsonSchema } from "zod-to-json-schema";
7 |
8 | // Schema definition for getCurrentTime
9 | const GetTimeArgsSchema = z.object({});
10 |
11 | const server = new Server({
12 | name: "time-server",
13 | version: "0.1.0",
14 | }, {
15 | capabilities: {
16 | tools: {},
17 | },
18 | });
19 |
20 | // Tool handlers
21 | server.setRequestHandler(ListToolsRequestSchema, async () => {
22 | return {
23 | tools: [
24 | {
25 | name: "getCurrentTime",
26 | description: "Get current time in UTC",
27 | inputSchema: zodToJsonSchema(GetTimeArgsSchema),
28 | },
29 | ],
30 | };
31 | });
32 |
33 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
34 | try {
35 | const { name } = request.params;
36 |
37 | if (name === "getCurrentTime") {
38 | const time = new Date().toISOString();
39 | return {
40 | content: [{
41 | type: "text",
42 | text: time
43 | }],
44 | isError: false,
45 | };
46 | }
47 |
48 | throw new Error(`Unknown tool: ${name}`);
49 | } catch (error) {
50 | const errorMessage = error instanceof Error ? error.message : String(error);
51 | return {
52 | content: [{ type: "text", text: `Error: ${errorMessage}` }],
53 | isError: true,
54 | };
55 | }
56 | });
57 |
58 | // Start server
59 | async function runServer() {
60 | const transport = new StdioServerTransport();
61 | await server.connect(transport);
62 | console.error("Time server running on stdio");
63 | }
64 |
65 | runServer().catch((error) => {
66 | console.error("Fatal error running server:", error);
67 | process.exit(1);
68 | });
```
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | #!/usr/bin/env node
2 |
3 | import { exec } from 'child_process';
4 | import { promisify } from 'util';
5 |
6 | const execAsync = promisify(exec);
7 |
8 | interface JsonRpcRequest {
9 | jsonrpc: '2.0';
10 | id: number | string | null;
11 | method: string;
12 | params?: any;
13 | }
14 |
15 | interface JsonRpcResponse {
16 | jsonrpc: '2.0';
17 | id: number | string | null;
18 | result?: any;
19 | error?: {
20 | code: number;
21 | message: string;
22 | data?: any;
23 | };
24 | }
25 |
26 | interface TimeResponse {
27 | time: string;
28 | success: boolean;
29 | }
30 |
31 | async function handleJsonRpcMessage(message: JsonRpcRequest): Promise<JsonRpcResponse> {
32 | if (message.method === 'getCurrentTime') {
33 | try {
34 | const { stdout } = await execAsync('date "+%Y-%m-%d %H:%M:%S"');
35 | return {
36 | jsonrpc: '2.0',
37 | id: message.id,
38 | result: {
39 | time: stdout.trim(),
40 | success: true
41 | }
42 | };
43 | } catch (error) {
44 | return {
45 | jsonrpc: '2.0',
46 | id: message.id,
47 | error: {
48 | code: -32603,
49 | message: 'Failed to get current time',
50 | data: error instanceof Error ? error.message : String(error)
51 | }
52 | };
53 | }
54 | }
55 |
56 | return {
57 | jsonrpc: '2.0',
58 | id: message.id,
59 | error: {
60 | code: -32601,
61 | message: 'Method not found'
62 | }
63 | };
64 | }
65 |
66 | // メインのサーバー処理
67 | process.stdin.setEncoding('utf-8');
68 | let buffer = '';
69 |
70 | process.stdin.on('data', async (chunk: string) => {
71 | buffer += chunk;
72 |
73 | const messages = buffer.split('\n');
74 | buffer = messages.pop() || '';
75 |
76 | for (const message of messages) {
77 | try {
78 | const request: JsonRpcRequest = JSON.parse(message);
79 | const response = await handleJsonRpcMessage(request);
80 | console.log(JSON.stringify(response));
81 | } catch (error) {
82 | console.log(JSON.stringify({
83 | jsonrpc: '2.0',
84 | id: null,
85 | error: {
86 | code: -32700,
87 | message: 'Parse error',
88 | data: error instanceof Error ? error.message : String(error)
89 | }
90 | }));
91 | }
92 | }
93 | });
94 |
95 | process.stdin.on('end', () => {
96 | process.exit(0);
97 | });
98 |
99 | // エラーハンドリング
100 | process.on('uncaughtException', (error) => {
101 | console.error('Uncaught Exception:', error);
102 | process.exit(1);
103 | });
104 |
105 | process.on('unhandledRejection', (reason, promise) => {
106 | console.error('Unhandled Rejection at:', promise, 'reason:', reason);
107 | process.exit(1);
108 | });
109 |
```