Skip to content

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

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.

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.

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.

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 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 structured output 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 (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 startup
const 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 servers
app.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 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}`);
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 chat
app.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 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
});
}
// 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 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(['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;

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 MCP chat:

Terminal window
# Test MCP-enhanced chat with database query
curl -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"]}'

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 demo MCP servers and their capabilities
  3. Select servers → Choose which servers to use for chat
  4. Test database queries → Ask “Query the database for user information”
  5. Test system info → Ask “Get system status from connected servers”
  6. Add new server → Try connecting to additional MCP servers
  7. Test different queries → Try various types of questions requiring external data
  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: Test with unresponsive server configuration

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