# Directory Structure
```
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── src
│ └── index.ts
└── tsconfig.json
```
# Files
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
1 | # Dependencies
2 | node_modules/
3 |
4 | # Build output
5 | build/
6 |
7 | # Logs
8 | logs
9 | *.log
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 | lerna-debug.log*
15 |
16 | # Diagnostic reports (https://nodejs.org/api/report.html)
17 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
18 |
19 | # Runtime data
20 | pids
21 | *.pid
22 | *.seed
23 | *.pid.lock
24 |
25 | # Directory for instrumented libs generated by jscoverage/JSCover
26 | lib-cov
27 |
28 | # Coverage directory used by tools like istanbul
29 | coverage
30 | *.lcov
31 |
32 | # nyc test coverage
33 | .nyc_output
34 |
35 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
36 | .grunt
37 |
38 | # Bower dependency directory (https://bower.io/)
39 | bower_components
40 |
41 | # node-waf configuration
42 | .lock-wscript
43 |
44 | # Compiled binary addons (https://nodejs.org/api/addons.html)
45 | build/Release
46 |
47 | # Dependency directories
48 | jspm_packages/
49 |
50 | # Snowpack dependency directory (https://snowpack.dev/)
51 | web_modules/
52 |
53 | # VS Code files
54 | .vscode/*
55 | !.vscode/settings.json
56 | !.vscode/tasks.json
57 | !.vscode/launch.json
58 | !.vscode/extensions.json
59 | *.code-workspace
60 |
61 | # macOS files
62 | .DS_Store
63 | .AppleDouble
64 | .LSOverride
65 |
66 | # Thumbnails
67 | ._*
68 |
69 | # Files that might appear in the root of a volume
70 | .DocumentRevisions-V100
71 | .fseventsd
72 | .Spotlight-V100
73 | .TemporaryItems
74 | .Trashes
75 | .VolumeIcon.icns
76 | .com.apple.timemachine.donotpresent
77 |
78 | # Directories potentially created on remote AFP share
79 | .AppleDB
80 | .AppleDesktop
81 | Network Trash Folder
82 | Temporary Items
83 | .apdisk
84 |
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # MCP Wait Timer Server
2 |
3 | An MCP (Model Context Protocol) server providing a simple `wait` tool.
4 |
5 | Watch the demo video: [https://www.youtube.com/watch?v=TaF_j9wrWVw](https://www.youtube.com/watch?v=TaF_j9wrWVw)
6 |
7 | ## Overview
8 |
9 | This server exposes a single tool, `wait`, designed to introduce deliberate pauses into workflows executed by MCP clients (e.g., Cline, Claude Desktop, Cursor).
10 |
11 | ## Problem Solved
12 |
13 | MCP clients and the AI models driving them often operate sequentially. After executing a command or action (like a web request, file operation, or API call), the model might proceed to the next step immediately. However, some actions require additional time to fully complete their effects (e.g., background processes finishing, web pages fully rendering after JavaScript execution, file system propagation).
14 |
15 | Since the model cannot always reliably detect when these asynchronous effects are complete, it might proceed prematurely, leading to errors or incorrect assumptions in subsequent steps.
16 |
17 | ## Solution: The `wait` Tool
18 |
19 | This server provides a `wait` tool that allows the user or the AI prompt to explicitly instruct the client to pause for a specified duration before continuing. This ensures that time-dependent operations have sufficient time to complete.
20 |
21 | **Tool:** `wait`
22 | * **Description:** Pauses execution for a specified number of seconds.
23 | * **Input Parameter:**
24 | * `duration_seconds` (number, required): The duration to wait, in seconds. Must be a positive number.
25 |
26 | ## Use Cases
27 |
28 | * **Web Automation:** Ensure dynamic content loads or scripts finish executing after page navigation or element interaction.
29 | ```
30 | Example Prompt: "Navigate to example.com, fill the login form, click submit, then wait for 5 seconds and capture a screenshot."
31 | ```
32 | * **Command Line Operations:** Allow time for background tasks, file writes, or service startups initiated by a shell command.
33 | ```
34 | Example Prompt: "Run 'npm run build', wait for 15 seconds, then check if the 'dist/app.js' file exists."
35 | ```
36 | * **API Interaction:** Add delays between API calls to handle rate limiting or wait for asynchronous job completion.
37 | * **Workflow Debugging:** Insert pauses to observe the state of the system at specific points during a complex task.
38 |
39 | ## Installation & Setup
40 |
41 | This server requires Node.js (version 16 or higher).
42 |
43 | ### Step 1: Configure Your MCP Client
44 |
45 | Add the following JSON block within the `"mcpServers": {}` object in your client's configuration file. Choose the file corresponding to your client and operating system:
46 |
47 | **Configuration Block:**
48 |
49 | ```json
50 | "wait-timer": {
51 | "command": "npx",
52 | "args": ["mcp-wait-timer"],
53 | "env": {},
54 | "disabled": false,
55 | "autoApprove": []
56 | }
57 | ```
58 |
59 | **Client Configuration File Locations:**
60 |
61 | * **Claude Desktop:**
62 | * macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
63 | * Windows: `%APPDATA%\Claude\claude_desktop_config.json`
64 | * Linux: `~/.config/Claude/claude_desktop_config.json` *(Path may vary slightly)*
65 |
66 | * **VS Code Extension (Cline / "Claude Code"):**
67 | * macOS: `~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`
68 | * Windows: `%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json`
69 | * Linux: `~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`
70 |
71 | * **Cursor:**
72 | * Global: `~/.cursor/mcp.json`
73 | * Project-Specific: Create a file at `.cursor/mcp.json` within your project folder.
74 |
75 | * **Windsurf:**
76 | * `~/.codeium/windsurf/mcp_config.json`
77 |
78 | * **Other Clients:**
79 | * Consult the specific client's documentation for the location of its MCP configuration file. The JSON structure shown in the "Configuration Block" above should generally work.
80 |
81 | ### Step 2: Restart Client
82 |
83 | After adding the configuration block and saving the file, **fully restart** your MCP client application for the changes to take effect. The first time the client starts the server, `npx` will automatically download the `mcp-wait-timer` package if it's not already cached.
84 |
85 | ## Usage Example
86 |
87 | Once installed and enabled, you can instruct your MCP client:
88 |
89 | ```
90 | "Please wait for 10 seconds before proceeding."
91 | ```
92 |
93 | The client's AI model should recognize the intent and call the `wait` tool with `duration_seconds: 10`.
94 |
95 | ## Developed By
96 |
97 | This tool was developed as part of the initiatives at [199 Longevity](https://www.199.company), a group focused on extending the frontiers of human health and longevity.
98 |
99 | Learn more about our work in biotechnology at [199.bio](https://www.199.bio).
100 |
101 | Project contributor: Boris Djordjevic
102 |
103 | ## License
104 |
105 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
106 |
```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "compilerOptions": {
3 | "target": "ES2022",
4 | "module": "Node16",
5 | "moduleResolution": "Node16",
6 | "outDir": "./build",
7 | "rootDir": "./src",
8 | "strict": true,
9 | "esModuleInterop": true,
10 | "skipLibCheck": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "resolveJsonModule": true
13 | },
14 | "include": ["src/**/*"],
15 | "exclude": ["node_modules"]
16 | }
17 |
```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "mcp-wait-timer",
3 | "version": "0.1.8",
4 | "description": "MCP server with a simple wait tool",
5 | "type": "module",
6 | "main": "build/index.js",
7 | "bin": {
8 | "mcp-wait-timer": "./build/index.js"
9 | },
10 | "scripts": {
11 | "build": "tsc && chmod +x build/index.js",
12 | "start": "node build/index.js"
13 | },
14 | "keywords": [
15 | "mcp",
16 | "model-context-protocol"
17 | ],
18 | "author": "Cline",
19 | "license": "MIT",
20 | "dependencies": {
21 | "@modelcontextprotocol/sdk": "^0.4.0",
22 | "zod": "^3.22.4"
23 | },
24 | "devDependencies": {
25 | "@types/node": "^20.11.24",
26 | "typescript": "^5.3.3"
27 | },
28 | "files": [
29 | "build",
30 | "README.md",
31 | "LICENSE",
32 | "CHANGELOG.md"
33 | ]
34 | }
35 |
```
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
```markdown
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 |
8 | ## [0.1.6] - 2025-03-29
9 |
10 | ### Fixed
11 | - Use `z.coerce.number()` for `duration_seconds` to handle string inputs from clients like Claude Desktop.
12 |
13 | ## [0.1.5] - 2025-03-29
14 |
15 | ### Added
16 | - `CHANGELOG.md` file.
17 |
18 | ## [0.1.4] - 2025-03-29
19 |
20 | ### Fixed
21 | - Removed comments from the example JSON configuration block in `README.md`.
22 |
23 | ## [0.1.3] - 2025-03-29
24 |
25 | ### Added
26 | - MIT `LICENSE` file.
27 | - License section in `README.md`.
28 |
29 | ### Changed
30 | - Updated `license` field in `package.json` to "MIT".
31 |
32 | ## [0.1.2] - 2025-03-29
33 |
34 | ### Fixed
35 | - Refactored server code (`src/index.ts`) to align with MCP SDK examples (`Server` class, `setRequestHandler`).
36 | - Reverted build script in `package.json` to use `tsc` instead of `esbuild`.
37 |
38 | ## [0.1.1] - 2025-03-29
39 |
40 | ### Fixed
41 | - Attempted fix for `npx` execution using `esbuild` bundling (later reverted).
42 | - Updated `package.json` build script to use `esbuild`.
43 |
44 | ## [0.1.0] - 2025-03-29
45 |
46 | ### Added
47 | - Initial release of the `mcp-wait-timer` server.
48 | - Basic `wait` tool functionality.
49 | - Configuration for `npx` execution via `package.json` `bin` field.
50 |
```
--------------------------------------------------------------------------------
/src/index.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 {
5 | CallToolRequestSchema,
6 | CallToolResult,
7 | ErrorCode,
8 | ListToolsRequestSchema,
9 | McpError,
10 | Tool,
11 | } from '@modelcontextprotocol/sdk/types.js';
12 | import { z } from 'zod';
13 |
14 | // --- Tool Logic ---
15 |
16 | const waitInputSchemaShape = {
17 | duration_seconds: z.coerce.number().positive().describe('The number of seconds to wait'), // Use coerce.number()
18 | };
19 | const waitInputSchema = z.object(waitInputSchemaShape);
20 |
21 | async function waitHandler(args: z.infer<typeof waitInputSchema>): Promise<CallToolResult> {
22 | const { duration_seconds } = args;
23 | try {
24 | console.error(`[mcp-wait-timer] Waiting for ${duration_seconds} seconds...`);
25 | await new Promise(resolve => setTimeout(resolve, duration_seconds * 1000));
26 | console.error(`[mcp-wait-timer] Wait finished.`);
27 | return {
28 | isError: false,
29 | content: [{ type: 'text', text: `Successfully waited for ${duration_seconds} seconds.` }],
30 | };
31 | } catch (error: any) {
32 | console.error(`[mcp-wait-timer] Error during wait: ${error.message}`);
33 | // Ensure error responses also conform to CallToolResult
34 | return {
35 | isError: true,
36 | content: [{ type: 'text', text: `Error waiting: ${error.message}` }],
37 | };
38 | }
39 | }
40 |
41 | // --- Tool Definition ---
42 |
43 | const WAIT_TOOL: Tool = {
44 | name: 'wait',
45 | description: 'Waits for a specified duration in seconds.',
46 | inputSchema: {
47 | type: 'object',
48 | properties: waitInputSchemaShape,
49 | required: ['duration_seconds'],
50 | },
51 | };
52 |
53 | // --- Server Setup ---
54 |
55 | const server = new Server({
56 | name: 'mcp-wait-timer',
57 | version: '0.1.1', // Will update later before publishing
58 | // Capabilities are defined implicitly via setRequestHandler
59 | });
60 |
61 | // --- Request Handlers ---
62 |
63 | server.setRequestHandler(ListToolsRequestSchema, async () => ({
64 | tools: [WAIT_TOOL],
65 | }));
66 |
67 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
68 | if (request.params.name === WAIT_TOOL.name) {
69 | const parseResult = waitInputSchema.safeParse(request.params.arguments);
70 | if (!parseResult.success) {
71 | throw new McpError(
72 | ErrorCode.InvalidParams,
73 | `Invalid arguments for tool ${WAIT_TOOL.name}: ${parseResult.error.message}`
74 | );
75 | }
76 | return waitHandler(parseResult.data);
77 | }
78 | throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
79 | });
80 |
81 | // --- Main Execution ---
82 |
83 | async function main() {
84 | const transport = new StdioServerTransport();
85 | await server.connect(transport);
86 | console.error('[mcp-wait-timer] Server running on stdio');
87 | // Keep alive
88 | await new Promise(() => {});
89 | }
90 |
91 | main().catch((error) => {
92 | console.error('[mcp-wait-timer] Fatal error:', error);
93 | process.exit(1);
94 | });
95 |
96 | // Graceful shutdown
97 | process.on('SIGINT', async () => {
98 | console.error('[mcp-wait-timer] SIGINT received, shutting down...');
99 | await server.close();
100 | process.exit(0);
101 | });
102 |
103 | process.on('SIGTERM', async () => {
104 | console.error('[mcp-wait-timer] SIGTERM received, shutting down...');
105 | await server.close();
106 | process.exit(0);
107 | });
108 |
```