Second Opinion
STDIOAI-powered assistance for coding problems using Gemini, Stack Overflow, and Perplexity insights.
AI-powered assistance for coding problems using Gemini, Stack Overflow, and Perplexity insights.
An MCP server that provides AI-powered assistance for coding problems by combining insights from:
npm install
npm run build
{ "mcpServers": { "second-opinion": { "command": "node", "args": ["/path/to/second-opinion-server/build/index.js"], "env": { "GEMINI_API_KEY": "your-gemini-api-key", "PERPLEXITY_API_KEY": "your-perplexity-api-key", "STACK_EXCHANGE_KEY": "your-stack-exchange-key" } } } }
Required environment variables:
GEMINI_API_KEY
: Google's Gemini AI API keyPERPLEXITY_API_KEY
: Perplexity AI API keySTACK_EXCHANGE_KEY
: Stack Exchange API key (optional, uses anonymous access if not provided)The server provides a single tool:
Get AI-powered insights and solutions for coding problems.
Input Schema:
{ "goal": "string (required) - What you're trying to accomplish", "error": "string (optional) - Any error messages you're seeing", "code": "string (optional) - Relevant code context", "solutionsTried": "string (optional) - What solutions you've already tried", "filePath": "string (optional) - Path to the file with the issue" }
Example Input:
{ "goal": "Fix React useEffect cleanup error", "error": "React Hook useEffect has a missing dependency: 'socket'. Either include it in the dependency array, or remove the dependency array react-hooks/exhaustive-deps", "code": "useEffect(() => {\n socket.on('message', handleMessage);\n return () => socket.off('message');\n}, []);", "solutionsTried": "I tried adding socket to the dependency array but then it causes infinite re-renders" }
Example Response:
The core issue lies in how React's useEffect
hook manages side effects and their dependencies. When you provide an empty dependency array ([]
), you're telling React that the effect should only run once when the component mounts and that the cleanup function should run when the component unmounts.
However, in your code, the socket
object is used within the effect. This creates a closure where the handleMessage
function and the cleanup function (socket.off('message')
) implicitly depend on the current value of socket
. If socket
ever changes (e.g., due to a reconnection or reinitialization), your effect will be using an outdated socket
instance.
handleMessage
) might be working with an old socket
objectsocket.off('message')
might not remove the intended event listenerimport React, { useEffect, useRef } from 'react'; function MyComponent({ socket }) { const socketRef = useRef(socket); useEffect(() => { const currentSocket = socketRef.current; currentSocket.on('message', handleMessage); return () => { currentSocket.off('message'); }; }, []); // Empty dependency array is now safe }
Why This Works:
useRef
creates a mutable object that persists across rendersimport React, { useEffect, useRef, useCallback } from 'react'; function MyComponent({ socket, someProp }) { const socketRef = useRef(socket); const handleMessage = useCallback((message) => { // Do something with the message and potentially someProp console.log(message, someProp); }, [someProp]); // Include dependencies of handleMessage useEffect(() => { const currentSocket = socketRef.current; currentSocket.on('message', handleMessage); return () => { currentSocket.off('message', handleMessage); }; }, [handleMessage]); // Depend on the memoized handler }
import React, { useEffect, useState } from 'react'; function MyComponent() { const [messages, setMessages] = useState([]); useEffect(() => { const socket = new WebSocket('your_websocket_url'); const handleMessage = (message) => { setMessages((prevMessages) => [...prevMessages, message]); }; socket.on('message', handleMessage); return () => { socket.off('message', handleMessage); socket.close(); }; }, []); // Empty array is correct - socket lifecycle managed within }
function useSocket(url) { const [messages, setMessages] = useState([]); const socketRef = useRef(null); useEffect(() => { const socket = new WebSocket(url); socketRef.current = socket; const handleMessage = (message) => { setMessages((prevMessages) => [...prevMessages, message]); }; socket.on('message', handleMessage); return () => { socket.off('message', handleMessage); socket.close(); }; }, [url]); const sendMessage = useCallback((message) => { if (socketRef.current?.readyState === WebSocket.OPEN) { socketRef.current.send(message); } }, []); return { messages, sendMessage }; }
Dependency Management
useRef
for stable referencesuseCallback
Performance Optimization
Error Handling
Testing Considerations
src/
├── config.ts # Configuration and API settings
├── fileUtils.ts # File operations and language detection
├── index.ts # Entry point
├── perplexity.ts # Perplexity AI integration
├── server.ts # MCP server implementation
├── stackOverflow.ts # Stack Overflow API integration
└── types.ts # TypeScript interfaces
See errors.md for current issues and workarounds.