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

```
├── .gitignore
├── Dockerfile
├── index.ts
├── package-lock.json
├── package.json
├── README.md
├── smithery.yaml
└── tsconfig.json
```

# Files

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

```
 1 | # Node.js dependencies
 2 | node_modules/
 3 | 
 4 | # Bun
 5 | .bun/
 6 | 
 7 | # Logs
 8 | logs
 9 | *.log
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | 
14 | # OS specific files
15 | .DS_Store
16 | Thumbs.db
17 | 
18 | # IDE specific files
19 | .idea/
20 | .vscode/
21 | *.swp
22 | *.swo
23 | 
24 | # Build outputs
25 | dist/
26 | build/
27 | 
28 | # Environment variables
29 | .env
30 | .env.local
31 | .env.development.local
32 | .env.test.local
33 | .env.production.local
34 | 
```

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

```markdown
  1 | # Claude ChatGPT MCP Tool
  2 | 
  3 | This is a Model Context Protocol (MCP) tool that allows Claude to interact with the ChatGPT desktop app on macOS.
  4 | 
  5 | ## Features
  6 | 
  7 | - Ask ChatGPT questions directly from Claude
  8 | - View ChatGPT conversation history
  9 | - Continue existing ChatGPT conversations
 10 | 
 11 | ## Installation
 12 | 
 13 | ### Prerequisites
 14 | 
 15 | - macOS with M1/M2/M3 chip
 16 | - [ChatGPT desktop app](https://chatgpt.com/download) installed
 17 | - [Bun](https://bun.sh/) installed
 18 | - [Claude desktop app](https://claude.ai/desktop) installed
 19 | 
 20 | ### NPX Installation (Recommended)
 21 | 
 22 | You can use NPX to run this tool without cloning the repository:
 23 | 
 24 | - **Install and run the package using NPX:**
 25 | 
 26 | ```bash
 27 | npx claude-chatgpt-mcp
 28 | ```
 29 | 
 30 | - **Configure Claude Desktop:**
 31 | 
 32 | Edit your `claude_desktop_config.json` file (located at `~/Library/Application Support/Claude/claude_desktop_config.json`) to include this tool:
 33 | 
 34 | ```json
 35 | "chatgpt-mcp": {
 36 |   "command": "npx",
 37 |   "args": ["claude-chatgpt-mcp"]
 38 | }
 39 | ```
 40 | 
 41 | - **Restart the Claude Desktop app**
 42 | 
 43 | - **Grant necessary permissions:**
 44 |   - Go to System Preferences > Privacy & Security > Privacy
 45 |   - Give Terminal (or iTerm) access to Accessibility features
 46 |   - You may see permission prompts when the tool is first used
 47 | 
 48 | ### Manual Installation
 49 | 
 50 | 1. Clone this repository:
 51 | 
 52 | ```bash
 53 | git clone https://github.com/syedazharmbnr1/claude-chatgpt-mcp.git
 54 | cd claude-chatgpt-mcp
 55 | ```
 56 | 
 57 | 2. Install dependencies:
 58 | 
 59 | ```bash
 60 | bun install
 61 | ```
 62 | 
 63 | 3. Make sure the script is executable:
 64 | 
 65 | ```bash
 66 | chmod +x index.ts
 67 | ```
 68 | 
 69 | 4. Update your Claude Desktop configuration:
 70 | 
 71 | Edit your `claude_desktop_config.json` file (located at `~/Library/Application Support/Claude/claude_desktop_config.json`) to include this tool:
 72 | 
 73 | ```json
 74 | "chatgpt-mcp": {
 75 |   "command": "/Users/YOURUSERNAME/.bun/bin/bun",
 76 |   "args": ["run", "/path/to/claude-chatgpt-mcp/index.ts"]
 77 | }
 78 | ```
 79 | 
 80 | Make sure to replace `YOURUSERNAME` with your actual macOS username and adjust the path to where you cloned this repository.
 81 | 
 82 | 5. Restart Claude Desktop app
 83 | 
 84 | 6. Grant permissions:
 85 |    - Go to System Preferences > Privacy & Security > Privacy
 86 |    - Give Terminal (or iTerm) access to Accessibility features
 87 |    - You may see permission prompts when the tool is first used
 88 | 
 89 | ## Usage
 90 | 
 91 | Once installed, you can use the ChatGPT tool directly from Claude by asking questions like:
 92 | 
 93 | - "Can you ask ChatGPT what the capital of France is?"
 94 | - "Show me my recent ChatGPT conversations"
 95 | - "Ask ChatGPT to explain quantum computing"
 96 | 
 97 | ## Troubleshooting
 98 | 
 99 | If the tool isn't working properly:
100 | 
101 | 1. Make sure ChatGPT app is installed and you're logged in
102 | 2. Verify the path to bun in your claude_desktop_config.json is correct
103 | 3. Check that you've granted all necessary permissions
104 | 4. Try restarting both Claude and ChatGPT apps
105 | 
106 | ## Optimizations
107 | 
108 | This fork includes several significant improvements to the original implementation:
109 | 
110 | ### Enhanced AppleScript Robustness
111 | 
112 | #### Conversation Retrieval
113 | - Added multiple UI element targeting approaches to handle ChatGPT UI changes
114 | - Implemented better error detection with specific error messages
115 | - Added fallback mechanisms using accessibility attributes
116 | - Improved timeout handling with appropriate delays
117 | 
118 | #### Response Handling
119 | - Replaced fixed waiting times with dynamic response detection
120 | - Added intelligent completion detection that recognizes when ChatGPT has finished typing
121 | - Implemented text stability detection (waits until text stops changing)
122 | - Added response extraction logic to isolate just the relevant response text
123 | - Improved error handling with detailed error messages
124 | - Added post-processing to clean up UI elements from responses
125 | - Implemented incomplete response detection to warn about potential cutoffs
126 | 
127 | These optimizations make the integration more reliable across different scenarios, more resilient to UI changes in the ChatGPT application, and better at handling longer response times without message cutoff issues.
128 | 
129 | ## License
130 | 
131 | MIT
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | FROM node:18-slim
 2 | 
 3 | WORKDIR /app
 4 | 
 5 | # Copy package.json and package-lock.json
 6 | COPY package*.json ./
 7 | 
 8 | # Install dependencies
 9 | RUN npm install
10 | 
11 | # Copy source code
12 | COPY . .
13 | 
14 | # Build TypeScript code
15 | RUN npm run build
16 | 
17 | # Set executable permissions for the entry point
18 | RUN chmod +x dist/index.js
19 | 
20 | # Start the MCP server
21 | CMD ["node", "dist/index.js"]
22 | 
```

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

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "NodeNext",
 5 |     "moduleResolution": "NodeNext",
 6 |     "esModuleInterop": true,
 7 |     "strict": true,
 8 |     "outDir": "dist",
 9 |     "declaration": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true
12 |   },
13 |   "include": ["index.ts"],
14 |   "exclude": ["node_modules", "dist"]
15 | }
16 | 
```

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

```json
 1 | {
 2 |   "name": "claude-chatgpt-mcp",
 3 |   "version": "1.0.1",
 4 |   "main": "dist/index.js",
 5 |   "type": "module",
 6 |   "description": "A Claude MCP tool to interact with the ChatGPT desktop app on macOS",
 7 |   "author": "Syed Azhar",
 8 |   "license": "MIT",
 9 |   "bin": {
10 |     "claude-chatgpt-mcp": "dist/index.js"
11 |   },
12 |   "repository": {
13 |     "type": "git",
14 |     "url": "git+https://github.com/syedazharmbnr1/claude-chatgpt-mcp.git"
15 |   },
16 |   "keywords": [
17 |     "mcp",
18 |     "claude",
19 |     "chatgpt",
20 |     "mac"
21 |   ],
22 |   "scripts": {
23 |     "dev": "bun run index.ts",
24 |     "build": "tsc",
25 |     "prepare": "npm run build",
26 |     "start": "node dist/index.js"
27 |   },
28 |   "dependencies": {
29 |     "@jxa/global-type": "^1.3.6",
30 |     "@jxa/run": "^1.3.6",
31 |     "@modelcontextprotocol/sdk": "^1.5.0",
32 |     "run-applescript": "^7.0.0"
33 |   },
34 |   "devDependencies": {
35 |     "@types/bun": "latest",
36 |     "@types/node": "^22.13.4",
37 |     "typescript": "^5.4.2"
38 |   },
39 |   "files": [
40 |     "dist",
41 |     "README.md"
42 |   ],
43 |   "engines": {
44 |     "node": ">=18"
45 |   }
46 | }
47 | 
```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | # Smithery configuration for claude-chatgpt-mcp
 2 | startCommand:
 3 |   type: stdio
 4 |   configSchema:
 5 |     type: object
 6 |     properties:
 7 |       logLevel:
 8 |         type: string
 9 |         enum: [error, warn, info, debug]
10 |         description: "Logging level for the ChatGPT MCP tool"
11 |         default: "info"
12 |     additionalProperties: false
13 |   commandFunction: |
14 |     function(config) {
15 |       const env = { 
16 |         NODE_ENV: 'production'
17 |       };
18 |       
19 |       if (config && config.logLevel) {
20 |         env.LOG_LEVEL = config.logLevel;
21 |       }
22 |       
23 |       return {
24 |         command: 'node',
25 |         args: ['dist/index.js'],
26 |         env: env
27 |       };
28 |     }
29 | 
30 | # Build configuration
31 | build:
32 |   dockerfile: Dockerfile
33 |   dockerBuildPath: .
34 | 
35 | # Metadata for Smithery.ai
36 | metadata:
37 |   name: "Claude ChatGPT MCP Tool"
38 |   description: "A Model Context Protocol (MCP) tool that allows Claude to interact with the ChatGPT desktop app on macOS"
39 |   version: "1.0.1"
40 |   author: "Syed Azhar"
41 |   license: "MIT"
42 |   repository: "https://github.com/syedazharmbnr1/claude-chatgpt-mcp"
43 |   keywords: ["mcp", "claude", "chatgpt", "mac"]
44 | 
```

--------------------------------------------------------------------------------
/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 | 	ListToolsRequestSchema,
  7 | 	type Tool,
  8 | } from "@modelcontextprotocol/sdk/types.js";
  9 | import { runAppleScript } from "run-applescript";
 10 | import { run } from "@jxa/run";
 11 | 
 12 | // Define the ChatGPT tool
 13 | const CHATGPT_TOOL: Tool = {
 14 | 	name: "chatgpt",
 15 | 	description: "Interact with the ChatGPT desktop app on macOS",
 16 | 	inputSchema: {
 17 | 		type: "object",
 18 | 		properties: {
 19 | 			operation: {
 20 | 				type: "string",
 21 | 				description: "Operation to perform: 'ask' or 'get_conversations'",
 22 | 				enum: ["ask", "get_conversations"],
 23 | 			},
 24 | 			prompt: {
 25 | 				type: "string",
 26 | 				description:
 27 | 					"The prompt to send to ChatGPT (required for ask operation)",
 28 | 			},
 29 | 			conversation_id: {
 30 | 				type: "string",
 31 | 				description:
 32 | 					"Optional conversation ID to continue a specific conversation",
 33 | 			},
 34 | 		},
 35 | 		required: ["operation"],
 36 | 	},
 37 | };
 38 | 
 39 | const server = new Server(
 40 | 	{
 41 | 		name: "ChatGPT MCP Tool",
 42 | 		version: "1.0.0",
 43 | 	},
 44 | 	{
 45 | 		capabilities: {
 46 | 			tools: {},
 47 | 		},
 48 | 	},
 49 | );
 50 | 
 51 | // Check if ChatGPT app is installed and running
 52 | async function checkChatGPTAccess(): Promise<boolean> {
 53 | 	try {
 54 | 		const isRunning = await runAppleScript(`
 55 |       tell application "System Events"
 56 |         return application process "ChatGPT" exists
 57 |       end tell
 58 |     `);
 59 | 
 60 | 		if (isRunning !== "true") {
 61 | 			console.log("ChatGPT app is not running, attempting to launch...");
 62 | 			try {
 63 | 				await runAppleScript(`
 64 |           tell application "ChatGPT" to activate
 65 |           delay 2
 66 |         `);
 67 | 			} catch (activateError) {
 68 | 				console.error("Error activating ChatGPT app:", activateError);
 69 | 				throw new Error(
 70 | 					"Could not activate ChatGPT app. Please start it manually.",
 71 | 				);
 72 | 			}
 73 | 		}
 74 | 
 75 | 		return true;
 76 | 	} catch (error) {
 77 | 		console.error("ChatGPT access check failed:", error);
 78 | 		throw new Error(
 79 | 			`Cannot access ChatGPT app. Please make sure ChatGPT is installed and properly configured. Error: ${error instanceof Error ? error.message : String(error)}`,
 80 | 		);
 81 | 	}
 82 | }
 83 | 
 84 | // Function to send a prompt to ChatGPT
 85 | async function askChatGPT(
 86 | 	prompt: string,
 87 | 	conversationId?: string,
 88 | ): Promise<string> {
 89 | 	await checkChatGPTAccess();
 90 | 	try {
 91 | 		// Function to properly encode text for AppleScript, including handling of Chinese characters
 92 | 		const encodeForAppleScript = (text: string): string => {
 93 | 			// Only escape double quotes, leave other characters as is
 94 | 			return text.replace(/"/g, '\\"');
 95 | 		};
 96 | 
 97 | 		const encodedPrompt = encodeForAppleScript(prompt);
 98 | 		
 99 | 		// Save original clipboard content
100 | 		const saveClipboardScript = `
101 | 			set savedClipboard to the clipboard
102 | 			return savedClipboard
103 | 		`;
104 | 		const originalClipboard = await runAppleScript(saveClipboardScript);
105 | 		const encodedOriginalClipboard = encodeForAppleScript(originalClipboard);
106 | 		
107 | 		const script = `
108 |       tell application "ChatGPT"
109 |         activate
110 |         delay 1
111 |         tell application "System Events"
112 |           tell process "ChatGPT"
113 |             ${
114 | 							conversationId
115 | 								? `
116 |               try
117 |                 click button "${conversationId}" of group 1 of group 1 of window 1
118 |                 delay 1
119 |               end try
120 |             `
121 | 								: ""
122 | 						}
123 |             -- Clear any existing text in the input field
124 |             keystroke "a" using {command down}
125 |             keystroke (ASCII character 8) -- Delete key
126 |             delay 0.5
127 |             
128 |             -- Set the clipboard to the prompt text
129 |             set the clipboard to "${encodedPrompt}"
130 |             
131 |             -- Paste the prompt and send it
132 |             keystroke "v" using {command down}
133 |             delay 0.5
134 |             keystroke return
135 |             
136 |             -- Wait for the response with dynamic detection
137 |             set maxWaitTime to 120 -- Maximum wait time in seconds
138 |             set waitInterval to 1 -- Check interval in seconds
139 |             set totalWaitTime to 0
140 |             set previousText to ""
141 |             set stableCount to 0
142 |             set requiredStableChecks to 3 -- Number of consecutive stable checks required
143 |             
144 |             repeat while totalWaitTime < maxWaitTime
145 |               delay waitInterval
146 |               set totalWaitTime to totalWaitTime + waitInterval
147 |               
148 |               -- Get current text
149 |               set frontWin to front window
150 |               set allUIElements to entire contents of frontWin
151 |               set conversationText to {}
152 |               repeat with e in allUIElements
153 |                 try
154 |                   if (role of e) is "AXStaticText" then
155 |                     set end of conversationText to (description of e)
156 |                   end if
157 |                 end try
158 |               end repeat
159 |               
160 |               set AppleScript's text item delimiters to linefeed
161 |               set currentText to conversationText as text
162 |               
163 |               -- Check if text has stabilized (not changing anymore)
164 |               if currentText is equal to previousText then
165 |                 set stableCount to stableCount + 1
166 |                 if stableCount ≥ requiredStableChecks then
167 |                   -- Text has been stable for multiple checks, assume response is complete
168 |                   exit repeat
169 |                 end if
170 |               else
171 |                 -- Text changed, reset stable count
172 |                 set stableCount to 0
173 |                 set previousText to currentText
174 |               end if
175 |               
176 |               -- Check for response completion indicators
177 |               if currentText contains "▍" then
178 |                 -- ChatGPT is still typing (blinking cursor indicator)
179 |                 set stableCount to 0
180 |               else if currentText contains "Regenerate" or currentText contains "Continue generating" then
181 |                 -- Response likely complete if these UI elements are visible
182 |                 set stableCount to stableCount + 1
183 |               end if
184 |             end repeat
185 |             
186 |             -- Final check for text content
187 |             if (count of conversationText) = 0 then
188 |               return "No response text found. ChatGPT may still be processing or encountered an error."
189 |             else
190 |               -- Extract just the latest response
191 |               set responseText to ""
192 |               try
193 |                 -- Attempt to find the latest response by looking for patterns
194 |                 set AppleScript's text item delimiters to linefeed
195 |                 set fullText to conversationText as text
196 |                 
197 |                 -- Look for the prompt in the text to find where the response starts
198 |                 set promptPattern to "${prompt.replace(/"/g, '\\"').replace(/\n/g, ' ')}"
199 |                 if fullText contains promptPattern then
200 |                   set promptPos to offset of promptPattern in fullText
201 |                   if promptPos > 0 then
202 |                     -- Get text after the prompt
203 |                     set responseText to text from (promptPos + (length of promptPattern)) to end of fullText
204 |                   end if
205 |                 end if
206 |                 
207 |                 -- If we couldn't find the prompt, return the full text
208 |                 if responseText is "" then
209 |                   set responseText to fullText
210 |                 end if
211 |                 
212 |                 return responseText
213 |               on error
214 |                 -- Fallback to returning all text if parsing fails
215 |                 return conversationText as text
216 |               end try
217 |             end if
218 |           end tell
219 |         end tell
220 |       end tell
221 |     `;
222 | 		const result = await runAppleScript(script);
223 | 		
224 | 		// Restore original clipboard content
225 | 		await runAppleScript(`set the clipboard to "${encodedOriginalClipboard}"`);
226 | 		
227 | 		// Post-process the result to clean up any UI text that might have been captured
228 | 		let cleanedResult = result
229 | 			.replace(/Regenerate( response)?/g, '')
230 | 			.replace(/Continue generating/g, '')
231 | 			.replace(/▍/g, '')
232 | 			.trim();
233 | 			
234 | 		// More context-aware incomplete response detection
235 | 		const isLikelyComplete = 
236 | 			cleanedResult.length > 50 || // Longer responses are likely complete
237 | 			cleanedResult.endsWith('.') || 
238 | 			cleanedResult.endsWith('!') || 
239 | 			cleanedResult.endsWith('?') ||
240 | 			cleanedResult.endsWith(':') ||
241 | 			cleanedResult.endsWith(')') ||
242 | 			cleanedResult.endsWith('}') ||
243 | 			cleanedResult.endsWith(']') ||
244 | 			cleanedResult.includes('\n\n') || // Multiple paragraphs suggest completeness
245 | 			/^[A-Z].*[.!?]$/.test(cleanedResult); // Complete sentence structure
246 | 			
247 | 		if (cleanedResult.length > 0 && !isLikelyComplete) {
248 | 			console.warn("Warning: ChatGPT response may be incomplete");
249 | 		}
250 | 		
251 | 		return cleanedResult;
252 | 	} catch (error) {
253 | 		console.error("Error interacting with ChatGPT:", error);
254 | 		throw new Error(
255 | 			`Failed to get response from ChatGPT: ${
256 | 				error instanceof Error ? error.message : String(error)
257 | 			}`,
258 | 		);
259 | 	}
260 | }
261 | 
262 | // Function to get available conversations
263 | async function getConversations(): Promise<string[]> {
264 | 	try {
265 | 		// Run AppleScript to get conversations from ChatGPT app
266 | 		const result = await runAppleScript(`
267 |       -- Check if ChatGPT is running
268 |       tell application "System Events"
269 |         if not (application process "ChatGPT" exists) then
270 |           return "ChatGPT is not running"
271 |         end if
272 |       end tell
273 | 
274 |       tell application "ChatGPT"
275 |         -- Activate ChatGPT and give it time to respond
276 |         activate
277 |         delay 1.5
278 | 
279 |         tell application "System Events"
280 |           tell process "ChatGPT"
281 |             -- Check if ChatGPT window exists
282 |             if not (exists window 1) then
283 |               return "No ChatGPT window found"
284 |             end if
285 |             
286 |             -- Try to get conversation titles with multiple approaches
287 |             set conversationsList to {}
288 |             
289 |             try
290 |               -- First attempt: try buttons in group 1 of group 1
291 |               if exists group 1 of group 1 of window 1 then
292 |                 set chatButtons to buttons of group 1 of group 1 of window 1
293 |                 repeat with chatButton in chatButtons
294 |                   set buttonName to name of chatButton
295 |                   if buttonName is not "New chat" then
296 |                     set end of conversationsList to buttonName
297 |                   end if
298 |                 end repeat
299 |               end if
300 |               
301 |               -- If we didn't find any conversations, try an alternative approach
302 |               if (count of conversationsList) is 0 then
303 |                 -- Try to find UI elements by accessibility description
304 |                 set uiElements to UI elements of window 1
305 |                 repeat with elem in uiElements
306 |                   try
307 |                     if exists (attribute "AXDescription" of elem) then
308 |                       set elemDesc to value of attribute "AXDescription" of elem
309 |                       if elemDesc is not "New chat" and elemDesc is not "" then
310 |                         set end of conversationsList to elemDesc
311 |                       end if
312 |                     end if
313 |                   end try
314 |                 end repeat
315 |               end if
316 |               
317 |               -- If still no conversations found, return a specific message
318 |               if (count of conversationsList) is 0 then
319 |                 return "No conversations found"
320 |               end if
321 |             on error errMsg
322 |               -- Return error message for debugging
323 |               return "Error: " & errMsg
324 |             end try
325 |             
326 |             return conversationsList
327 |           end tell
328 |         end tell
329 |       end tell
330 |     `);
331 | 
332 | 		// Parse the AppleScript result into an array
333 | 		if (result === "ChatGPT is not running") {
334 | 			console.error("ChatGPT application is not running");
335 | 			throw new Error("ChatGPT application is not running");
336 | 		} else if (result === "No ChatGPT window found") {
337 | 			console.error("No ChatGPT window found");
338 | 			throw new Error("No ChatGPT window found");
339 | 		} else if (result === "No conversations found") {
340 | 			console.error("No conversations found in ChatGPT");
341 | 			return []; // Return empty array instead of error message
342 | 		} else if (result.startsWith("Error:")) {
343 | 			console.error(result);
344 | 			throw new Error(result);
345 | 		}
346 | 		
347 | 		const conversations = result.split(", ");
348 | 		return conversations;
349 | 	} catch (error) {
350 | 		console.error("Error getting ChatGPT conversations:", error);
351 | 		throw new Error("Error retrieving conversations: " + (error instanceof Error ? error.message : String(error)));
352 | 	}
353 | }
354 | 
355 | function isChatGPTArgs(args: unknown): args is {
356 | 	operation: "ask" | "get_conversations";
357 | 	prompt?: string;
358 | 	conversation_id?: string;
359 | } {
360 | 	if (typeof args !== "object" || args === null) return false;
361 | 
362 | 	const { operation, prompt, conversation_id } = args as any;
363 | 
364 | 	if (!operation || !["ask", "get_conversations"].includes(operation)) {
365 | 		return false;
366 | 	}
367 | 
368 | 	// Validate required fields based on operation
369 | 	if (operation === "ask" && !prompt) return false;
370 | 
371 | 	// Validate field types if present
372 | 	if (prompt && typeof prompt !== "string") return false;
373 | 	if (conversation_id && typeof conversation_id !== "string") return false;
374 | 
375 | 	return true;
376 | }
377 | 
378 | server.setRequestHandler(ListToolsRequestSchema, async () => ({
379 | 	tools: [CHATGPT_TOOL],
380 | }));
381 | 
382 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
383 | 	try {
384 | 		const { name, arguments: args } = request.params;
385 | 
386 | 		if (!args) {
387 | 			throw new Error("No arguments provided");
388 | 		}
389 | 
390 | 		if (name === "chatgpt") {
391 | 			if (!isChatGPTArgs(args)) {
392 | 				throw new Error("Invalid arguments for ChatGPT tool");
393 | 			}
394 | 
395 | 			switch (args.operation) {
396 | 				case "ask": {
397 | 					if (!args.prompt) {
398 | 						throw new Error("Prompt is required for ask operation");
399 | 					}
400 | 
401 | 					const response = await askChatGPT(args.prompt, args.conversation_id);
402 | 
403 | 					return {
404 | 						content: [
405 | 							{
406 | 								type: "text",
407 | 								text: response || "No response received from ChatGPT.",
408 | 							},
409 | 						],
410 | 						isError: false,
411 | 					};
412 | 				}
413 | 
414 | 				case "get_conversations": {
415 | 					const conversations = await getConversations();
416 | 
417 | 					return {
418 | 						content: [
419 | 							{
420 | 								type: "text",
421 | 								text:
422 | 									conversations.length > 0
423 | 										? `Found ${conversations.length} conversation(s):\n\n${conversations.join("\n")}`
424 | 										: "No conversations found in ChatGPT.",
425 | 							},
426 | 						],
427 | 						isError: false,
428 | 					};
429 | 				}
430 | 
431 | 				default:
432 | 					throw new Error(`Unknown operation: ${args.operation}`);
433 | 			}
434 | 		}
435 | 
436 | 		return {
437 | 			content: [{ type: "text", text: `Unknown tool: ${name}` }],
438 | 			isError: true,
439 | 		};
440 | 	} catch (error) {
441 | 		return {
442 | 			content: [
443 | 				{
444 | 					type: "text",
445 | 					text: `Error: ${error instanceof Error ? error.message : String(error)}`,
446 | 				},
447 | 			],
448 | 			isError: true,
449 | 		};
450 | 	}
451 | });
452 | 
453 | const transport = new StdioServerTransport();
454 | 
455 | await server.connect(transport);
456 | console.error("ChatGPT MCP Server running on stdio");
457 | 
```