🔗 MCP Integration Made Simple
Your AI has incredible skills, but what if it could connect to external data sources and services in real-time? 🔗
Right now your AI is limited to built-in capabilities. But what if it could access databases, APIs, file systems, and specialized services, creating truly dynamic and powerful applications?
What we’re building: AI that connects to the external world through Model Context Protocol (MCP), giving it access to live data and specialized tools beyond its training!
🎯 From Built-in Capabilities to External Connections
Section titled “🎯 From Built-in Capabilities to External Connections”Current limitation: Your AI is limited to built-in OpenAI capabilities
New superpower: Your AI can connect to external systems and services via MCP!
🔄 The External Access Transformation
Section titled “🔄 The External Access Transformation”Before (Isolated AI):
User: "Check my calendar for conflicts"AI: "I don't have access to your calendar system" 😕After (MCP-Connected AI):
User: "Check my calendar for conflicts"AI: [Connects to calendar MCP] "You have a conflict at 2 PM - meeting with client" 📅The magic: Your AI becomes a connected agent with access to real-world systems and data!
🚀 Why MCP Integration Changes Everything
Section titled “🚀 Why MCP Integration Changes Everything”Real-world scenarios your connected AI will handle:
- 📊 Database access - “Query our customer database” → Live database results
- 📁 File system operations - “Check project files” → Real-time file system access
- 🌐 API integrations - “Get weather data” → Live API calls to weather services
- 💼 Business systems - “Check inventory” → Connection to business databases
- 🛠️ Specialized tools - “Run analytics” → Access to specialized software tools
Isolated AI vs. Connected AI:
❌ Isolated: "I can't access external systems"✅ Connected: "Let me check that system for you..."
❌ Isolated: Limited to training knowledge✅ Connected: Access to live, current data
❌ Isolated: Can only think and respond✅ Connected: Can perform real actions in external systems🧠 Step 1: Understanding MCP Integration
Section titled “🧠 Step 1: Understanding MCP Integration”Before we write any code, let’s understand what MCP integration actually means and why it transforms your AI from a chatbot into a connected agent.
What MCP Integration Actually Means
Section titled “What MCP Integration Actually Means”MCP (Model Context Protocol) is 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, databases, file systems, APIs, and any other tool you connect to it.
Real-world analogy: It’s like hiring a brilliant assistant who not only knows a lot but can also access your company’s databases, check your calendar, read your files, and use your business systems to get things done.
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)
🔗 MCP Integration - AI accesses external systems (external connections)
🎤 Voice/Audio - AI processes and generates audio (built-in capabilities)
🔗 MCP Integration - AI interacts with the real world (external actions)
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.
Model Context Protocol Overview
Section titled “Model Context Protocol Overview”Your MCP integration will connect to remote MCP servers:
🌐 MCP Servers - External Data Connectors
- Best for: Accessing specialized data sources and services
- Strengths: Real-time data, specialized APIs, standardized protocol
- Use cases: Databases, file systems, APIs, business tools
- Think of it as: Your AI’s connection to the digital ecosystem
Key capabilities:
- Standardized protocol for consistent integration
- Multiple server support for diverse data sources
- Secure connections with proper authentication
- Resource and tool access from external systems
🔧 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 stateKey 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/sdkWhat 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 structured output 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 connection (mock implementation for demo)const initializeMCPServer = async (serverConfig, serverName = 'default') => { try { console.log(`🔗 Connecting to MCP server: ${serverName}`);
// Mock MCP client for demonstration // In a real implementation, you would create actual MCP connections const mockClient = { name: serverName, config: serverConfig, connected: true, resources: [ { uri: `${serverName}://data/users`, name: "User Database", description: "Access to user information and profiles", mimeType: "application/json" }, { uri: `${serverName}://data/projects`, name: "Project Database", description: "Access to project data and status", mimeType: "application/json" } ], tools: [ { name: "query_database", description: `Query ${serverName} database for information`, inputSchema: { type: "object", properties: { query: { type: "string", description: "Database query" }, table: { type: "string", description: "Table to query" } }, required: ["query"] } }, { name: "get_system_info", description: `Get system information from ${serverName}`, inputSchema: { type: "object", properties: { info_type: { type: "string", description: "Type of system information" } } } } ], // Mock methods listResources: async () => ({ resources: mockClient.resources }), listTools: async () => ({ tools: mockClient.tools }), callTool: async (request) => { // Mock tool execution if (request.name === 'query_database') { return { content: [ { type: "text", text: JSON.stringify({ results: [ { id: 1, name: "John Doe", role: "developer" }, { id: 2, name: "Jane Smith", role: "designer" } ], query: request.arguments.query, timestamp: new Date().toISOString() }) } ] }; } else if (request.name === 'get_system_info') { return { content: [ { type: "text", text: JSON.stringify({ system: serverName, status: "online", uptime: "24h 15m", connections: 42, timestamp: new Date().toISOString() }) } ] }; } return { content: [{ type: "text", text: "Tool execution completed" }] }; } };
mcpClients.set(serverName, mockClient);
console.log(`✅ Connected to MCP server: ${serverName}`); return mockClient;
} catch (error) { console.error(`❌ Failed to connect to MCP server ${serverName}:`, error); throw error; }};
// Initialize demo MCP servers on startupconst initializeDefaultMCPServers = async () => { try { console.log("🔗 Initializing demo MCP servers...");
const defaultServers = [ { name: 'demo-server', config: { url: 'demo://localhost' } }, { name: 'data-service', config: { url: 'data://localhost' } } ];
for (const server of defaultServers) { try { await initializeMCPServer(server.config, server.name); console.log(`✅ Initialized ${server.name} MCP server`); } catch (error) { console.warn(`⚠️ Could not initialize ${server.name}: ${error.message}`); } }
} catch (error) { console.error("Error initializing MCP servers:", error); }};
// 🔗 MCP ENDPOINTS: Add these to your existing server
// List available MCP serversapp.get("/api/mcp/servers", async (req, res) => { try { const servers = [];
for (const [name, client] of mcpClients) { try { const resources = await client.listResources(); const tools = await client.listTools();
servers.push({ name, status: client.connected ? 'connected' : 'disconnected', capabilities: { resources: resources.resources?.length || 0, tools: tools.tools?.length || 0 }, resources: resources.resources || [], tools: tools.tools || [] }); } 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 }); }});
// 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}`);
const client = await initializeMCPServer({ url: server_url }, server_name);
const resources = await client.listResources(); const tools = await client.listTools();
res.json({ success: true, server: { name: server_name, url: server_url, status: 'connected', capabilities: { resources: resources.resources?.length || 0, tools: tools.tools?.length || 0 }, resources: resources.resources || [], tools: tools.tools || [] } });
} 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-enhanced chatapp.post("/api/mcp/chat", async (req, res) => { try { const { message, conversation_history = [], use_servers = ['demo-server'], temperature = 0.7 } = 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 context const systemMessage = { 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(', ')}
When users ask questions that might benefit from external data or tools, explain what information you could access through the connected MCP servers. Be helpful and informative about the capabilities available.` };
const messages = [ systemMessage, ...conversation_history, { role: "user", content: message } ];
const response = await openai.chat.completions.create({ model: "gpt-4o-mini", messages, temperature, max_tokens: 2000 });
let finalResponse = response.choices[0].message.content; let mcpData = { servers_used: use_servers, tools_available: availableTools.length, resources_available: availableResources.length, tool_calls: [] };
// For demo purposes, simulate tool usage when certain keywords are mentioned if (message.toLowerCase().includes('database') || message.toLowerCase().includes('query')) { try { const demoClient = mcpClients.get('demo-server'); if (demoClient) { const toolResult = await demoClient.callTool({ name: 'query_database', arguments: { query: 'SELECT * FROM users LIMIT 2', table: 'users' } });
mcpData.tool_calls.push({ tool_name: 'query_database', server: 'demo-server', result: toolResult.content[0].text, timestamp: new Date().toISOString() });
finalResponse += `\n\n**MCP Database Query Result:**\n\`\`\`json\n${toolResult.content[0].text}\n\`\`\``; } } catch (error) { console.error('MCP tool call error:', error); } }
if (message.toLowerCase().includes('system') || message.toLowerCase().includes('status')) { try { const demoClient = mcpClients.get('demo-server'); if (demoClient) { const toolResult = await demoClient.callTool({ name: 'get_system_info', arguments: { info_type: 'status' } });
mcpData.tool_calls.push({ tool_name: 'get_system_info', server: 'demo-server', result: toolResult.content[0].text, timestamp: new Date().toISOString() });
finalResponse += `\n\n**MCP System Info:**\n\`\`\`json\n${toolResult.content[0].text}\n\`\`\``; } } catch (error) { console.error('MCP tool call error:', error); } }
// 📤 SUCCESS RESPONSE: Send MCP-enhanced chat results const updatedHistory = [ ...conversation_history, { role: "user", content: message }, { role: "assistant", content: finalResponse } ];
res.json({ success: true, response: finalResponse, conversation_history: updatedHistory, mcp_data: mcpData, model: "gpt-4o-mini", 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 }); }});
// 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 }); }
// Mock resource data for demo const mockResourceData = { uri: `${server}://${resource}`, data: { type: "resource_data", server: server, resource: resource, content: `Mock data from ${server} resource ${resource}`, timestamp: new Date().toISOString(), items: [ { id: 1, name: "Sample Item 1", status: "active" }, { id: 2, name: "Sample Item 2", status: "pending" } ] } };
res.json({ success: true, server, resource, data: mockResourceData });
} 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 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(['demo-server']); // 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, temperature: 0.7 }) });
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="demo://localhost or custom://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 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>Ready</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">Demo servers will load automatically</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 mb-4"> Your AI can now access external data sources and services. Ask questions that require external data or tools! </p> <div className="text-sm text-gray-500 space-y-1"> <p>💡 "Query the database for user information"</p> <p>💡 "Get system status from connected servers"</p> <p>💡 "Access project data from external sources"</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' }`} > <div className="text-sm whitespace-pre-wrap" dangerouslySetInnerHTML={{ __html: msg.content.replace(/```json\n([\s\S]*?)\n```/g, '<div class="bg-gray-800 text-green-400 p-2 rounded mt-2 text-xs font-mono overflow-x-auto">$1</div>') }}></div> </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 4: Testing Your MCP Integration
Section titled “🧪 Step 4: Testing Your MCP Integration”Let’s test your MCP integration feature step by step to make sure everything works correctly.
Step 4A: Backend Route Test
Section titled “Step 4A: 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/serversTest MCP chat:
# Test MCP-enhanced chat with database querycurl -X POST http://localhost:8000/api/mcp/chat \ -H "Content-Type: application/json" \ -d '{"message": "Query the database for user information", "use_servers": ["demo-server"]}'Step 4B: Full Application Test
Section titled “Step 4B: Full Application Test”Start both servers:
Backend (in your backend folder):
npm run devFrontend (in your frontend folder):
npm run devTest the complete flow:
- Navigate to MCP → Click the “MCP” tab in navigation
- View connected servers → See demo MCP servers and their capabilities
- Select servers → Choose which servers to use for chat
- Test database queries → Ask “Query the database for user information”
- Test system info → Ask “Get system status from connected servers”
- Add new server → Try connecting to additional MCP servers
- Test different queries → Try various types of questions requiring external data
- Manage conversation → Clear chat and start new conversations
Step 4C: Error Handling Test
Section titled “Step 4C: 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: Test with unresponsive server configurationExpected 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 MCP server connections
- ✅ Created server management with dynamic connection capabilities
- ✅ 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
- 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
- Function calling with real-world tool integration
- Web search with real-time internet access
- Structured output with Zod validation and guaranteed data formats
- MCP integration with external data sources and services
- Unified navigation between all features
- Professional UI with consistent styling
Next up: You’ll learn about Function Calling, where your AI can call external tools and APIs to perform actions beyond conversation - like checking weather, calculations, or connecting to databases.
Your OpenAI mastery application now connects to the external world! 🔗