talktocursor 1.0.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.
package/INSTALL.md ADDED
@@ -0,0 +1,249 @@
1
+ # TalkToCursor - Installation Guide
2
+
3
+ A hands-free voice interface for Cursor AI. Your coding assistant speaks progress updates aloud and can listen for voice commands using ElevenLabs TTS.
4
+
5
+ ---
6
+
7
+ ## Quick Install (via npm)
8
+
9
+ ```bash
10
+ npm install -g talktocursor
11
+ ```
12
+
13
+ Then add to your Cursor MCP config (`~/.cursor/mcp.json`):
14
+
15
+ ```json
16
+ {
17
+ "mcpServers": {
18
+ "tts": {
19
+ "command": "npx",
20
+ "args": ["-y", "talktocursor"]
21
+ }
22
+ }
23
+ }
24
+ ```
25
+
26
+ Skip to [Step 3: Get your ElevenLabs API Key](#step-3-get-your-elevenlabs-api-key).
27
+
28
+ ---
29
+
30
+ ## Manual Install (from source)
31
+
32
+ ### Step 1: Download and extract
33
+
34
+ **Option A** - From tar.gz:
35
+ ```bash
36
+ tar -xzf talk-to-cursor.tar.gz
37
+ cd cursor-tts-mcp
38
+ ```
39
+
40
+ **Option B** - From GitHub:
41
+ ```bash
42
+ git clone https://github.com/yourusername/cursor-tts-mcp.git
43
+ cd cursor-tts-mcp
44
+ ```
45
+
46
+ ### Step 2: Install dependencies and build
47
+
48
+ ```bash
49
+ npm install
50
+ npm run build
51
+ ```
52
+
53
+ Then add to your Cursor MCP config (`~/.cursor/mcp.json`):
54
+
55
+ ```json
56
+ {
57
+ "mcpServers": {
58
+ "tts": {
59
+ "command": "node",
60
+ "args": ["/ABSOLUTE/PATH/TO/cursor-tts-mcp/build/index.js"]
61
+ }
62
+ }
63
+ }
64
+ ```
65
+
66
+ > **Important:** Replace `/ABSOLUTE/PATH/TO/cursor-tts-mcp` with the actual path on your machine.
67
+ >
68
+ > - macOS/Linux: `/Users/yourname/cursor-tts-mcp/build/index.js`
69
+ > - Windows: `C:\\Users\\yourname\\cursor-tts-mcp\\build\\index.js`
70
+
71
+ ---
72
+
73
+ ## Step 3: Get your ElevenLabs API Key
74
+
75
+ 1. Go to [elevenlabs.io/app/settings/api-keys](https://elevenlabs.io/app/settings/api-keys)
76
+ 2. Sign up or log in (free tier available with 10,000 characters/month)
77
+ 3. Create a new API key and copy it
78
+
79
+ ## Step 4: Configure via Settings UI
80
+
81
+ ```bash
82
+ npm run settings
83
+ ```
84
+
85
+ Open **http://localhost:3847** in your browser, then:
86
+
87
+ 1. Paste your ElevenLabs API key and click **Save API Key**
88
+ 2. Click **Test Key** to verify it works
89
+ 3. (Optional) Browse and select a voice
90
+ 4. (Optional) Adjust voice settings (speed, stability, style)
91
+ 5. (Optional) Enable Auto-Listen for hands-free voice loop
92
+
93
+ > **Alternatively**, you can set your API key via environment variable:
94
+ > ```json
95
+ > {
96
+ > "mcpServers": {
97
+ > "tts": {
98
+ > "command": "npx",
99
+ > "args": ["-y", "talktocursor"],
100
+ > "env": {
101
+ > "ELEVENLABS_API_KEY": "your-api-key-here"
102
+ > }
103
+ > }
104
+ > }
105
+ > }
106
+ > ```
107
+
108
+ ## Step 5: Restart Cursor
109
+
110
+ **Fully quit Cursor** (Cmd+Q on Mac) and reopen it. The MCP server needs a fresh restart to load.
111
+
112
+ ## Step 6: Test it
113
+
114
+ 1. Open a new Cursor chat (Cmd+L)
115
+ 2. Check that the `speak` tool appears in "Available Tools"
116
+ 3. Type: **"Say hello using the speak tool"**
117
+ 4. You should hear the voice through your speakers!
118
+
119
+ ---
120
+
121
+ ## Optional: Voice Feedback Rule
122
+
123
+ For the best experience, create a Cursor rule so the agent automatically speaks at key moments.
124
+
125
+ Create the file `~/.cursor/rules/voice-feedback.mdc`:
126
+
127
+ ```markdown
128
+ ---
129
+ description: MANDATORY voice feedback - agent MUST speak at task start and completion
130
+ alwaysApply: true
131
+ ---
132
+
133
+ # Voice Feedback Rule
134
+
135
+ You MUST use the `speak` tool at these moments:
136
+ - **Task Start**: Briefly announce what you're about to do
137
+ - **Task Completion**: Summarize what was done
138
+
139
+ Keep messages concise (1-2 sentences). Always speak at start and end of every task.
140
+ ```
141
+
142
+ ---
143
+
144
+ ## Optional: Hands-Free Dictation (macOS only)
145
+
146
+ For a fully hands-free experience with voice dictation:
147
+
148
+ ### Auto-Submit Setup
149
+
150
+ 1. Enable **Auto-Submit** in the settings UI
151
+ 2. Set up a Python virtual environment:
152
+
153
+ ```bash
154
+ cd cursor-tts-mcp
155
+ python3 -m venv .venv
156
+ source .venv/bin/activate
157
+ pip install pynput pyobjc-framework-ApplicationServices
158
+ ```
159
+
160
+ 3. Run in a separate terminal:
161
+
162
+ ```bash
163
+ npm run auto-submit
164
+ ```
165
+
166
+ 4. Grant Accessibility permissions when prompted:
167
+ - System Settings > Privacy & Security > Accessibility
168
+ - Add your terminal app (Terminal.app, iTerm, or Cursor)
169
+
170
+ ### Wispr Voice Loop Setup (requires Wispr Flow)
171
+
172
+ For a full conversational voice loop using [Wispr Flow](https://wispr.com):
173
+
174
+ 1. Install Wispr Flow and configure its dictation hotkey
175
+ 2. Enable **Wispr Voice Loop** in the settings UI
176
+ 3. Configure the hotkey to match your Wispr Flow settings
177
+ 4. Install additional Python dependency:
178
+
179
+ ```bash
180
+ source .venv/bin/activate
181
+ pip install sounddevice numpy
182
+ brew install portaudio
183
+ ```
184
+
185
+ 5. Grant Microphone permissions to your terminal app
186
+ 6. Run the auto-submit script (handles both auto-submit and voice loop):
187
+
188
+ ```bash
189
+ npm run auto-submit
190
+ ```
191
+
192
+ ---
193
+
194
+ ## Configuration
195
+
196
+ All settings are stored in `config.json` in the project root. You can edit this directly or use the settings UI.
197
+
198
+ | Setting | Description | Default |
199
+ |---------|-------------|---------|
200
+ | `apiKey` | ElevenLabs API key | (required) |
201
+ | `voiceId` | ElevenLabs voice ID | Rachel |
202
+ | `model` | TTS model | `eleven_flash_v2_5` |
203
+ | `voiceSettings.speed` | Speech speed (0.7-1.2) | 1.0 |
204
+ | `voiceSettings.stability` | Voice stability (0-1) | 0.5 |
205
+ | `voiceSettings.similarityBoost` | Voice similarity (0-1) | 0.75 |
206
+ | `voiceSettings.style` | Style exaggeration (0-1) | 0.0 |
207
+ | `autoListen` | Auto-listen after tasks | true |
208
+ | `autoSubmit.enabled` | Auto-press Enter | false |
209
+ | `wisprLoop.enabled` | Voice loop with Wispr | false |
210
+
211
+ ---
212
+
213
+ ## Troubleshooting
214
+
215
+ ### Tool doesn't appear in Cursor
216
+ - Fully quit and restart Cursor (Cmd+Q)
217
+ - Verify `~/.cursor/mcp.json` has the correct path
218
+ - Run `npm run build` to ensure the project is compiled
219
+
220
+ ### "API key not set" error
221
+ - Open settings: `npm run settings`
222
+ - Enter your API key and save
223
+ - Restart Cursor
224
+
225
+ ### No audio output
226
+ - Check system volume and speaker output
227
+ - Verify `mpv` is installed: `brew install mpv`
228
+ - Test your API key in the settings UI
229
+
230
+ ### Auto-submit not working
231
+ - Ensure macOS Accessibility permissions are granted
232
+ - Check that Cursor is the frontmost app
233
+ - Try increasing the silence delay in settings
234
+
235
+ ---
236
+
237
+ ## Scripts Reference
238
+
239
+ | Command | Description |
240
+ |---------|-------------|
241
+ | `npm run build` | Compile TypeScript |
242
+ | `npm run settings` | Open settings UI (port 3847) |
243
+ | `npm run auto-submit` | Start auto-submit + voice loop (macOS) |
244
+
245
+ ---
246
+
247
+ ## License
248
+
249
+ MIT
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # Cursor TTS MCP Server
2
+
3
+ A Model Context Protocol (MCP) server that adds text-to-speech capabilities to Cursor AI. The agent can speak progress updates, completions, and responses aloud using ElevenLabs TTS, enabling hands-free coding workflows.
4
+
5
+ ## Features
6
+
7
+ - 🔊 **Text-to-Speech** - Agent speaks aloud via ElevenLabs API
8
+ - 🎛️ **Settings UI** - Web interface to configure API key, voice, and speech parameters
9
+ - ⚡ **Auto-Submit** - Optional: automatically press Enter when dictation finishes (hands-free)
10
+ - 🎨 **Voice Presets** - Quick settings for fast, slow, expressive, stable, and dramatic speech
11
+ - 🔧 **Configurable** - Speed, stability, similarity boost, and style exaggeration controls
12
+
13
+ ## Installation
14
+
15
+ ### 1. Clone or download this repository
16
+
17
+ ```bash
18
+ git clone https://github.com/yourusername/cursor-tts-mcp.git
19
+ cd cursor-tts-mcp
20
+ ```
21
+
22
+ Or download and extract the ZIP.
23
+
24
+ ### 2. Install dependencies
25
+
26
+ ```bash
27
+ npm install
28
+ ```
29
+
30
+ ### 3. Build the project
31
+
32
+ ```bash
33
+ npm run build
34
+ ```
35
+
36
+ ### 4. Configure Cursor to use the MCP server
37
+
38
+ Edit (or create) `~/.cursor/mcp.json`:
39
+
40
+ ```json
41
+ {
42
+ "mcpServers": {
43
+ "tts": {
44
+ "command": "node",
45
+ "args": ["/ABSOLUTE/PATH/TO/cursor-tts-mcp/build/index.js"]
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ **Important:** Replace `/ABSOLUTE/PATH/TO/cursor-tts-mcp` with the actual full path to where you cloned/downloaded this project.
52
+
53
+ For example:
54
+ - macOS/Linux: `/Users/yourname/cursor-tts-mcp/build/index.js`
55
+ - Windows: `C:\\Users\\yourname\\cursor-tts-mcp\\build\\index.js`
56
+
57
+ ### 5. Get your ElevenLabs API key
58
+
59
+ 1. Go to [elevenlabs.io/app/settings/api-keys](https://elevenlabs.io/app/settings/api-keys)
60
+ 2. Sign up or log in (free tier available)
61
+ 3. Create a new API key and copy it
62
+
63
+ ### 6. Configure the MCP server
64
+
65
+ Open the settings UI:
66
+
67
+ ```bash
68
+ npm run settings
69
+ ```
70
+
71
+ Then open http://localhost:3847 in your browser and:
72
+ 1. Paste your ElevenLabs API key
73
+ 2. Click "Test Key" to verify it works
74
+ 3. Click "Save API Key"
75
+ 4. (Optional) Choose a voice, model, and voice settings
76
+ 5. (Optional) Enable Auto-Submit if you want hands-free dictation
77
+
78
+ ### 7. Restart Cursor
79
+
80
+ **Fully quit Cursor** (Cmd+Q on Mac, or close completely on Windows/Linux) and reopen it.
81
+
82
+ ### 8. Test it
83
+
84
+ 1. Open a new Cursor chat (Cmd+L)
85
+ 2. Check that the `speak` or `user-tts-speak` tool appears in "Available Tools"
86
+ 3. Type: **"Say hello using the speak tool"**
87
+ 4. You should hear the voice through your speakers!
88
+
89
+ ## Usage
90
+
91
+ Once installed, the Cursor AI agent will automatically speak at key moments:
92
+ - When starting a task
93
+ - When completing a task
94
+ - When encountering errors or needing clarification
95
+ - At major progress milestones
96
+
97
+ You can customize when the agent speaks by editing `~/.cursor/rules/voice-feedback.mdc`.
98
+
99
+ ## Voice Settings
100
+
101
+ The settings UI lets you adjust:
102
+
103
+ - **Speed** (0.7x - 1.2x) - How fast the speech is delivered
104
+ - **Stability** (0-1) - More consistent vs. more expressive
105
+ - **Similarity Boost** (0-1) - How closely it matches the original voice
106
+ - **Style Exaggeration** (0-1) - Amplifies the speaker's style (V2+ models)
107
+
108
+ **Quick Presets:**
109
+ - Default - Balanced settings
110
+ - Fast - Quick and energetic
111
+ - Slow - Clear and measured
112
+ - Expressive - Dynamic and varied
113
+ - Stable - Consistent tone
114
+ - Dramatic - Maximum style
115
+
116
+ ## Auto-Submit (Optional)
117
+
118
+ For completely hands-free dictation:
119
+
120
+ 1. Enable "Auto-Submit" in the settings UI
121
+ 2. Adjust the silence delay (how long to wait after you stop speaking)
122
+ 3. Save the settings
123
+ 4. Run in a separate terminal:
124
+
125
+ ```bash
126
+ npm run auto-submit
127
+ ```
128
+
129
+ **Requirements:**
130
+ - macOS only (uses Accessibility API)
131
+ - Grant Accessibility permissions: System Settings > Privacy & Security > Accessibility > Add your terminal app
132
+
133
+ The script monitors the text field and automatically presses Enter when dictation finishes.
134
+
135
+ ## Configuration Files
136
+
137
+ - **`config.json`** - Stores API key, voice settings, and auto-submit preferences
138
+ - **`~/.cursor/mcp.json`** - Registers the MCP server with Cursor
139
+ - **`~/.cursor/rules/voice-feedback.mdc`** - Controls when the agent speaks
140
+
141
+ ## Troubleshooting
142
+
143
+ **Tool doesn't appear in Cursor?**
144
+ - Make sure you fully quit and restarted Cursor (Cmd+Q)
145
+ - Check that `~/.cursor/mcp.json` has the correct absolute path
146
+ - Run `npm run build` to ensure the project is compiled
147
+
148
+ **"API key not set" error?**
149
+ - Open the settings UI: `npm run settings`
150
+ - Enter your ElevenLabs API key and click "Save API Key"
151
+ - Restart Cursor
152
+
153
+ **No audio?**
154
+ - Check system volume and speaker output
155
+ - Verify `mpv` is installed: `mpv --version` (installed automatically by ElevenLabs SDK)
156
+ - Test your API key in the settings UI
157
+
158
+ **Auto-submit not working?**
159
+ - Ensure macOS Accessibility permissions are granted
160
+ - Check that Cursor is the frontmost app when dictating
161
+ - Adjust the "Min Text Length" if short dictations aren't triggering
162
+ - Increase "Silence Delay" if prompts are being submitted too early
163
+
164
+ ## Scripts
165
+
166
+ - `npm run build` - Compile TypeScript to JavaScript
167
+ - `npm run settings` - Open the web settings UI
168
+ - `npm run auto-submit` - Start the auto-submit script (macOS only)
169
+
170
+ ## License
171
+
172
+ MIT
173
+
174
+ ## Credits
175
+
176
+ - [ElevenLabs](https://elevenlabs.io) for TTS API
177
+ - [Model Context Protocol](https://modelcontextprotocol.io) for MCP SDK
@@ -0,0 +1,82 @@
1
+ import { readFileSync, writeFileSync, existsSync } from "fs";
2
+ import { join, dirname } from "path";
3
+ import { fileURLToPath } from "url";
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = dirname(__filename);
6
+ const CONFIG_PATH = join(__dirname, "..", "config.json");
7
+ const DEFAULT_VOICE_SETTINGS = {
8
+ speed: 1.0,
9
+ stability: 0.5,
10
+ similarityBoost: 0.75,
11
+ style: 0.0,
12
+ };
13
+ const DEFAULT_AUTO_SUBMIT = {
14
+ enabled: false,
15
+ silenceDelay: 3.0,
16
+ minTextLength: 15,
17
+ targetApp: "Cursor",
18
+ };
19
+ const DEFAULT_WISPR_LOOP = {
20
+ enabled: false,
21
+ ttsDelay: 8.0,
22
+ silenceThreshold: 0.02,
23
+ silenceDuration: 2.0,
24
+ wisprHotkey: "shift+ctrl",
25
+ manualTriggerHotkey: "ctrl+shift+l",
26
+ };
27
+ const DEFAULT_CONFIG = {
28
+ apiKey: "",
29
+ voiceId: "21m00Tcm4TlvDq8ikWAM",
30
+ model: "eleven_flash_v2_5",
31
+ voiceSettings: { ...DEFAULT_VOICE_SETTINGS },
32
+ autoSubmit: { ...DEFAULT_AUTO_SUBMIT },
33
+ wisprLoop: { ...DEFAULT_WISPR_LOOP },
34
+ autoListen: true,
35
+ };
36
+ export function loadConfig() {
37
+ try {
38
+ if (existsSync(CONFIG_PATH)) {
39
+ const raw = readFileSync(CONFIG_PATH, "utf-8");
40
+ const parsed = JSON.parse(raw);
41
+ return {
42
+ ...DEFAULT_CONFIG,
43
+ ...parsed,
44
+ voiceSettings: {
45
+ ...DEFAULT_VOICE_SETTINGS,
46
+ ...(parsed.voiceSettings || {}),
47
+ },
48
+ autoSubmit: {
49
+ ...DEFAULT_AUTO_SUBMIT,
50
+ ...(parsed.autoSubmit || {}),
51
+ },
52
+ wisprLoop: {
53
+ ...DEFAULT_WISPR_LOOP,
54
+ ...(parsed.wisprLoop || {}),
55
+ },
56
+ autoListen: parsed.autoListen !== undefined ? parsed.autoListen : DEFAULT_CONFIG.autoListen,
57
+ };
58
+ }
59
+ }
60
+ catch (error) {
61
+ console.error("[Config] Error reading config.json:", error);
62
+ }
63
+ return { ...DEFAULT_CONFIG, voiceSettings: { ...DEFAULT_VOICE_SETTINGS }, autoSubmit: { ...DEFAULT_AUTO_SUBMIT }, wisprLoop: { ...DEFAULT_WISPR_LOOP }, autoListen: DEFAULT_CONFIG.autoListen };
64
+ }
65
+ export function saveConfig(config) {
66
+ const current = loadConfig();
67
+ const updated = { ...current, ...config };
68
+ writeFileSync(CONFIG_PATH, JSON.stringify(updated, null, 2), "utf-8");
69
+ return updated;
70
+ }
71
+ export function getEffectiveConfig() {
72
+ const fileConfig = loadConfig();
73
+ return {
74
+ apiKey: process.env.ELEVENLABS_API_KEY || fileConfig.apiKey,
75
+ voiceId: process.env.ELEVENLABS_VOICE_ID || fileConfig.voiceId,
76
+ model: fileConfig.model || DEFAULT_CONFIG.model,
77
+ voiceSettings: fileConfig.voiceSettings,
78
+ autoSubmit: fileConfig.autoSubmit,
79
+ wisprLoop: fileConfig.wisprLoop,
80
+ autoListen: fileConfig.autoListen,
81
+ };
82
+ }
package/build/index.js ADDED
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ import { ElevenLabsClient, play } from "@elevenlabs/elevenlabs-js";
6
+ import { getEffectiveConfig } from "./config.js";
7
+ import { writeFileSync } from "fs";
8
+ import { join, dirname } from "path";
9
+ import { fileURLToPath } from "url";
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+ // Load config (config.json with env var overrides)
13
+ const config = getEffectiveConfig();
14
+ // Create server instance
15
+ const server = new McpServer({
16
+ name: "cursor-tts",
17
+ version: "1.0.0",
18
+ });
19
+ // Initialize ElevenLabs client
20
+ const elevenlabs = new ElevenLabsClient({
21
+ apiKey: config.apiKey,
22
+ });
23
+ const voiceId = config.voiceId;
24
+ const ttsQueue = [];
25
+ let isProcessingQueue = false;
26
+ async function processTTSQueue() {
27
+ if (isProcessingQueue || ttsQueue.length === 0) {
28
+ return;
29
+ }
30
+ isProcessingQueue = true;
31
+ while (ttsQueue.length > 0) {
32
+ const item = ttsQueue.shift();
33
+ try {
34
+ console.error(`[TTS] Speaking: ${item.text}`);
35
+ // Call ElevenLabs TTS API
36
+ const audio = await elevenlabs.textToSpeech.convert(voiceId, {
37
+ text: item.text,
38
+ modelId: config.model,
39
+ voiceSettings: {
40
+ speed: config.voiceSettings.speed,
41
+ stability: config.voiceSettings.stability,
42
+ similarityBoost: config.voiceSettings.similarityBoost,
43
+ style: config.voiceSettings.style,
44
+ },
45
+ });
46
+ // Play and WAIT for audio to complete
47
+ await play(audio);
48
+ // Write TTS completion signal for background script
49
+ const completionPath = join(__dirname, "..", "tts-complete.json");
50
+ const completionSignal = {
51
+ timestamp: new Date().toISOString(),
52
+ completed: true,
53
+ };
54
+ writeFileSync(completionPath, JSON.stringify(completionSignal, null, 2), "utf-8");
55
+ console.error(`[TTS] Playback complete, signal written: ${completionPath}`);
56
+ item.resolve({
57
+ content: [
58
+ {
59
+ type: "text",
60
+ text: `Spoken: "${item.text}"`,
61
+ },
62
+ ],
63
+ });
64
+ }
65
+ catch (error) {
66
+ const errorMessage = error instanceof Error ? error.message : String(error);
67
+ console.error(`[TTS] Error: ${errorMessage}`);
68
+ item.reject({
69
+ content: [
70
+ {
71
+ type: "text",
72
+ text: `Failed to speak: ${errorMessage}`,
73
+ },
74
+ ],
75
+ isError: true,
76
+ });
77
+ }
78
+ }
79
+ isProcessingQueue = false;
80
+ }
81
+ function queueTTS(text) {
82
+ return new Promise((resolve, reject) => {
83
+ ttsQueue.push({ text, resolve, reject });
84
+ processTTSQueue();
85
+ });
86
+ }
87
+ // Register the speak tool
88
+ server.registerTool("speak", {
89
+ description: "Speak text aloud using text-to-speech. Use this to announce task progress, completions, and important updates so the user can follow along without looking at the screen.",
90
+ inputSchema: {
91
+ text: z
92
+ .string()
93
+ .describe("The text to speak aloud. Keep it concise (1-2 sentences max)."),
94
+ },
95
+ }, async ({ text }) => {
96
+ // Queue the TTS request to prevent overlapping audio
97
+ return await queueTTS(text);
98
+ });
99
+ // Register the listen tool
100
+ server.registerTool("listen", {
101
+ description: "Signal the background script to start listening for user voice input via Wispr Flow. Call this after speaking task completion to enable hands-free conversational loop.",
102
+ inputSchema: {},
103
+ }, async () => {
104
+ try {
105
+ // Check if auto-listen is enabled
106
+ if (!config.autoListen) {
107
+ console.error(`[TTS] Auto-listen is disabled, skipping listen signal`);
108
+ return {
109
+ content: [
110
+ {
111
+ type: "text",
112
+ text: "Auto-listen is disabled",
113
+ },
114
+ ],
115
+ };
116
+ }
117
+ const signalPath = join(__dirname, "..", "listen-signal.json");
118
+ const signal = {
119
+ timestamp: new Date().toISOString(),
120
+ triggered: true,
121
+ };
122
+ writeFileSync(signalPath, JSON.stringify(signal, null, 2), "utf-8");
123
+ console.error(`[TTS] Listen signal written: ${signalPath}`);
124
+ return {
125
+ content: [
126
+ {
127
+ type: "text",
128
+ text: "Listening for user input...",
129
+ },
130
+ ],
131
+ };
132
+ }
133
+ catch (error) {
134
+ const errorMessage = error instanceof Error ? error.message : String(error);
135
+ console.error(`[TTS] Listen error: ${errorMessage}`);
136
+ return {
137
+ content: [
138
+ {
139
+ type: "text",
140
+ text: `Failed to start listening: ${errorMessage}`,
141
+ },
142
+ ],
143
+ isError: true,
144
+ };
145
+ }
146
+ });
147
+ // Main function to start the server
148
+ async function main() {
149
+ // Validate API key
150
+ if (!config.apiKey) {
151
+ console.error("[TTS] ERROR: No API key found! Set ELEVENLABS_API_KEY env var or configure via the settings UI.");
152
+ console.error("[TTS] Run 'npm run settings' to open the settings UI.");
153
+ console.error("[TTS] Or get your API key from: https://elevenlabs.io/app/settings/api-keys");
154
+ process.exit(1);
155
+ }
156
+ console.error(`[TTS] Starting Cursor TTS MCP Server...`);
157
+ console.error(`[TTS] Voice ID: ${voiceId}`);
158
+ console.error(`[TTS] Model: ${config.model}`);
159
+ const transport = new StdioServerTransport();
160
+ await server.connect(transport);
161
+ console.error("[TTS] Server running on stdio");
162
+ }
163
+ main().catch((error) => {
164
+ console.error("[TTS] Fatal error in main():", error);
165
+ process.exit(1);
166
+ });