🔗 MCP Integration Made Simple
Right now, you have chat, images, audio transcription, files, speech synthesis, vision, and voice interaction working in your application. But what if your AI could access external data sources and services in real-time?
MCP (Model Context Protocol) opens up endless possibilities. Instead of being limited to built-in capabilities, your AI can connect to databases, APIs, file systems, and specialized services, creating truly powerful and dynamic applications.
You’re about to learn exactly how to add MCP integration to your existing application.
🧠 Step 1: Understanding MCP Integration
Section titled “🧠 Step 1: Understanding MCP Integration”Before we write any code, let’s understand what MCP actually means and why it’s different from what you’ve built before.
What MCP Actually Means
Section titled “What MCP Actually Means”MCP (Model Context Protocol) is like giving your AI superpowers to connect with the outside world. Your AI can access real-time data, interact with databases, call APIs, read files, and use specialized tools - all through standardized connections.
Real-world analogy: It’s like giving your AI access to a workshop full of specialized tools. Instead of just being able to think and respond, it can now use calculators, encyclopedias, databases, weather stations, and any other tool you connect to it.
Why MCP vs. Your Existing Features
Section titled “Why MCP vs. Your Existing Features”You already have powerful AI capabilities, but MCP integration is different:
💬 Chat Features - AI thinks and responds (internal intelligence)
🎤 Voice/Audio - AI processes and generates audio (built-in capabilities)
🔗 MCP Integration - AI accesses external systems (external connections)
The key difference: MCP allows your AI to interact with the real world beyond its training data, accessing live information and performing actions through connected services.
Real-World Use Cases
Section titled “Real-World Use Cases”Think about all the times your AI needs external data or actions:
- Live data access - Current weather, stock prices, news updates
- Database integration - Customer records, inventory systems, user data
- File system access - Reading configurations, processing documents
- API interactions - Social media posting, email sending, payment processing
- Specialized tools - Calendar management, task tracking, analytics
Without MCP integration, your AI is limited to:
- Static knowledge from training data (outdated information)
- Built-in capabilities only (no external connections)
- Manual data input (users must provide all context)
- Isolated functionality (can’t interact with your systems)
With MCP integration, your AI can access live data and perform real actions through connected services.
MCP Server Capabilities
Section titled “MCP Server Capabilities”Your MCP integration will connect to remote MCP servers:
🌐 Remote MCP Servers - External Data Connectors
- Best for: Accessing specialized data sources and services
- Strengths: Real-time data, specialized APIs, third-party integrations
- Use cases: Weather data, knowledge bases, file systems, databases
- Think of it as: Your AI’s connection to the digital world
Key capabilities:
- Real-time data access from external sources
- Standardized protocol for consistent integration
- Multiple server support for diverse data sources
- Secure connections with proper authentication
🔧 Step 2: Adding MCP Integration to Your Backend
Section titled “🔧 Step 2: Adding MCP Integration to Your Backend”Let’s add MCP integration to your existing backend using the same patterns you learned in previous modules. We’ll add new routes to handle MCP connections and data retrieval.
Building on your foundation: You already have a working Node.js server with OpenAI integration. We’re simply adding MCP connectivity to enhance your AI’s capabilities.
Step 2A: Understanding MCP Integration State
Section titled “Step 2A: Understanding MCP Integration State”Before writing code, let’s understand what data our MCP integration system needs to manage:
// 🧠 MCP INTEGRATION STATE CONCEPTS:// 1. Server Connections - Available MCP servers and their capabilities// 2. Resource Access - Tools and data sources from connected servers// 3. Chat Context - Enhanced messages with MCP data and tool calls// 4. Tool Results - Responses from MCP server tools and resources// 5. Session Management - Persistent connections and state
Key MCP integration concepts:
- Server Discovery: Finding and connecting to available MCP servers
- Resource Mapping: Understanding what tools and data each server provides
- Tool Execution: Calling MCP server functions and retrieving results
- Context Enhancement: Enriching AI conversations with external data
Step 2B: Installing Required Dependencies
Section titled “Step 2B: Installing Required Dependencies”First, add the MCP client dependencies to your backend. In your backend folder, run:
npm install @modelcontextprotocol/sdk
What this package does:
- @modelcontextprotocol/sdk: Official MCP client for connecting to MCP servers
Step 2C: Adding the MCP Integration Routes
Section titled “Step 2C: Adding the MCP Integration Routes”Add these new endpoints to your existing index.js
file, right after your voice interaction routes:
import { Client } from '@modelcontextprotocol/sdk/client/index.js';import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
// 🔗 MCP CLIENT SETUP: Initialize MCP connectionslet mcpClients = new Map();
// Initialize MCP server connectionconst initializeMCPServer = async (serverUrl, serverName = 'default') => { try { console.log(`🔗 Connecting to MCP server: ${serverUrl}`);
// Create MCP client for remote server const transport = new StdioClientTransport({ command: 'node', args: ['-e', ` const { createMCPProxy } = require('@modelcontextprotocol/sdk'); createMCPProxy('${serverUrl}'); `] });
const client = new Client( { name: serverName, version: "1.0.0" }, { capabilities: { resources: {}, tools: {}, prompts: {} } } );
await client.connect(transport); mcpClients.set(serverName, client);
console.log(`✅ Connected to MCP server: ${serverName}`); return client;
} catch (error) { console.error(`❌ Failed to connect to MCP server ${serverName}:`, error); throw error; }};
// 🔗 MCP SERVERS ENDPOINT: List available MCP serversapp.get("/api/mcp/servers", async (req, res) => { try { const servers = [];
for (const [name, client] of mcpClients) { try { // Get server capabilities const resources = await client.listResources(); const tools = await client.listTools(); const prompts = await client.listPrompts();
servers.push({ name, status: 'connected', capabilities: { resources: resources.resources?.length || 0, tools: tools.tools?.length || 0, prompts: prompts.prompts?.length || 0 }, resources: resources.resources || [], tools: tools.tools || [], prompts: prompts.prompts || [] }); } catch (error) { servers.push({ name, status: 'error', error: error.message }); } }
res.json({ success: true, servers, total_servers: servers.length });
} catch (error) { console.error("MCP servers listing error:", error); res.status(500).json({ error: "Failed to list MCP servers", details: error.message, success: false }); }});
// 🔗 MCP CONNECT ENDPOINT: Connect to new MCP serverapp.post("/api/mcp/connect", async (req, res) => { try { const { server_url, server_name = 'custom' } = req.body;
if (!server_url) { return res.status(400).json({ error: "Server URL is required", success: false }); }
console.log(`🔗 Connecting to MCP server: ${server_url}`);
// Initialize the MCP server connection const client = await initializeMCPServer(server_url, server_name);
// Get server capabilities const resources = await client.listResources(); const tools = await client.listTools(); const prompts = await client.listPrompts();
res.json({ success: true, server: { name: server_name, url: server_url, status: 'connected', capabilities: { resources: resources.resources?.length || 0, tools: tools.tools?.length || 0, prompts: prompts.prompts?.length || 0 }, resources: resources.resources || [], tools: tools.tools || [], prompts: prompts.prompts || [] } });
} catch (error) { console.error("MCP connection error:", error); res.status(500).json({ error: "Failed to connect to MCP server", details: error.message, success: false }); }});
// 🔗 MCP CHAT ENDPOINT: Chat with MCP-enhanced AIapp.post("/api/mcp/chat", async (req, res) => { try { const { message, conversation_history = [], use_servers = ['default'], stream = false } = req.body;
if (!message) { return res.status(400).json({ error: "Message is required", success: false }); }
console.log(`🔗 MCP Chat: ${message.substring(0, 50)}...`);
// 🔍 RESOURCE DISCOVERY: Get available MCP resources and tools let availableTools = []; let availableResources = [];
for (const serverName of use_servers) { const client = mcpClients.get(serverName); if (client) { try { const resources = await client.listResources(); const tools = await client.listTools();
availableTools.push(...(tools.tools || [])); availableResources.push(...(resources.resources || [])); } catch (error) { console.warn(`Warning: Could not get resources from ${serverName}:`, error.message); } } }
// 🎯 ENHANCED CHAT: Create OpenAI chat with MCP tools const messages = [ { role: "system", content: `You are an intelligent AI assistant with access to external data sources and tools through MCP (Model Context Protocol).
Available MCP Resources: ${availableResources.map(r => `${r.name} (${r.description || 'No description'})`).join(', ')}Available MCP Tools: ${availableTools.map(t => `${t.name} (${t.description || 'No description'})`).join(', ')}
You can access real-time data and perform actions using these connected services. When appropriate, use MCP tools to enhance your responses with live, accurate information.` }, ...conversation_history, { role: "user", content: message } ];
// Convert MCP tools to OpenAI format const openaiTools = availableTools.map(tool => ({ type: "function", function: { name: `mcp_${tool.name}`, description: tool.description || `Execute ${tool.name} from MCP server`, parameters: tool.inputSchema || { type: "object", properties: {}, required: [] } } }));
const chatParams = { model: "gpt-4", messages, temperature: 0.7, max_tokens: 2000 };
if (openaiTools.length > 0) { chatParams.tools = openaiTools; chatParams.tool_choice = "auto"; }
if (stream) { chatParams.stream = true; }
const response = await openai.chat.completions.create(chatParams);
// 🔧 TOOL EXECUTION: Handle MCP tool calls let finalResponse = response; let toolResults = [];
if (response.choices[0].message.tool_calls) { const toolCalls = response.choices[0].message.tool_calls;
for (const toolCall of toolCalls) { const toolName = toolCall.function.name.replace('mcp_', ''); const toolArgs = JSON.parse(toolCall.function.arguments);
try { // Find the appropriate MCP client let toolResult = null; for (const serverName of use_servers) { const client = mcpClients.get(serverName); if (client) { try { toolResult = await client.callTool({ name: toolName, arguments: toolArgs }); break; } catch (error) { console.warn(`Tool ${toolName} not found in ${serverName}:`, error.message); } } }
if (toolResult) { toolResults.push({ tool_call_id: toolCall.id, tool_name: toolName, arguments: toolArgs, result: toolResult.content }); } } catch (error) { console.error(`Error executing MCP tool ${toolName}:`, error); toolResults.push({ tool_call_id: toolCall.id, tool_name: toolName, arguments: toolArgs, error: error.message }); } }
// Get final response with tool results if (toolResults.length > 0) { const toolMessages = [ ...messages, response.choices[0].message, ...toolResults.map(result => ({ role: "tool", tool_call_id: result.tool_call_id, content: result.error ? `Error: ${result.error}` : JSON.stringify(result.result) })) ];
finalResponse = await openai.chat.completions.create({ model: "gpt-4", messages: toolMessages, temperature: 0.7, max_tokens: 2000 }); } }
// 📤 SUCCESS RESPONSE: Send MCP-enhanced chat results const updatedHistory = [ ...conversation_history, { role: "user", content: message }, { role: "assistant", content: finalResponse.choices[0].message.content } ];
res.json({ success: true, response: finalResponse.choices[0].message.content, conversation_history: updatedHistory, mcp_data: { servers_used: use_servers, tools_available: availableTools.length, resources_available: availableResources.length, tool_calls: toolResults }, model: "gpt-4", timestamp: new Date().toISOString() });
} catch (error) { console.error("MCP chat error:", error); res.status(500).json({ error: "Failed to process MCP chat", details: error.message, success: false }); }});
// 🔧 MCP RESOURCE ENDPOINT: Access specific MCP resourceapp.get("/api/mcp/resource/:server/:resource", async (req, res) => { try { const { server, resource } = req.params;
const client = mcpClients.get(server); if (!client) { return res.status(404).json({ error: `MCP server '${server}' not found`, success: false }); }
const resourceData = await client.readResource({ uri: resource });
res.json({ success: true, server, resource, data: resourceData.contents });
} catch (error) { console.error("MCP resource access error:", error); res.status(500).json({ error: "Failed to access MCP resource", details: error.message, success: false }); }});
// 🚀 INITIALIZE DEFAULT MCP SERVERS: Connect to demo servers on startupconst initializeDefaultMCPServers = async () => { try { console.log("🔗 Initializing default MCP servers...");
// Connect to demo MCP servers (you can add your own) const defaultServers = [ { name: 'deepwiki', url: 'https://mcp.deepwiki.com/mcp' } ];
for (const server of defaultServers) { try { await initializeMCPServer(server.url, server.name); console.log(`✅ Connected to ${server.name} MCP server`); } catch (error) { console.warn(`⚠️ Could not connect to ${server.name}: ${error.message}`); } }
} catch (error) { console.error("Error initializing default MCP servers:", error); }};
// Initialize MCP servers when the server startsinitializeDefaultMCPServers();
Function breakdown:
- Server management - Connect to and manage multiple MCP servers
- Resource discovery - Find available tools and data sources
- Enhanced chat - Integrate MCP capabilities with OpenAI chat
- Tool execution - Call MCP server functions and handle results
- Resource access - Direct access to MCP server data
🔧 Step 3: Building the React MCP Integration Component
Section titled “🔧 Step 3: Building the React MCP Integration Component”Now let’s create a React component for MCP integration using the same patterns from your existing components.
Step 3A: Creating the MCP Integration Component
Section titled “Step 3A: Creating the MCP Integration Component”Create a new file src/MCPIntegration.jsx
:
import { useState, useEffect } from "react";import { Link, Server, Database, MessageSquare, Play, Settings, Zap, Globe } from "lucide-react";
function MCPIntegration() { // 🧠 STATE: MCP integration data management const [servers, setServers] = useState([]); // Connected MCP servers const [isLoading, setIsLoading] = useState(false); // Loading status const [conversation, setConversation] = useState([]); // Chat history const [message, setMessage] = useState(""); // Current message const [selectedServers, setSelectedServers] = useState(['deepwiki']); // Active servers const [error, setError] = useState(null); // Error messages const [newServerUrl, setNewServerUrl] = useState(""); // New server URL const [newServerName, setNewServerName] = useState(""); // New server name const [isConnecting, setIsConnecting] = useState(false); // Connection status const [showServerForm, setShowServerForm] = useState(false); // Show add server form
// 🔧 FUNCTIONS: MCP integration logic engine
// Load available MCP servers const loadServers = async () => { setIsLoading(true); setError(null);
try { const response = await fetch("http://localhost:8000/api/mcp/servers"); const data = await response.json();
if (!response.ok) { throw new Error(data.error || 'Failed to load MCP servers'); }
setServers(data.servers);
} catch (error) { console.error('Failed to load servers:', error); setError(error.message || 'Could not load MCP servers'); } finally { setIsLoading(false); } };
// Connect to new MCP server const connectToServer = async () => { if (!newServerUrl.trim() || !newServerName.trim()) { setError('Both server URL and name are required'); return; }
setIsConnecting(true); setError(null);
try { const response = await fetch("http://localhost:8000/api/mcp/connect", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ server_url: newServerUrl.trim(), server_name: newServerName.trim() }) });
const data = await response.json();
if (!response.ok) { throw new Error(data.error || 'Failed to connect to MCP server'); }
// Add new server to list setServers(prev => [...prev, data.server]); setNewServerUrl(""); setNewServerName(""); setShowServerForm(false);
} catch (error) { console.error('Connection failed:', error); setError(error.message || 'Could not connect to MCP server'); } finally { setIsConnecting(false); } };
// Send message with MCP enhancement const sendMessage = async () => { if (!message.trim()) return;
const userMessage = message.trim(); setMessage(""); setIsLoading(true); setError(null);
// Add user message to conversation const newConversation = [ ...conversation, { role: "user", content: userMessage } ]; setConversation(newConversation);
try { const response = await fetch("http://localhost:8000/api/mcp/chat", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: userMessage, conversation_history: conversation, use_servers: selectedServers, stream: false }) });
const data = await response.json();
if (!response.ok) { throw new Error(data.error || 'Failed to send message'); }
// Update conversation with AI response setConversation(data.conversation_history);
} catch (error) { console.error('Message failed:', error); setError(error.message || 'Could not send message');
// Remove user message if request failed setConversation(conversation); } finally { setIsLoading(false); } };
// Handle Enter key press const handleKeyPress = (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } };
// Clear conversation const clearConversation = () => { setConversation([]); setError(null); };
// Load servers on component mount useEffect(() => { loadServers(); }, []);
// 🎨 UI: Interface components return ( <div className="min-h-screen bg-gradient-to-br from-green-50 to-emerald-50 flex items-center justify-center p-4"> <div className="bg-white rounded-2xl shadow-2xl w-full max-w-6xl flex flex-col overflow-hidden">
{/* Header */} <div className="bg-gradient-to-r from-green-600 to-emerald-600 text-white p-6"> <div className="flex items-center space-x-3"> <div className="w-10 h-10 bg-white bg-opacity-20 rounded-full flex items-center justify-center"> <Link className="w-5 h-5" /> </div> <div> <h1 className="text-xl font-bold">🔗 MCP Integration</h1> <p className="text-green-100 text-sm">Connect AI to external data sources and services!</p> </div> </div> </div>
<div className="flex flex-1"> {/* Servers Sidebar */} <div className="w-1/3 border-r border-gray-200 p-6"> <div className="flex items-center justify-between mb-4"> <h3 className="font-semibold text-gray-900 flex items-center"> <Server className="w-5 h-5 mr-2 text-green-600" /> MCP Servers ({servers.length}) </h3> <button onClick={() => setShowServerForm(!showServerForm)} className="px-3 py-1 bg-green-100 text-green-700 rounded-lg hover:bg-green-200 transition-colors duration-200 text-sm" > Add Server </button> </div>
{/* Add Server Form */} {showServerForm && ( <div className="mb-4 p-4 bg-gray-50 rounded-lg"> <div className="space-y-3"> <div> <label className="block text-sm font-medium text-gray-700 mb-1"> Server Name </label> <input type="text" value={newServerName} onChange={(e) => setNewServerName(e.target.value)} placeholder="e.g., my-server" className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500" /> </div> <div> <label className="block text-sm font-medium text-gray-700 mb-1"> Server URL </label> <input type="url" value={newServerUrl} onChange={(e) => setNewServerUrl(e.target.value)} placeholder="https://mcp.example.com/mcp" className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500" /> </div> <div className="flex space-x-2"> <button onClick={connectToServer} disabled={isConnecting} className="flex-1 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200" > {isConnecting ? 'Connecting...' : 'Connect'} </button> <button onClick={() => setShowServerForm(false)} className="px-4 py-2 bg-gray-300 text-gray-700 rounded-lg hover:bg-gray-400 transition-colors duration-200" > Cancel </button> </div> </div> </div> )}
{/* Servers List */} <div className="space-y-3 max-h-96 overflow-y-auto"> {servers.map((server, index) => ( <div key={index} className={`p-4 rounded-lg border transition-all duration-200 ${ selectedServers.includes(server.name) ? 'border-green-300 bg-green-50' : 'border-gray-200 bg-white hover:border-gray-300' }`} > <div className="flex items-center justify-between mb-2"> <div className="flex items-center space-x-2"> <input type="checkbox" checked={selectedServers.includes(server.name)} onChange={(e) => { if (e.target.checked) { setSelectedServers([...selectedServers, server.name]); } else { setSelectedServers(selectedServers.filter(s => s !== server.name)); } }} className="w-4 h-4 text-green-600 rounded focus:ring-green-500" /> <h4 className="font-medium text-gray-900">{server.name}</h4> </div> <div className={`w-2 h-2 rounded-full ${ server.status === 'connected' ? 'bg-green-500' : 'bg-red-500' }`} /> </div>
{server.status === 'connected' && server.capabilities && ( <div className="grid grid-cols-3 gap-2 text-xs text-gray-600"> <div className="flex items-center space-x-1"> <Database className="w-3 h-3" /> <span>{server.capabilities.resources} resources</span> </div> <div className="flex items-center space-x-1"> <Zap className="w-3 h-3" /> <span>{server.capabilities.tools} tools</span> </div> <div className="flex items-center space-x-1"> <MessageSquare className="w-3 h-3" /> <span>{server.capabilities.prompts} prompts</span> </div> </div> )}
{server.status === 'error' && ( <p className="text-xs text-red-600 mt-1">{server.error}</p> )} </div> ))}
{servers.length === 0 && !isLoading && ( <div className="text-center py-8"> <Globe className="w-12 h-12 text-gray-400 mx-auto mb-2" /> <p className="text-gray-600 text-sm">No MCP servers connected</p> <p className="text-gray-500 text-xs">Add a server to get started</p> </div> )} </div>
<button onClick={loadServers} disabled={isLoading} className="w-full mt-4 px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 disabled:opacity-50 transition-colors duration-200" > {isLoading ? 'Loading...' : 'Refresh Servers'} </button> </div>
{/* Chat Area */} <div className="flex-1 flex flex-col"> {/* Chat Header */} <div className="p-4 border-b border-gray-200"> <div className="flex items-center justify-between"> <h3 className="font-semibold text-gray-900"> MCP-Enhanced Chat </h3> <div className="flex items-center space-x-2"> <span className="text-sm text-gray-600"> {selectedServers.length} server{selectedServers.length !== 1 ? 's' : ''} active </span> {conversation.length > 0 && ( <button onClick={clearConversation} className="px-3 py-1 bg-red-100 text-red-700 rounded-lg hover:bg-red-200 transition-colors duration-200 text-sm" > Clear </button> )} </div> </div> </div>
{/* Error Display */} {error && ( <div className="p-4 bg-red-50 border-b border-red-200"> <p className="text-red-700 text-sm"> <strong>Error:</strong> {error} </p> </div> )}
{/* Chat Messages */} <div className="flex-1 p-4 overflow-y-auto"> {conversation.length === 0 ? ( <div className="text-center py-12"> <div className="w-16 h-16 bg-green-100 rounded-2xl flex items-center justify-center mx-auto mb-4"> <Link className="w-8 h-8 text-green-600" /> </div> <h4 className="text-lg font-semibold text-gray-700 mb-2"> MCP-Enhanced Conversations </h4> <p className="text-gray-600 max-w-md mx-auto"> Your AI can now access external data sources and services. Ask questions that require live data or external tools! </p> <div className="mt-4 p-3 bg-green-50 rounded-lg text-sm text-green-700"> <p><strong>Try asking:</strong> "What's the weather like?" or "Search for recent news about AI"</p> </div> </div> ) : ( <div className="space-y-4"> {conversation.map((msg, index) => ( <div key={index} className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`} > <div className={`max-w-xs lg:max-w-md px-4 py-2 rounded-lg ${ msg.role === 'user' ? 'bg-green-500 text-white' : 'bg-gray-200 text-gray-900' }`} > <p className="text-sm whitespace-pre-wrap">{msg.content}</p> </div> </div> ))}
{isLoading && ( <div className="flex justify-start"> <div className="bg-gray-200 text-gray-900 px-4 py-2 rounded-lg"> <div className="flex items-center space-x-2"> <div className="flex space-x-1"> <div className="w-2 h-2 bg-gray-500 rounded-full animate-bounce"></div> <div className="w-2 h-2 bg-gray-500 rounded-full animate-bounce" style={{ animationDelay: '0.1s' }}></div> <div className="w-2 h-2 bg-gray-500 rounded-full animate-bounce" style={{ animationDelay: '0.2s' }}></div> </div> <span className="text-sm">Processing with MCP...</span> </div> </div> </div> )} </div> )} </div>
{/* Message Input */} <div className="p-4 border-t border-gray-200"> <div className="flex space-x-3"> <textarea value={message} onChange={(e) => setMessage(e.target.value)} onKeyPress={handleKeyPress} placeholder="Ask something that requires external data or tools..." disabled={isLoading || selectedServers.length === 0} className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500 resize-none disabled:bg-gray-100" rows="3" /> <button onClick={sendMessage} disabled={isLoading || !message.trim() || selectedServers.length === 0} className="px-6 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200 self-end" > <Play className="w-5 h-5" /> </button> </div>
{selectedServers.length === 0 && ( <p className="text-sm text-orange-600 mt-2"> Select at least one MCP server to enable chat </p> )} </div> </div> </div> </div> </div> );}
export default MCPIntegration;
Step 3B: Adding MCP Integration to Navigation
Section titled “Step 3B: Adding MCP Integration to Navigation”Update your src/App.jsx
to include the new MCP integration component:
import { useState } from "react";import StreamingChat from "./StreamingChat";import ImageGenerator from "./ImageGenerator";import AudioTranscription from "./AudioTranscription";import FileAnalysis from "./FileAnalysis";import TextToSpeech from "./TextToSpeech";import VisionAnalysis from "./VisionAnalysis";import VoiceInteraction from "./VoiceInteraction";import MCPIntegration from "./MCPIntegration";import { MessageSquare, Image, Mic, Folder, Volume2, Eye, Phone, Link } from "lucide-react";
function App() { // 🧠 STATE: Navigation management const [currentView, setCurrentView] = useState("chat"); // 'chat', 'images', 'audio', 'files', 'speech', 'vision', 'voice', or 'mcp'
// 🎨 UI: Main app with navigation return ( <div className="min-h-screen bg-gray-100"> {/* Navigation Header */} <nav className="bg-white shadow-sm border-b border-gray-200"> <div className="max-w-7xl mx-auto px-4"> <div className="flex items-center justify-between h-16"> {/* Logo */} <div className="flex items-center space-x-3"> <div className="w-8 h-8 bg-gradient-to-r from-blue-500 to-purple-600 rounded-lg flex items-center justify-center"> <span className="text-white font-bold text-sm">AI</span> </div> <h1 className="text-xl font-bold text-gray-900">OpenAI Mastery</h1> </div>
{/* Navigation Buttons */} <div className="flex space-x-1"> <button onClick={() => setCurrentView("chat")} className={`px-3 py-2 rounded-lg flex items-center space-x-2 transition-all duration-200 ${ currentView === "chat" ? "bg-blue-100 text-blue-700 shadow-sm" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100" }`} > <MessageSquare className="w-4 h-4" /> <span>Chat</span> </button>
<button onClick={() => setCurrentView("images")} className={`px-3 py-2 rounded-lg flex items-center space-x-2 transition-all duration-200 ${ currentView === "images" ? "bg-purple-100 text-purple-700 shadow-sm" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100" }`} > <Image className="w-4 h-4" /> <span>Images</span> </button>
<button onClick={() => setCurrentView("audio")} className={`px-3 py-2 rounded-lg flex items-center space-x-2 transition-all duration-200 ${ currentView === "audio" ? "bg-blue-100 text-blue-700 shadow-sm" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100" }`} > <Mic className="w-4 h-4" /> <span>Audio</span> </button>
<button onClick={() => setCurrentView("files")} className={`px-3 py-2 rounded-lg flex items-center space-x-2 transition-all duration-200 ${ currentView === "files" ? "bg-green-100 text-green-700 shadow-sm" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100" }`} > <Folder className="w-4 h-4" /> <span>Files</span> </button>
<button onClick={() => setCurrentView("speech")} className={`px-3 py-2 rounded-lg flex items-center space-x-2 transition-all duration-200 ${ currentView === "speech" ? "bg-orange-100 text-orange-700 shadow-sm" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100" }`} > <Volume2 className="w-4 h-4" /> <span>Speech</span> </button>
<button onClick={() => setCurrentView("vision")} className={`px-3 py-2 rounded-lg flex items-center space-x-2 transition-all duration-200 ${ currentView === "vision" ? "bg-indigo-100 text-indigo-700 shadow-sm" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100" }`} > <Eye className="w-4 h-4" /> <span>Vision</span> </button>
<button onClick={() => setCurrentView("voice")} className={`px-3 py-2 rounded-lg flex items-center space-x-2 transition-all duration-200 ${ currentView === "voice" ? "bg-blue-100 text-blue-700 shadow-sm" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100" }`} > <Phone className="w-4 h-4" /> <span>Voice</span> </button>
<button onClick={() => setCurrentView("mcp")} className={`px-3 py-2 rounded-lg flex items-center space-x-2 transition-all duration-200 ${ currentView === "mcp" ? "bg-green-100 text-green-700 shadow-sm" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100" }`} > <Link className="w-4 h-4" /> <span>MCP</span> </button> </div> </div> </div> </nav>
{/* Main Content */} <main className="h-[calc(100vh-4rem)]"> {currentView === "chat" && <StreamingChat />} {currentView === "images" && <ImageGenerator />} {currentView === "audio" && <AudioTranscription />} {currentView === "files" && <FileAnalysis />} {currentView === "speech" && <TextToSpeech />} {currentView === "vision" && <VisionAnalysis />} {currentView === "voice" && <VoiceInteraction />} {currentView === "mcp" && <MCPIntegration />} </main> </div> );}
export default App;
🧪 Testing Your MCP Integration
Section titled “🧪 Testing Your MCP Integration”Let’s test your MCP integration feature step by step to make sure everything works correctly.
Step 1: Backend Route Test
Section titled “Step 1: Backend Route Test”First, verify your backend routes work by testing them individually:
Test server listing:
# Test the servers endpointcurl http://localhost:8000/api/mcp/servers
Test server connection:
# Test connecting to a new MCP servercurl -X POST http://localhost:8000/api/mcp/connect \ -H "Content-Type: application/json" \ -d '{"server_url": "https://mcp.deepwiki.com/mcp", "server_name": "test"}'
Step 2: Full Application Test
Section titled “Step 2: Full Application Test”Start both servers:
Backend (in your backend folder):
npm run dev
Frontend (in your frontend folder):
npm run dev
Test the complete flow:
- Navigate to MCP → Click the “MCP” tab in navigation
- View connected servers → See available MCP servers and their capabilities
- Select servers → Choose which servers to use for chat
- Add new server → Connect to additional MCP servers
- Send MCP-enhanced messages → Ask questions requiring external data
- View tool usage → See how AI uses MCP tools and resources
- Test different queries → Try various types of questions
- Manage conversation → Clear chat and start new conversations
Step 3: Error Handling Test
Section titled “Step 3: Error Handling Test”Test error scenarios:
❌ Invalid server URL: Try connecting to non-existent server❌ Network error: Disconnect internet during chat❌ No servers selected: Try chatting without any servers enabled❌ Server timeout: Try using very slow or unresponsive server
Expected behavior:
- Clear error messages displayed
- Graceful fallback when servers unavailable
- User can retry after fixing issues
- Conversation state preserved during errors
✅ What You Built
Section titled “✅ What You Built”Congratulations! You’ve extended your existing application with complete MCP integration:
- ✅ Extended your backend with MCP client connectivity and server management
- ✅ Added React MCP component following the same patterns as your other features
- ✅ Implemented external data access with real-time MCP server connections
- ✅ Created server management with dynamic connection and configuration
- ✅ Added enhanced chat with MCP tool and resource integration
- ✅ Maintained consistent design with your existing application
Your application now has:
- Text chat with streaming responses
- Image generation with DALL-E 3 and GPT-Image-1
- Audio transcription with Whisper voice recognition
- File analysis with intelligent document processing
- Text-to-speech with natural voice synthesis
- Vision analysis with GPT-4o visual intelligence
- Voice interaction with GPT-4o Audio natural conversations
- MCP integration with external data sources and services
- Unified navigation between all features
- Professional UI with consistent TailwindCSS styling
Next up: You’ll learn about Structured Output, where your AI responses follow strict schemas and formats using Zod parsing - perfect for building reliable data processing and API integrations.
Your OpenAI mastery application now connects to the external world! 🔗