Skip to content

🔗 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.

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.

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.

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:

  1. Static knowledge from training data (outdated information)
  2. Built-in capabilities only (no external connections)
  3. Manual data input (users must provide all context)
  4. Isolated functionality (can’t interact with your systems)

With MCP integration, your AI can access live data and perform real actions through connected services.

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

First, add the MCP client dependencies to your backend. In your backend folder, run:

Terminal window
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 connections
let mcpClients = new Map();
// Initialize MCP server connection
const 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 servers
app.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 server
app.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 AI
app.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 resource
app.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 startup
const 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 starts
initializeDefaultMCPServers();

Function breakdown:

  1. Server management - Connect to and manage multiple MCP servers
  2. Resource discovery - Find available tools and data sources
  3. Enhanced chat - Integrate MCP capabilities with OpenAI chat
  4. Tool execution - Call MCP server functions and handle results
  5. 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;

Let’s test your MCP integration feature step by step to make sure everything works correctly.

First, verify your backend routes work by testing them individually:

Test server listing:

Terminal window
# Test the servers endpoint
curl http://localhost:8000/api/mcp/servers

Test server connection:

Terminal window
# Test connecting to a new MCP server
curl -X POST http://localhost:8000/api/mcp/connect \
-H "Content-Type: application/json" \
-d '{"server_url": "https://mcp.deepwiki.com/mcp", "server_name": "test"}'

Start both servers:

Backend (in your backend folder):

Terminal window
npm run dev

Frontend (in your frontend folder):

Terminal window
npm run dev

Test the complete flow:

  1. Navigate to MCP → Click the “MCP” tab in navigation
  2. View connected servers → See available MCP servers and their capabilities
  3. Select servers → Choose which servers to use for chat
  4. Add new server → Connect to additional MCP servers
  5. Send MCP-enhanced messages → Ask questions requiring external data
  6. View tool usage → See how AI uses MCP tools and resources
  7. Test different queries → Try various types of questions
  8. Manage conversation → Clear chat and start new conversations

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

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! 🔗