두 번째 의견 MCP 서버
다음의 통찰력을 결합하여 코딩 문제에 대한 AI 기반 지원을 제공하는 MCP 서버:
- 구글의 제미니 AI
- Stack Overflow에서 수락된 답변
- Perplexity AI 분석
특징
- 다양한 소스의 컨텍스트를 통해 코딩 문제에 대한 자세한 솔루션을 얻으세요
- 파일 확장자에서 자동 언어 감지
- 코드 조각 추출 및 서식 지정
- 솔루션을 위한 마크다운 보고서 생성
- Git 인식 파일 컨텍스트 수집
설정
- 종속성 설치:
지엑스피1
- 서버를 빌드하세요:
- MCP 설정에서 환경 변수를 구성합니다.
{
"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"
}
}
}
}
필수 환경 변수:
GEMINI_API_KEY
: Google의 Gemini AI API 키PERPLEXITY_API_KEY
: Perplexity AI API 키STACK_EXCHANGE_KEY
: Stack Exchange API 키(선택 사항, 제공하지 않으면 익명 액세스 사용)
용법
서버는 단일 도구를 제공합니다.
두 번째 의견을 얻으세요
코딩 문제에 대한 AI 기반 통찰력과 솔루션을 얻으세요.
입력 스키마:
{
"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"
}
입력 예시:
{
"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"
}
응답 예시:
문제 이해
핵심 문제는 React의 useEffect
훅이 부작용과 그 종속성을 관리하는 방식에 있습니다. 빈 종속성 배열( []
)을 제공하면 React에게 컴포넌트가 마운트될 때 효과가 한 번만 실행되고, 컴포넌트가 언마운트될 때 정리 함수가 실행되어야 한다는 것을 알려주는 것입니다.
하지만 코드에서는 이펙트 내에서 socket
객체가 사용됩니다. 이로 인해 handleMessage
함수와 정리 함수( socket.off('message')
)가 암묵적으로 socket
의 현재 값에 의존하는 클로저가 생성됩니다. socket
변경되는 경우(예: 재연결 또는 재초기화) 이펙트는 오래된 socket
인스턴스를 사용하게 됩니다.
일반적인 문제
- 오래된 폐쇄: 이벤트 핸들러(
handleMessage
)가 오래된 socket
객체와 함께 작동하고 있을 수 있습니다. - 잘못된 정리:
socket.off('message')
의도한 이벤트 리스너를 제거하지 못할 수 있습니다. - 메모리 누수: 정리에 실패하면 메모리 누수 및 예기치 않은 동작이 발생할 수 있습니다.
솔루션
1. 안정적인 참조를 위해 useRef 사용
import 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
}
이것이 효과적인 이유:
useRef
렌더링 간에 지속되는 변경 가능한 객체를 생성합니다.- 참조 객체 자체는 변경되지 않으므로 효과가 다시 실행되지 않습니다.
- ref를 통해 최신 소켓 값에 접근할 수 있습니다.
2. 핸들러에 useCallback 사용
import 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
}
3. useEffect 내부에서 소켓 수명 주기 관리
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
}
4. 커스텀 후크 솔루션
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 };
}
모범 사례
- 종속성 관리
- 안정적인 참조를 위해
useRef
사용하세요 useCallback
사용하여 핸들러 메모하기- 소켓 수명 주기 관리를 고려하세요
- 성능 최적화
- 불필요한 재렌더링을 최소화하세요
- 대용량 메시지를 효율적으로 처리하세요
- 적절한 정리 패턴을 사용하세요
- 오류 처리
- 연결 오류를 정상적으로 처리합니다
- 필요한 경우 재연결 논리를 구현합니다.
- 리소스를 적절하게 정리하세요
- 테스트 고려 사항
- 테스트에서 모의 WebSocket 연결
- 이벤트 리스너 정리 확인
- 테스트 오류 시나리오
프로젝트 구조
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
알려진 문제
현재 문제와 해결 방법은 errors.md에서 확인하세요.