├── assets └── sleep-server.png ├── .gitignore ├── tsconfig.json ├── jest.config.js ├── src ├── services │ ├── sleep.ts │ └── __tests__ │ │ └── sleep.test.ts └── index.ts ├── package.json └── README.md /assets/sleep-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Garoth/sleep-mcp/HEAD/assets/sleep-server.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules/ 3 | npm-debug.log* 4 | yarn-debug.log* 5 | yarn-error.log* 6 | 7 | # Build output 8 | build/ 9 | dist/ 10 | *.tsbuildinfo 11 | 12 | # IDE 13 | .idea/ 14 | .vscode/ 15 | *.swp 16 | *.swo 17 | 18 | # Environment 19 | .env 20 | .env.local 21 | .env.*.local 22 | 23 | # OS 24 | .DS_Store 25 | Thumbs.db 26 | -------------------------------------------------------------------------------- /tsconfig.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 | }, 13 | "include": ["src/**/*"], 14 | "exclude": ["node_modules"] 15 | } 16 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | export default { 3 | preset: 'ts-jest', 4 | testEnvironment: 'node', 5 | extensionsToTreatAsEsm: ['.ts'], 6 | moduleNameMapper: { 7 | '^(\\.{1,2}/.*)\\.js$': '$1', 8 | }, 9 | transform: { 10 | '^.+\\.tsx?$': [ 11 | 'ts-jest', 12 | { 13 | useESM: true, 14 | }, 15 | ], 16 | }, 17 | testMatch: [ 18 | "**/src/**/__tests__/**/*.ts", 19 | "**/src/**/*.test.ts" 20 | ], 21 | }; 22 | -------------------------------------------------------------------------------- /src/services/sleep.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Service class that handles sleep functionality 3 | */ 4 | export class SleepService { 5 | /** 6 | * Wait for the specified duration 7 | * @param ms Duration to wait in milliseconds 8 | * @returns Promise that resolves after the duration 9 | */ 10 | async sleep(ms: number): Promise { 11 | if (isNaN(ms) || ms < 0) { 12 | throw new Error("milliseconds must be a non-negative number"); 13 | } 14 | 15 | return new Promise(resolve => setTimeout(resolve, ms)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sleep-server", 3 | "version": "1.0.0", 4 | "description": "Allows AI agents to wait a while, such as adding a delay between an API call and seeing the result", 5 | "private": true, 6 | "type": "module", 7 | "bin": { 8 | "sleep-server": "./build/index.js" 9 | }, 10 | "files": [ 11 | "build" 12 | ], 13 | "scripts": { 14 | "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"", 15 | "prepare": "npm run build", 16 | "watch": "tsc --watch", 17 | "inspector": "npx @modelcontextprotocol/inspector build/index.js", 18 | "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", 19 | "test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch" 20 | }, 21 | "dependencies": { 22 | "@modelcontextprotocol/sdk": "0.6.0" 23 | }, 24 | "devDependencies": { 25 | "@types/jest": "^29.5.14", 26 | "@types/node": "^20.11.24", 27 | "jest": "^29.7.0", 28 | "ts-jest": "^29.2.5", 29 | "typescript": "^5.3.3" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sleep MCP Server 2 | 3 | Sleep MCP Logo 4 | 5 | A Model Context Protocol (MCP) server that provides a simple sleep/wait tool. Useful for adding delays between operations, such as waiting between API calls or testing eventually consistent systems. 6 | 7 | ## Available Tools 8 | 9 | - `sleep`: Wait for a specified duration in milliseconds 10 | 11 | ## Installation 12 | 13 | ```bash 14 | git clone https://github.com/Garoth/sleep-mcp.git 15 | npm install 16 | ``` 17 | 18 | ## Configuration 19 | 20 | Add to your Cline MCP settings file (ex. ~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json): 21 | 22 | ```json 23 | { 24 | "mcpServers": { 25 | "sleep": { 26 | "command": "node", 27 | "args": ["/path/to/sleep-server/build/index.js"], 28 | "disabled": false, 29 | "autoApprove": [], 30 | "timeout": 300 31 | } 32 | } 33 | } 34 | ``` 35 | 36 | > **Note:** The `timeout` parameter specifies the maximum time (in milliseconds) that the MCP server will wait for a response before timing out. This is particularly important for the sleep tool, as setting a timeout that's shorter than your sleep duration will cause the operation to fail. Make sure your timeout value is always greater than the maximum sleep duration you plan to use. 37 | 38 | ## Development 39 | 40 | ### Setting Up Tests 41 | 42 | The tests verify the sleep functionality with various durations: 43 | 44 | ```bash 45 | npm test 46 | ``` 47 | 48 | ### Building 49 | 50 | ```bash 51 | npm run build 52 | ``` 53 | 54 | ## License 55 | 56 | MIT 57 | -------------------------------------------------------------------------------- /src/services/__tests__/sleep.test.ts: -------------------------------------------------------------------------------- 1 | import { jest } from '@jest/globals'; 2 | import { SleepService } from '../sleep.js'; 3 | 4 | describe('SleepService', () => { 5 | let service: SleepService; 6 | 7 | beforeEach(() => { 8 | service = new SleepService(); 9 | jest.useFakeTimers(); 10 | }); 11 | 12 | afterEach(() => { 13 | jest.useRealTimers(); 14 | }); 15 | 16 | describe('sleep', () => { 17 | it('should wait for the specified duration', async () => { 18 | const duration = 1000; 19 | const promise = service.sleep(duration); 20 | 21 | // Fast-forward time 22 | jest.advanceTimersByTime(duration); 23 | 24 | await promise; // Should resolve without throwing 25 | }); 26 | 27 | it('should reject negative durations', async () => { 28 | await expect(service.sleep(-1000)) 29 | .rejects 30 | .toThrow('milliseconds must be a non-negative number'); 31 | }); 32 | 33 | it('should reject NaN durations', async () => { 34 | await expect(service.sleep(NaN)) 35 | .rejects 36 | .toThrow('milliseconds must be a non-negative number'); 37 | }); 38 | 39 | it('should handle zero duration', async () => { 40 | const promise = service.sleep(0); 41 | jest.advanceTimersByTime(0); 42 | await promise; // Should resolve without throwing 43 | }); 44 | 45 | it('should handle large durations', async () => { 46 | const duration = 24 * 60 * 60 * 1000; // 24 hours 47 | const promise = service.sleep(duration); 48 | jest.advanceTimersByTime(duration); 49 | await promise; // Should resolve without throwing 50 | }); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { Server } from "@modelcontextprotocol/sdk/server/index.js"; 4 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 5 | import { 6 | CallToolRequestSchema, 7 | ListToolsRequestSchema, 8 | ErrorCode, 9 | McpError, 10 | } from "@modelcontextprotocol/sdk/types.js"; 11 | import { SleepService } from "./services/sleep.js"; 12 | 13 | const service = new SleepService(); 14 | const server = new Server( 15 | { 16 | name: "sleep-server", 17 | version: "1.0.0", 18 | }, 19 | { 20 | capabilities: { 21 | tools: {}, 22 | }, 23 | } 24 | ); 25 | 26 | /** 27 | * Handler that lists available tools. 28 | * Exposes a single "sleep" tool that waits for a specified duration. 29 | */ 30 | server.setRequestHandler(ListToolsRequestSchema, async () => { 31 | return { 32 | tools: [ 33 | { 34 | name: "sleep", 35 | description: "Wait for a specified duration", 36 | inputSchema: { 37 | type: "object", 38 | properties: { 39 | milliseconds: { 40 | type: "number", 41 | description: "Duration to wait in milliseconds", 42 | minimum: 0 43 | } 44 | }, 45 | required: ["milliseconds"] 46 | } 47 | } 48 | ] 49 | }; 50 | }); 51 | 52 | /** 53 | * Handler for the sleep tool. 54 | * Waits for the specified duration and returns a success message. 55 | */ 56 | server.setRequestHandler(CallToolRequestSchema, async (request) => { 57 | if (request.params.name !== "sleep") { 58 | throw new McpError(ErrorCode.MethodNotFound, "Unknown tool"); 59 | } 60 | 61 | try { 62 | const ms = Number(request.params.arguments?.milliseconds); 63 | await service.sleep(ms); 64 | 65 | return { 66 | content: [{ 67 | type: "text", 68 | text: `Waited for ${ms} milliseconds` 69 | }] 70 | }; 71 | } catch (error) { 72 | throw new McpError( 73 | ErrorCode.InvalidParams, 74 | error instanceof Error ? error.message : "Unknown error" 75 | ); 76 | } 77 | }); 78 | 79 | /** 80 | * Start the server using stdio transport. 81 | */ 82 | async function main() { 83 | const transport = new StdioServerTransport(); 84 | await server.connect(transport); 85 | console.error('Sleep MCP server running on stdio'); 86 | } 87 | 88 | main().catch((error) => { 89 | console.error("Server error:", error); 90 | process.exit(1); 91 | }); 92 | --------------------------------------------------------------------------------