Content
# MCP Chat Client
[](https://opensource.org/licenses/MIT)
[](https://nodejs.org/)
<p align="center">
<img src="https://amap.com/favicon.ico" alt="Gaode Map" width="80" height="80">
</p>
## Project Introduction
This is a chat client based on the Model Context Protocol (MCP), implementing natural language interaction with Gaode Map services. By combining large language models with the MCP protocol, users can query geographic information, plan routes, and obtain weather data using natural language.
> **Core Feature**: This project demonstrates how to integrate large language models with map services to achieve natural language interactive map functionality through the MCP protocol.
## Features
- **Intelligent Conversational Interaction**: Uses SiliconFlow API to access QWEN large model for natural language understanding.
- **Map Service Integration**: Supports various MCP tool calls from Gaode Map, including:
- Place search and nearby queries
- Route planning for cycling, driving, public transport, and walking
- Weather information queries
- Geocoding and reverse geocoding
- **Real-time Communication**: Achieves real-time connection with Gaode Map MCP services via SSE (Server-Sent Events).
- **User-friendly Interface**: Provides a simple and intuitive web chat interface that supports multi-turn conversations.
## Environment Requirements
- **Node.js**: >= 16.0.0
- **Package Manager**: npm
- **API Key**: SiliconFlow API key is required.
## Quick Start
### 1. Clone the Project
```bash
git clone https://github.com/Ceeon/mcp-chat-client.git
cd mcp-chat-client
```
### 2. Install Dependencies
```bash
npm install
```
### 3. Configure Environment Variables
Create a `.env` file and add the following configuration:
```env
SILICONFLOW_API_KEY=your_siliconflow_api_key
AMAP_MCP_URL=gaode_map_mcp_service_url
PORT=3000 # Optional, defaults to 3000
```
### 4. Start the Service
Choose one of the following methods to start the service:
```bash
# Method 1: Using npm script
npm start
# Method 2: Directly run the server file
node server.js
```
### 5. Access the Application
Once the service is started, open your browser and visit:
```
http://localhost:3000
```
## Project Structure
### Directory Structure
```
└── MCP Client
├── server.js # Main server file
├── mcp-chat-simple/ # Frontend files directory
│ ├── index.html # Main page
│ ├── app.js # Frontend logic
│ └── styles.css # Stylesheet
├── package.json # Project configuration
├── tsconfig.json # TypeScript configuration
├── .env # Environment variables (to be created)
└── .env.example # Environment variable example
```
### Core File Descriptions
#### Backend Files
- **server.js** ⭐⭐
- Main server file built on Express.
- Provides web services and API endpoints.
- **Connects to Gaode Map MCP services and manages tool calls** ⭐⭐⭐
- **Integrates SiliconFlow API for large model interaction** ⭐⭐⭐
- **siliconflow-client.ts** ⭐⭐
- TypeScript source file defining core client logic.
- **Implements interaction with SiliconFlow API and Gaode Map MCP services** ⭐⭐⭐
- Contains type definitions for tool calls and message handling.
- **build/siliconflow-client.js**
- JavaScript file generated by TypeScript compilation.
- Referenced by the server at runtime.
#### Frontend Files
- **index.html**
- HTML structure of the chat interface.
- Defines message container and input area.
- **styles.css**
- Defines styles for the chat interface.
- Implements responsive design.
- **app.js** ⭐⭐
- Frontend JavaScript code.
- Handles user input and message display.
- **Interacts with backend API to send queries and process responses** ⭐⭐
#### Configuration Files
- **package.json** - Project metadata, dependencies, and script definitions.
- **tsconfig.json** - TypeScript compiler configuration.
- **.env** - Environment variable configuration (to be created).
- **.env.example** - Environment variable configuration example.
## Core Technical Highlights
<div align="center">
<table>
<tr>
<th>Technical Highlights</th>
<th>Importance</th>
<th>Description</th>
</tr>
<tr>
<td><b>MCP Protocol Integration</b></td>
<td>⭐⭐⭐</td>
<td>
- Achieves seamless connection between large models and map services<br>
- Supports 12 geographic service tools provided by Gaode Map<br>
- Real-time communication via SSE
</td>
</tr>
<tr>
<td><b>Large Language Model Application</b></td>
<td>⭐⭐⭐</td>
<td>
- Uses SiliconFlow API to access QWEN large model<br>
- Smartly parses user intent and selects appropriate tools<br>
- Processes tool call results and generates natural language responses
</td>
</tr>
<tr>
<td><b>Map Service Integration</b></td>
<td>⭐⭐</td>
<td>
- Supports functions like place search, nearby queries, and route planning<br>
- Integrates cycling, driving, public transport, and walking route planning<br>
- Weather queries, geocoding, and reverse geocoding functionalities
</td>
</tr>
<tr>
<td><b>Separation of Frontend and Backend Architecture</b></td>
<td>⭐</td>
<td>
- Express backend provides API services<br>
- Simple frontend interface for user interaction<br>
- RESTful API design promotes decoupling of frontend and backend
</td>
</tr>
</table>
</div>
## Development Guide
### Quick Start
This section provides key code examples and guidelines for project development, helping you quickly understand the core functionality implementation.
### Backend Development
#### 1. MCP Client Initialization
```javascript
// Create MCP client
const mcpClient = new Client({
name: "mcp-chat-client",
version: "1.0.0"
});
// Initialize SSE transport and connect to Gaode Map MCP service
const transport = new SSEClientTransport(new URL(AMAP_MCP_URL));
mcpClient.connect(transport);
// Get available tool list
const toolsResult = await mcpClient.listTools();
const availableTools = toolsResult.tools;
console.log(`Retrieved ${availableTools.length} available tools`);
```
#### 2. Large Model and Tool Call Integration
```javascript
// Prepare tool definitions for large model usage
const toolDefinitions = availableTools.map(tool => ({
type: "function",
function: {
name: tool.name,
description: tool.description,
parameters: tool.inputSchema
}
}));
// Call SiliconFlow API
const response = await axios.post(
SILICONFLOW_API_URL,
{
model: QWEN_MODEL,
messages: messages,
tools: toolDefinitions,
temperature: 0.7,
// Other parameters...
},
{
headers: {
'Authorization': `Bearer ${SILICONFLOW_API_KEY}`,
'Content-Type': 'application/json',
},
}
);
// If the model decides to call a tool
if (responseMessage.tool_calls && responseMessage.tool_calls.length > 0) {
// Handle tool calls
for (const toolCall of responseMessage.tool_calls) {
const toolName = toolCall.function.name;
const toolArgs = JSON.parse(toolCall.function.arguments);
// Call MCP tool
const toolResult = await mcpClient.callTool({
name: toolName,
arguments: toolArgs
});
console.log(`Tool ${toolName} call result:`, toolResult);
}
}
```
#### 3. Message Processing Flow
```javascript
// Complete message processing flow
async function processQuery(message) {
// 1. Add user message to history
const messages = [...messageHistory, { role: 'user', content: message }];
// 2. Call large model API
const initialResponse = await callLLMAPI(messages, availableTools);
// 3. If there are tool calls
if (initialResponse.tool_calls) {
// 3.1 Execute tool calls
const toolResults = await executeToolCalls(initialResponse.tool_calls);
// 3.2 Add tool results to message history
const messagesWithTools = addToolResultsToMessages(messages,
initialResponse.tool_calls,
toolResults);
// 3.3 Call large model again to get final response
const finalResponse = await callLLMAPI(messagesWithTools);
return finalResponse.content;
}
// 4. If there are no tool calls, return content directly
return initialResponse.content;
}
```
### Frontend Development
#### 1. Chat Interface Initialization
```javascript
// DOM element initialization
const chatMessages = document.getElementById('chatMessages');
const userInput = document.getElementById('userInput');
const sendButton = document.getElementById('sendButton');
// Initialization
document.addEventListener('DOMContentLoaded', () => {
// Add welcome message
addMessage('system', 'Welcome to the Gaode Map MCP Chat Assistant! You can ask about weather, route planning, place queries, and more.');
});
```
#### 2. User Interaction Handling
```javascript
// Handle user input
async function handleUserInput() {
const query = userInput.value.trim();
if (!query || isProcessing) return;
// Clear input box and add user message
userInput.value = '';
addMessage('user', query);
messages.push({ role: 'user', content: query });
// Show loading indicator
addLoadingMessage();
isProcessing = true;
try {
// Call backend API
const response = await callBackendAPI(query);
removeLoadingMessage();
addMessage('assistant', response);
} catch (error) {
removeLoadingMessage();
addMessage('error', `Error: ${error.message || 'Unknown error'}`);
console.error('Error processing query:', error);
} finally {
isProcessing = false;
}
}
```
#### 3. API Call
```javascript
// Call backend API
async function callBackendAPI(query) {
try {
// Send request
const response = await fetch(BACKEND_API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ messages: messages })
});
// Error handling
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || `Request failed: ${response.status}`);
}
// Process response
const data = await response.json();
if (data.content) {
messages.push({ role: 'assistant', content: data.content });
return data.content;
} else {
throw new Error('Server response format error');
}
} catch (error) {
console.error('API call failed:', error);
throw error;
}
}
```
## Open Source License
This project is open-sourced under the [MIT License](https://opensource.org/licenses/MIT).
## Contribution Guidelines
We welcome and appreciate all forms of contributions!
### How to Contribute
1. Fork this repository
2. Create a feature branch: `git checkout -b feature/amazing-feature`
3. Commit your changes: `git commit -m 'Add some amazing feature'`
4. Push to the branch: `git push origin feature/amazing-feature`
5. Create a Pull Request
### Types of Contributions
* Feature enhancements and new features
* Bug fixes and performance improvements
* Documentation improvements
* Test cases
* Code quality improvements
## Notes and Best Practices
### Key Configuration
1. **API Key Management**
- Ensure the `SILICONFLOW_API_KEY` is correctly configured in the `.env` file.
- Never hard-code API keys in the code.
- Consider using environment variables or secure key management services in production.
2. **MCP Connection Management**
- Implement connection retry mechanisms to handle network fluctuations.
- Add connection status monitoring and health checks.
- Provide graceful degradation handling in case of connection failures.
### MCP Tool Call Considerations
1. **Tool Name Format**
```javascript
// Example of Gaode Map MCP tool name format
const toolName = "mcp0_maps_text_search"; // Place search
const toolName = "mcp0_maps_direction_driving"; // Driving route planning
```
2. **Correct Tool Call Format**
```javascript
// ✅ Correct way to call
const toolResult = await mcpClient.callTool({
name: toolName,
arguments: toolArgs
});
// ❌ Incorrect way to call
// const toolResult = await mcpClient.callTool(toolName, toolArgs);
```
3. **Parameter Format Validation**
- Ensure parameters meet the `inputSchema` requirements of the tool.
- Validate the completeness of tool definitions before sending to the large model.
### Error Handling
```javascript
// Example of tool call error handling
try {
const toolResult = await mcpClient.callTool({
name: toolName,
arguments: toolArgs
});
return toolResult;
} catch (error) {
console.error(`Tool ${toolName} call failed:`, error);
// Return a friendly error message to the user
return { error: `Unable to complete operation: ${error.message || 'Unknown error'}` };
}
```
## Frequently Asked Questions
<details>
<summary><b>Failed to connect to Gaode Map MCP service</b></summary>
### Issue
Unable to connect to Gaode Map MCP service when starting the server.
### Solution
1. Check if the network connection is stable.
2. Confirm that the API Key in AMAP_MCP_URL is valid.
3. Review detailed error messages in the server logs.
4. Try increasing the connection timeout or implementing a retry mechanism.
</details>
<details>
<summary><b>Large model API call failed</b></summary>
### Issue
An error occurs when calling the SiliconFlow API.
### Solution
1. Verify that the SILICONFLOW_API_KEY is correctly configured and valid.
2. Check if the request format meets API requirements.
3. Review response status codes and error messages.
4. Confirm if the API call limit has been exceeded.
</details>
<details>
<summary><b>Tool call returns an error</b></summary>
### Issue
An error is returned when calling Gaode Map MCP tools.
### Solution
1. Check if the tool name is correct (including the prefix `mcp0_`).
2. Validate if the parameter format meets the tool's `inputSchema` requirements.
3. For geographic coordinate parameters, ensure the format is "longitude,latitude".
4. Review detailed error messages in the server logs.
</details>
<details>
<summary><b>Frontend interface fails to load</b></summary>
### Issue
The frontend interface fails to load when accessing http://localhost:3000.
### Solution
1. Confirm if the server has started successfully and check if the port is occupied.
2. Verify if Express is correctly configured to serve static files.
3. Check for error messages in the browser console.
4. Try clearing the browser cache or using incognito mode.
</details>