#
tokens: 1985/50000 5/5 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── dist
│   └── index.js
├── package-lock.json
├── package.json
├── README.md
├── sounds
│   └── completion.mp3
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
 2 | 
 3 | # dependencies
 4 | /node_modules
 5 | /.pnp
 6 | .pnp.js
 7 | 
 8 | # Database
 9 | *.db
10 | 
11 | # testing
12 | /coverage
13 | 
14 | # storybook
15 | storybook-static
16 | *storybook.log
17 | 
18 | # playwright
19 | /test-results/
20 | /playwright-report/
21 | /playwright/.cache/
22 | 
23 | # next.js
24 | /.next
25 | /out
26 | 
27 | # cache
28 | .swc/
29 | 
30 | # production
31 | /build
32 | 
33 | # misc
34 | .DS_Store
35 | *.pem
36 | Thumbs.db
37 | 
38 | # debug
39 | npm-debug.log*
40 | pnpm-debug.log*
41 | yarn-debug.log*
42 | yarn-error.log*
43 | 
44 | # local env files
45 | .env*.local
46 | 
47 | # Sentry Config File
48 | .env.sentry-build-plugin
49 | 
50 | # local folder
51 | local
52 | 
53 | # vercel
54 | .vercel
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Cursor Sound MCP
 2 | 
 3 | A Model Context Protocol (MCP) implementation that plays sound effects after Cursor AI completes code generation. This MCP integrates with Cursor to provide audio feedback for a more interactive coding experience.
 4 | 
 5 | Inspired by @EricListin on X.com - I have made some changes to the code to not error out and be online.
 6 | 
 7 | ## Features
 8 | 
 9 | - Plays a sound effect when Cursor completes code generation
10 | - Uses the Model Context Protocol (MCP) for standardized integration
11 | - Configurable sound effects
12 | - Improved error handling and logging
13 | - Stable JSON response format
14 | 
15 | ## Cursor Rules
16 | 
17 | Add this to your Cursor custom instructions:
18 | 
19 | "EVERY TIME you finish any task or you need something from me, run the sound-mcp MCP server to get my attention."
20 | 
21 | ## Installation
22 | 
23 | 1. Install dependencies:
24 | ```bash
25 | npm install
26 | ```
27 | 
28 | 2. Add your sound effects:
29 | Place your sound files in the `sounds` directory. The default expected sound is:
30 | - `sounds/completion.mp3` - Played after code generation
31 | 
32 | You can find free sound effects on freesound.org.
33 | 
34 | 3. Build the project:
35 | ```bash
36 | npm run build
37 | ```
38 | 
39 | ## Usage
40 | 
41 | Run the MCP server:
42 | ```bash
43 | npm start
44 | ```
45 | 
46 | The server will start and listen for events from Cursor through the stdio transport.
47 | 
48 | ## Configuration
49 | 
50 | The sound effects and volume can be customized by:
51 | 1. Replacing the sound files in the `sounds` directory
52 | 2. Modifying the sound file paths in `src/index.ts`
53 | 
54 | ## Development
55 | 
56 | For development with auto-recompilation:
57 | ```bash
58 | npm run dev
59 | ```
60 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "ES2022",
 5 |     "moduleResolution": "node",
 6 |     "outDir": "./dist",
 7 |     "rootDir": "./src",
 8 |     "strict": true,
 9 |     "esModuleInterop": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true,
12 |     "typeRoots": ["./src/types", "./node_modules/@types"]
13 |   },
14 |   "include": ["src/**/*"],
15 |   "exclude": ["node_modules", "dist"]
16 | }
17 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "cursor-sound-mcp",
 3 |   "version": "1.0.0",
 4 |   "description": "MCP for Cursor that plays sounds after code generation",
 5 |   "main": "dist/index.js",
 6 |   "type": "module",
 7 |   "scripts": {
 8 |     "build": "tsc",
 9 |     "start": "node dist/index.js",
10 |     "dev": "tsc -w"
11 |   },
12 |   "keywords": [
13 |     "mcp",
14 |     "cursor",
15 |     "sound"
16 |   ],
17 |   "author": "",
18 |   "license": "ISC",
19 |   "dependencies": {
20 |     "@modelcontextprotocol/sdk": "latest",
21 |     "@types/play-sound": "^1.1.2",
22 |     "play-sound": "^1.1.5",
23 |     "zod": "^3.24.2"
24 |   },
25 |   "devDependencies": {
26 |     "@types/node": "^20.0.0",
27 |     "typescript": "^5.0.0"
28 |   }
29 | }
30 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
 2 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
 3 | import player from 'play-sound';
 4 | import path from 'path';
 5 | import { fileURLToPath } from 'url';
 6 | 
 7 | // Get the directory name of the current module
 8 | const __filename = fileURLToPath(import.meta.url);
 9 | const __dirname = path.dirname(__filename);
10 | 
11 | const audioPlayer = player();
12 | // Use the custom sound file from the sounds directory
13 | const COMPLETION_SOUND = path.join(__dirname, '..', 'sounds', 'completion.mp3');
14 | 
15 | // Set up a proper logging function that uses stderr
16 | const log = (message: string) => {
17 |   process.stderr.write(`${message}\n`);
18 | };
19 | 
20 | async function main() {
21 |   const server = new McpServer({
22 |     name: 'CursorSoundMCP',
23 |     version: '1.0.0'
24 |   });
25 | 
26 |   // Tool to play sound after code generation
27 |   server.tool(
28 |     'playCompletionSound',
29 |     'Plays a completion sound when called',
30 |     async () => {
31 |       try {
32 |         // Play custom sound using a Promise to handle the callback properly
33 |         await new Promise<void>((resolve, reject) => {
34 |           audioPlayer.play(COMPLETION_SOUND, (err: Error | null) => {
35 |             if (err) {
36 |               log(`Error playing sound: ${err.message}`);
37 |               reject(err);
38 |             } else {
39 |               log('Played completion sound successfully');
40 |               resolve();
41 |             }
42 |           });
43 |         });
44 |         
45 |         // Return proper JSON response
46 |         return {
47 |           content: [{ type: 'text', text: 'Played completion sound' }]
48 |         };
49 |       } catch (error) {
50 |         log(`Failed to play sound: ${error}`);
51 |         return {
52 |           content: [{ type: 'text', text: 'Failed to play sound' }]
53 |         };
54 |       }
55 |     }
56 |   );
57 | 
58 |   // Start the server using stdio transport
59 |   const transport = new StdioServerTransport();
60 |   await server.connect(transport);
61 | 
62 |   log('Cursor Sound MCP server started...');
63 | }
64 | 
65 | main().catch(error => {
66 |   log(`Failed to start MCP server: ${error}`);
67 |   process.exit(1);
68 | });
69 | 
```