Skip to content

Commit aed6409

Browse files
authored
General Improvements (#4)
This pull request includes several changes aimed at improving the MCP frontend application, including updates to the user interface, API integration, and code organization. The most important changes include the addition of new API calls, the introduction of a new component, and various UI enhancements. ### API Integration: * [`src/api/index.ts`](diffhunk://#diff-764761d79ed791ea154187526b088322dba3bebe94f9d38ab22120554aba77c7R17-R40): Added new functions `fetchLLMProviders` and `fetchTools` to fetch data from the backend API. ### New Component: * [`src/components/AIIcon.tsx`](diffhunk://#diff-121125d547a62e793266ec8b60ad2742a95dcccd51b0560c255117f4a0d1126eR1-R61): Created a new `AIIcon` component for displaying an AI icon with customizable size and color. ### UI Enhancements: * [`src/App.tsx`](diffhunk://#diff-26ad4b834941d9b19ebf9db8082bd202aaf72ea0ddea85f5a8a0cb3c729cc6f2L166-R168): Updated the app to include the new `AIIcon` component in the header. * [`index.html`](diffhunk://#diff-0eb547304658805aad788d320f10bf1f292797b5e6d745a3bf617584da017051L5-R5): Changed the favicon link to use `mcp_chat.svg` instead of `vite.svg`. ### Code Organization: * [`src/components/ChatContainer.tsx`](diffhunk://#diff-b130cf7dc6a8812442b74fefd3c5d4ec6883ef769d71f5cc8c2bb01df41707b2L1-R7): Refactored the `ChatContainer` component to use the new `ChatService` class and improved state management. [[1]](diffhunk://#diff-b130cf7dc6a8812442b74fefd3c5d4ec6883ef769d71f5cc8c2bb01df41707b2L1-R7) [[2]](diffhunk://#diff-b130cf7dc6a8812442b74fefd3c5d4ec6883ef769d71f5cc8c2bb01df41707b2L33-L62) [[3]](diffhunk://#diff-b130cf7dc6a8812442b74fefd3c5d4ec6883ef769d71f5cc8c2bb01df41707b2L80-R114) [[4]](diffhunk://#diff-b130cf7dc6a8812442b74fefd3c5d4ec6883ef769d71f5cc8c2bb01df41707b2L122-R134) ### Other Changes: * [`README.md`](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L61-R66): Updated instructions for setting environment variables when running with Docker. * Various files: Standardized import formatting across multiple components. [[1]](diffhunk://#diff-26ad4b834941d9b19ebf9db8082bd202aaf72ea0ddea85f5a8a0cb3c729cc6f2L1-R1) [[2]](diffhunk://#diff-b130cf7dc6a8812442b74fefd3c5d4ec6883ef769d71f5cc8c2bb01df41707b2L1-R7) [[3]](diffhunk://#diff-1996a5e45995f5849cbcea7a39299aa1a96cc0fa41b1401e503d4891bbe686c1L1-R1) [[4]](diffhunk://#diff-63552adfc136b5745280f1413214afb454e46b6558a54e0ac1a62d3076779256L2-R7) [[5]](diffhunk://#diff-1dce3195a9d5ffa57316df6f7bfb57cf34633dd2efa81e82eb5331152b56dde0L1-R56)This pull request includes several improvements and new features to the MCP Frontend project. The main changes involve adding new API methods, refactoring existing services, and updating components to use the new services. ### API Methods and Service Refactoring: * [`src/api/index.ts`](diffhunk://#diff-764761d79ed791ea154187526b088322dba3bebe94f9d38ab22120554aba77c7R17-R40): Added new methods `fetchLLMProviders` and `fetchTools` for fetching LLM providers and tools. * [`src/services/APIClient.ts`](diffhunk://#diff-c541918b610d84d9d4591faecad3008e1a8a244d446b8b929f3e017ea97fd558R1-R54): Introduced `APIClient` class to handle API requests with error handling. * [`src/services/ChatService.ts`](diffhunk://#diff-9dd13b51c673219aa9d6fb02c8bc1100134172df11c9c69008b0b299c0b3d53fR1-R43): Refactored `ChatService` to extend `APIClient` and added methods for sending messages and loading chat history. * [`src/services/LLMService.ts`](diffhunk://#diff-cd77df0f49406951d1fac5878b9dbaedda26efdcfdf299051c8efa5b820c22fcR1-R12): Added `LLMService` class for fetching LLM providers. * [`src/services/ToolService.ts`](diffhunk://#diff-ebf1d939d609a4816004caf5632789818db419201d7af8b12e6123dcfd0b995dR1-R12): Added `ToolService` class for fetching tools. ### Component Updates: * [`src/components/ChatContainer.tsx`](diffhunk://#diff-b130cf7dc6a8812442b74fefd3c5d4ec6883ef769d71f5cc8c2bb01df41707b2L2-R7): Updated to use the new `ChatService` and refactored state management for chat messages. [[1]](diffhunk://#diff-b130cf7dc6a8812442b74fefd3c5d4ec6883ef769d71f5cc8c2bb01df41707b2L2-R7) [[2]](diffhunk://#diff-b130cf7dc6a8812442b74fefd3c5d4ec6883ef769d71f5cc8c2bb01df41707b2L16-L20) [[3]](diffhunk://#diff-b130cf7dc6a8812442b74fefd3c5d4ec6883ef769d71f5cc8c2bb01df41707b2L33-L62) [[4]](diffhunk://#diff-b130cf7dc6a8812442b74fefd3c5d4ec6883ef769d71f5cc8c2bb01df41707b2L80-R114) [[5]](diffhunk://#diff-b130cf7dc6a8812442b74fefd3c5d4ec6883ef769d71f5cc8c2bb01df41707b2L122-R134) * [`src/components/LLMProvidersModal.tsx`](diffhunk://#diff-1dce3195a9d5ffa57316df6f7bfb57cf34633dd2efa81e82eb5331152b56dde0L1-R56): Updated to use the new `LLMService` and refactored the modal's state and error handling. [[1]](diffhunk://#diff-1dce3195a9d5ffa57316df6f7bfb57cf34633dd2efa81e82eb5331152b56dde0L1-R56) [[2]](diffhunk://#diff-1dce3195a9d5ffa57316df6f7bfb57cf34633dd2efa81e82eb5331152b56dde0L53) [[3]](diffhunk://#diff-1dce3195a9d5ffa57316df6f7bfb57cf34633dd2efa81e82eb5331152b56dde0L93-R126) * [`src/components/ChatInputButton/ToolsModal.tsx`](diffhunk://#diff-63552adfc136b5745280f1413214afb454e46b6558a54e0ac1a62d3076779256R7): Updated to use the new `fetchTools` method from `src/api/index.ts`. [[1]](diffhunk://#diff-63552adfc136b5745280f1413214afb454e46b6558a54e0ac1a62d3076779256R7) [[2]](diffhunk://#diff-63552adfc136b5745280f1413214afb454e46b6558a54e0ac1a62d3076779256L19-R34) ### Documentation and Other Changes: * [`README.md`](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L61-R66): Updated instructions for running the application locally and with Docker. * [`src/types/llm.ts`](diffhunk://#diff-fcb3724752fd46a17d4f4378610a27a71fecae7857d540c0988f5318c4687af3R19-R22): Added `LLMProvidersResponse` interface. These changes aim to improve the maintainability and scalability of the codebase by introducing a more structured approach to API interactions and enhancing the user experience with better error handling and state management.
1 parent c118cc1 commit aed6409

35 files changed

+393
-175
lines changed

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,12 @@ docker run \
5858

5959
The following environment variables are required to run MCP Frontend:
6060

61-
##### Production Environment Variables (Running with Docker)
62-
6361
| env_key | Default | Required | Description |
6462
|---------------------------------|---------|----------|---------------------------------------|
6563
| `VITE_MCP_BACKEND_API_ENDPOINT` | - | Yes | The base URL for the MCP backend API. |
6664

67-
Simply copy the `.env.example` file to `.env` and update the values as needed.
65+
Simply copy the `.env.example` file to `.env` and update the values as needed to run the application locally.
66+
And for Docker, you can pass the environment variables using the `-e` flag.
6867

6968
## 🚀 Usage
7069

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<html lang="en">
33
<head>
44
<meta charset="UTF-8" />
5-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
5+
<link rel="icon" type="image/svg+xml" href="/mcp_chat.svg" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>MCP Kit - Chat Interface</title>
88
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&family=Open+Sans:wght@400;700&display=swap" rel="stylesheet">

public/mcp_chat.svg

Lines changed: 38 additions & 0 deletions
Loading

public/vite.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/App.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
import { useState, useEffect } from 'react';
2-
import { marked } from 'marked';
1+
import {useEffect, useState} from 'react';
2+
import {marked} from 'marked';
33
import DOMPurify from 'dompurify';
44
import hljs from 'highlight.js';
55
import 'highlight.js/styles/github-dark.css';
6-
import { Sidebar } from './components/Sidebar';
7-
import { ModelControls } from './components/ModelControls';
8-
import { ChatContainer } from './components/ChatContainer';
9-
import { WelcomeScreen } from './components/WelcomeScreen';
10-
import { Cog6ToothIcon } from "@heroicons/react/24/outline";
11-
import { NotificationProvider } from './context/NotificationContext';
6+
import {Sidebar} from './components/Sidebar';
7+
import {ModelControls} from './components/ModelControls';
8+
import {ChatContainer} from './components/ChatContainer';
9+
import {WelcomeScreen} from './components/WelcomeScreen';
10+
import {Cog6ToothIcon} from "@heroicons/react/24/outline";
11+
import {NotificationProvider} from './context/NotificationContext';
1212
import {NotificationContainer} from "./components/NotificationContainer.tsx";
13-
import { Auth0Provider } from '@auth0/auth0-react';
13+
import {Auth0Provider} from '@auth0/auth0-react';
14+
import AIIcon from "./components/AIIcon.tsx";
1415

1516
interface ModelSettings {
1617
temperature: number;
@@ -163,7 +164,8 @@ function App() {
163164
</svg>
164165
</button>
165166

166-
<div className="flex items-center">
167+
<div className="flex items-center space-x-2">
168+
<AIIcon size={24} color="#4285f4" />
167169
<span className="text-xl font-semibold text-gray-800">MCP Kit</span>
168170
</div>
169171
</div>

src/api/index.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,28 @@ export const fetchChatHistories = async (token: string) => {
1313
} catch (error) {
1414
throw error;
1515
}
16-
};
16+
};
17+
18+
export const fetchLLMProviders = async () => {
19+
try {
20+
const response = await fetch(`${import.meta.env.VITE_MCP_BACKEND_API_ENDPOINT}/llm-providers`);
21+
if (!response.ok) {
22+
throw new Error('Failed to fetch LLM providers');
23+
}
24+
return await response.json();
25+
} catch (error) {
26+
throw error;
27+
}
28+
};
29+
30+
export const fetchTools = async () => {
31+
try {
32+
const response = await fetch('http://localhost:8081/api/tools');
33+
if (!response.ok) {
34+
throw new Error('Failed to fetch tools');
35+
}
36+
return await response.json();
37+
} catch (error) {
38+
throw error;
39+
}
40+
};

src/assets/react.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/components/AIIcon.tsx

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import React from 'react';
2+
3+
interface AIIconProps {
4+
size?: number;
5+
color?: string;
6+
}
7+
8+
const AIIcon: React.FC<AIIconProps> = ({
9+
size = 200,
10+
color = '#4285f4'
11+
}) => {
12+
return (
13+
<svg
14+
width={size}
15+
height={size}
16+
viewBox="0 0 200 200"
17+
xmlns="http://www.w3.org/2000/svg"
18+
>
19+
<circle cx="100" cy="100" r="80" fill={color} opacity="0.1"/>
20+
<g stroke={color} stroke-width="2">
21+
<circle cx="100" cy="100" r="8" fill={color}/>
22+
<circle cx="60" cy="70" r="6" fill="white"/>
23+
<circle cx="140" cy="70" r="6" fill="white"/>
24+
<circle cx="60" cy="130" r="6" fill="white"/>
25+
<circle cx="140" cy="130" r="6" fill="white"/>
26+
<circle cx="100" cy="50" r="6" fill="white"/>
27+
<circle cx="100" cy="150" r="6" fill="white"/>
28+
29+
<line x1="100" y1="100" x2="60" y2="70"/>
30+
<line x1="100" y1="100" x2="140" y2="70"/>
31+
<line x1="100" y1="100" x2="60" y2="130"/>
32+
<line x1="100" y1="100" x2="140" y2="130"/>
33+
<line x1="100" y1="100" x2="100" y2="50"/>
34+
<line x1="100" y1="100" x2="100" y2="150"/>
35+
36+
<path d="M60 70 Q 100 85 140 70" fill="none"/>
37+
<path d="M60 130 Q 100 115 140 130" fill="none"/>
38+
</g>
39+
<circle cx="100" cy="100" r="20" fill="none" stroke={color} opacity="0.5">
40+
<animate
41+
attributeName="r"
42+
from="20"
43+
to="40"
44+
dur="1.5s"
45+
begin="0s"
46+
repeatCount="indefinite"
47+
/>
48+
<animate
49+
attributeName="opacity"
50+
from="0.5"
51+
to="0"
52+
dur="1.5s"
53+
begin="0s"
54+
repeatCount="indefinite"
55+
/>
56+
</circle>
57+
</svg>
58+
);
59+
};
60+
61+
export default AIIcon;

src/components/AuthStatus.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useAuth0 } from '@auth0/auth0-react';
1+
import {useAuth0} from '@auth0/auth0-react';
22

33
export function AuthStatus() {
44
const {

src/components/ChatContainer.tsx

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import React, {useState, useRef, useEffect} from 'react';
2-
import {chatService} from "../services/chatService.ts";
1+
import React, {useEffect, useRef, useState} from 'react';
32
import {Message} from "./Message/Message.tsx";
43
import {ChatInput} from "./ChatInput.tsx";
5-
import { ChatPayload } from '../types/chat';
4+
import {ChatPayload} from '../types/chat';
65
import {useNotification} from "../context/NotificationContext.tsx";
7-
import { useAuth0 } from '@auth0/auth0-react';
6+
import {useAuth0} from '@auth0/auth0-react';
7+
import {ApiChatMessage, ChatService, ClientChatMessage} from "../services/ChatService.ts";
88

99
interface ModelSettings {
1010
temperature: number;
@@ -13,11 +13,6 @@ interface ModelSettings {
1313
topK: number;
1414
}
1515

16-
interface ChatMessage {
17-
content: string;
18-
isUser: boolean;
19-
}
20-
2116
interface ChatContainerProps {
2217
selectedTools: string[];
2318
modelSettings: ModelSettings;
@@ -30,36 +25,21 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({
3025
selectedChatId
3126
}) => {
3227
const { addNotification } = useNotification();
33-
const [messages, setMessages] = useState<ChatMessage[]>([]);
28+
const [messages, setMessages] = useState<ClientChatMessage[]>([]);
3429
const [isLoading, setIsLoading] = useState(false);
3530
const messagesEndRef = useRef<HTMLDivElement>(null);
3631
const [chatUuid, setChatUuid] = useState<string | null>(null);
3732
const [selectedTools, setSelectedTools] = useState<string[]>([]);
3833
const [selectedProvider, setSelectedProvider] = useState<string | null>(null);
3934
const [selectedModelId, setSelectedModelId] = useState<string | null>(null);
4035
const { isAuthenticated, loginWithRedirect } = useAuth0();
41-
if (!isAuthenticated) {
42-
return (
43-
<div className="flex flex-col items-center justify-center h-full">
44-
<h2 className="text-xl mb-4">Please log in to use the chat</h2>
45-
<button
46-
onClick={() => loginWithRedirect()}
47-
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700"
48-
>
49-
Log In
50-
</button>
51-
</div>
52-
);
53-
}
54-
36+
const { getAccessTokenSilently } = useAuth0();
5537

5638
const handleProviderChange = (provider: string, modelId: string) => {
5739
setSelectedProvider(provider);
5840
setSelectedModelId(modelId);
5941
};
6042

61-
62-
6343
const scrollToBottom = () => {
6444
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
6545
};
@@ -77,33 +57,61 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({
7757
}
7858

7959
try {
80-
const data = await chatService.loadChatHistory(selectedChatId);
81-
const formattedMessages = data.messages.map((msg: any) => ({
82-
content: msg.Text,
83-
isUser: msg.IsUser
84-
}));
85-
86-
setMessages(formattedMessages);
87-
setChatUuid(selectedChatId);
60+
const token = await getAccessTokenSilently();
61+
const chatService = new ChatService(token);
62+
const response = await chatService.loadChatHistory(selectedChatId);
63+
64+
if (response.error) {
65+
console.error('Error loading chat history:', response.error);
66+
return;
67+
}
68+
69+
if (response.data) {
70+
const formattedMessages = response.data.messages.map((msg: ApiChatMessage): ClientChatMessage => ({
71+
content: msg.Text,
72+
isUser: msg.IsUser
73+
}));
74+
75+
setMessages(formattedMessages);
76+
setChatUuid(selectedChatId);
77+
}
8878
} catch (error) {
8979
console.error('Error loading chat history:', error);
9080
}
9181
};
9282

9383
loadChatHistory();
94-
}, [selectedChatId]);
84+
}, [selectedChatId, getAccessTokenSilently]);
85+
86+
87+
if (!isAuthenticated) {
88+
return (
89+
<div className="flex flex-col items-center justify-center h-full">
90+
<h2 className="text-xl mb-4">Please log in to use the chat</h2>
91+
<button
92+
onClick={() => loginWithRedirect()}
93+
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700"
94+
>
95+
Log In
96+
</button>
97+
</div>
98+
);
99+
}
95100

96101
const handleMessageSubmit = async (message: string) => {
97102
setIsLoading(true);
98103

99-
const newMessage: ChatMessage = {
104+
const newMessage: ClientChatMessage = {
100105
content: message,
101106
isUser: true
102107
};
103108

104109
setMessages(prev => [...prev, newMessage]);
105110

106111
try {
112+
const token = await getAccessTokenSilently();
113+
const chatService = new ChatService(token);
114+
107115
const payload: ChatPayload = {
108116
question: message,
109117
selectedTools,
@@ -119,11 +127,11 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({
119127

120128
const data = await chatService.sendMessage(payload);
121129

122-
if (data.chat_uuid && !chatUuid) {
123-
setChatUuid(data.chat_uuid);
130+
if (data.data.chat_uuid && !chatUuid) {
131+
setChatUuid(data.data.chat_uuid);
124132
}
125133

126-
setMessages(prev => [...prev, { content: data.answer, isUser: false }]);
134+
setMessages(prev => [...prev, { content: data.data.answer, isUser: false }]);
127135
} catch (error) {
128136
const errorMessage = error instanceof Error ? error.message : "Sorry, there was an error processing your request.";
129137
addNotification('error', errorMessage);

0 commit comments

Comments
 (0)