セカンドオピニオンMCPサーバー
以下の洞察を組み合わせて、コーディングの問題に対する AI を活用した支援を提供する MCP サーバー:
GoogleのGemini AI
Stack Overflow で承認された回答
困惑のAI分析
特徴
Related MCP server: Claude Code + Gemini MCP Server
設定
依存関係をインストールします:
サーバーを構築します。
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 キー (オプション、指定しない場合は匿名アクセスが使用されます)
使用法
サーバーは次の単一のツールを提供します:
2番目の意見を得る
コーディングの問題に対する 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フックが副作用とその依存関係をどのように管理しているかにあります。空の依存関係配列( [] )を指定すると、コンポーネントのマウント時に副作用を1回だけ実行し、コンポーネントのアンマウント時にクリーンアップ関数を実行するようにReactに指示することになります。
しかし、コード内ではsocketオブジェクトがエフェクト内で使用されています。これにより、 handleMessage関数とクリーンアップ関数 ( socket.off('message') ) が暗黙的にsocketの現在の値に依存するクロージャが作成されます。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オブジェクト自体は変更されないため、エフェクトの再実行は防止されます。
最新のソケット値には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 を参照してください。