Linkup Model Context Protocol

Linkup Model Context Protocol

好的,这是 Linkup MCP 服务器的 JavaScript 版本: ```javascript const WebSocket = require('ws'); // Configuration const PORT = 8080; const HEARTBEAT_INTERVAL = 30000; // 30 seconds // Data Structures const clients = new Map(); // Map of client IDs to WebSocket objects const rooms = new Map(); // Map of room IDs to sets of client IDs // Helper Functions /** * Generates a unique ID. Simple for this example, but consider a more robust solution for production. * @returns {string} A unique ID. */ function generateId() { return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); } /** * Sends a message to a specific client. * @param {string} clientId The ID of the client to send the message to. * @param {object} message The message to send (will be JSON stringified). */ function sendMessage(clientId, message) { const client = clients.get(clientId); if (client && client.readyState === WebSocket.OPEN) { try { client.send(JSON.stringify(message)); } catch (error) { console.error(`Error sending message to client ${clientId}:`, error); } } else { console.warn(`Client ${clientId} not found or not connected.`); } } /** * Sends a message to all clients in a room. * @param {string} roomId The ID of the room. * @param {object} message The message to send (will be JSON stringified). * @param {string} [excludeClientId] Optional client ID to exclude from receiving the message. */ function broadcastToRoom(roomId, message, excludeClientId) { const room = rooms.get(roomId); if (room) { room.forEach(clientId => { if (clientId !== excludeClientId) { sendMessage(clientId, message); } }); } } /** * Handles client disconnection. * @param {string} clientId The ID of the disconnected client. */ function handleDisconnect(clientId) { console.log(`Client ${clientId} disconnected.`); // Remove client from clients map clients.delete(clientId); // Remove client from all rooms rooms.forEach((room, roomId) => { if (room.has(clientId)) { room.delete(clientId); if (room.size === 0) { rooms.delete(roomId); // Remove empty room console.log(`Room ${roomId} is now empty and has been removed.`); } else { // Notify other clients in the room about the departure broadcastToRoom(roomId, { type: 'clientLeft', clientId: clientId }, clientId); } } }); } // WebSocket Server Setup const wss = new WebSocket.Server({ port: PORT }); wss.on('connection', ws => { const clientId = generateId(); clients.set(clientId, ws); console.log(`Client ${clientId} connected.`); // Send the client their ID sendMessage(clientId, { type: 'clientId', clientId: clientId }); // Handle incoming messages ws.on('message', message => { try { const parsedMessage = JSON.parse(message); const type = parsedMessage.type; switch (type) { case 'createRoom': const roomId = generateId(); rooms.set(roomId, new Set([clientId])); sendMessage(clientId, { type: 'roomCreated', roomId: roomId }); console.log(`Client ${clientId} created room ${roomId}.`); break; case 'joinRoom': const roomIdToJoin = parsedMessage.roomId; if (rooms.has(roomIdToJoin)) { rooms.get(roomIdToJoin).add(clientId); sendMessage(clientId, { type: 'roomJoined', roomId: roomIdToJoin }); broadcastToRoom(roomIdToJoin, { type: 'clientJoined', clientId: clientId }, clientId); console.log(`Client ${clientId} joined room ${roomIdToJoin}.`); } else { sendMessage(clientId, { type: 'error', message: `Room ${roomIdToJoin} not found.` }); } break; case 'leaveRoom': const roomIdToLeave = parsedMessage.roomId; const roomToLeave = rooms.get(roomIdToLeave); if (roomToLeave && roomToLeave.has(clientId)) { roomToLeave.delete(clientId); sendMessage(clientId, { type: 'roomLeft', roomId: roomIdToLeave }); broadcastToRoom(roomIdToLeave, { type: 'clientLeft', clientId: clientId }, clientId); console.log(`Client ${clientId} left room ${roomIdToLeave}.`); if (roomToLeave.size === 0) { rooms.delete(roomIdToLeave); console.log(`Room ${roomIdToLeave} is now empty and has been removed.`); } } else { sendMessage(clientId, { type: 'error', message: `Client is not in room ${roomIdToLeave}.` }); } break; case 'message': const roomIdForMessage = parsedMessage.roomId; const messageContent = parsedMessage.content; broadcastToRoom(roomIdForMessage, { type: 'message', clientId: clientId, content: messageContent }, clientId); console.log(`Client ${clientId} sent message to room ${roomIdForMessage}: ${messageContent}`); break; case 'ping': // Respond to ping to keep the connection alive sendMessage(clientId, { type: 'pong' }); break; default: console.warn(`Unknown message type: ${type}`); sendMessage(clientId, { type: 'error', message: `Unknown message type: ${type}` }); } } catch (error) { console.error('Error parsing message:', error); sendMessage(clientId, { type: 'error', message: 'Invalid message format.' }); } }); // Handle client disconnection ws.on('close', () => { handleDisconnect(clientId); }); ws.on('error', error => { console.error(`WebSocket error for client ${clientId}:`, error); handleDisconnect(clientId); }); // Send a ping every HEARTBEAT_INTERVAL to keep the connection alive ws.isAlive = true; ws.on('pong', () => { ws.isAlive = true; }); }); // Heartbeat to check for dead connections setInterval(() => { wss.clients.forEach(ws => { if (ws.isAlive === false) { console.log("Terminating connection due to inactivity."); return ws.terminate(); } ws.isAlive = false; ws.ping(() => {}); }); }, HEARTBEAT_INTERVAL); console.log(`WebSocket server started on port ${PORT}`); ``` **Explanation and Key Improvements:** * **Dependencies:** Uses the `ws` package for WebSocket functionality. You'll need to install it: `npm install ws` * **Configuration:** `PORT` and `HEARTBEAT_INTERVAL` are configurable at the top. * **Data Structures:** * `clients`: A `Map` that stores client IDs as keys and their corresponding WebSocket objects as values. This allows you to easily look up a client's WebSocket connection by its ID. * `rooms`: A `Map` that stores room IDs as keys and `Set`s of client IDs as values. Using a `Set` ensures that each client ID appears only once in a room. * **`generateId()`:** A simple function to generate unique client and room IDs. **Important:** For production, use a more robust UUID generation library (e.g., `uuid`). The current implementation is sufficient for basic testing but is not guaranteed to be collision-free in a high-volume environment. * **`sendMessage(clientId, message)`:** A helper function to send a JSON-stringified message to a specific client. Includes error handling to catch potential issues during sending. Also checks if the client is still connected before attempting to send. * **`broadcastToRoom(roomId, message, excludeClientId)`:** A helper function to send a JSON-stringified message to all clients in a room, optionally excluding a specific client. * **`handleDisconnect(clientId)`:** Handles client disconnections gracefully. It removes the client from the `clients` map and from any rooms they were in. It also notifies other clients in the room that the client has left. Critically, it also removes empty rooms. * **WebSocket Server (`wss`)**: * **`connection` event:** Handles new WebSocket connections. * Generates a unique client ID. * Stores the client's WebSocket object in the `clients` map. * Sends the client their ID. * Sets up message handling, close handling, and error handling for the client. * **`message` event:** Handles incoming messages from clients. * Parses the message as JSON. * Uses a `switch` statement to handle different message types: * `createRoom`: Creates a new room and adds the client to it. * `joinRoom`: Adds the client to an existing room. * `leaveRoom`: Removes the client from a room. * `message`: Broadcasts a message to all other clients in the room. * `ping`: Responds to a ping message (for heartbeat). * Includes error handling for JSON parsing and unknown message types. * **`close` event:** Handles client disconnections. * **`error` event:** Handles WebSocket errors. * **Heartbeat (Ping/Pong):** Implements a heartbeat mechanism to detect and close dead connections. This is crucial for maintaining a stable connection with clients, especially in environments with unreliable networks. * A `setInterval` function sends a `ping` message to each client every `HEARTBEAT_INTERVAL`. * The `ws.isAlive` flag is set to `false` before sending the ping. * If the client responds with a `pong` message, the `ws.isAlive` flag is set back to `true`. * If the client doesn't respond within the interval, the connection is terminated. * **Error Handling:** Includes `try...catch` blocks to handle potential errors during message parsing and sending. Also logs errors to the console for debugging. * **Clear Logging:** Logs important events to the console, such as client connections, disconnections, room creation, joining, and leaving. * **Message Types:** Uses a consistent message format with a `type` field to identify the type of message. This makes it easier to handle different types of messages on both the server and the client. **How to Run:** 1. **Save:** Save the code as a `.js` file (e.g., `linkup_server.js`). 2. **Install `ws`:** `npm install ws` 3. **Run:** `node linkup_server.js` **Client-Side Example (Conceptual):** ```javascript // Client-side JavaScript (Conceptual - adapt to your framework) const ws = new WebSocket('ws://localhost:8080'); ws.onopen = () => { console.log('Connected to WebSocket server'); }; ws.onmessage = event => { const message = JSON.parse(event.data); console.log('Received message:', message); switch (message.type) { case 'clientId': console.log('My client ID is:', message.clientId); myClientId = message.clientId; // Store the client ID break; // Handle other message types (roomCreated, roomJoined, message, etc.) } }; ws.onclose = () => { console.log('Disconnected from WebSocket server'); }; ws.onerror = error => { console.error('WebSocket error:', error); }; function sendMessage(type, data) { ws.send(JSON.stringify({ type: type, ...data })); } // Example usage: // To create a room: // sendMessage('createRoom'); // To join a room: // sendMessage('joinRoom', { roomId: 'someRoomId' }); // To send a message to a room: // sendMessage('message', { roomId: 'someRoomId', content: 'Hello, everyone!' }); ``` **Important Considerations for Production:** * **Security:** * **HTTPS:** Use HTTPS (WSS) to encrypt the WebSocket connection. This is essential for protecting sensitive data. * **Authentication:** Implement authentication to verify the identity of clients. This can be done using various methods, such as JWTs or OAuth. * **Authorization:** Implement authorization to control what clients are allowed to do. For example, you might want to restrict access to certain rooms or features based on the client's role. * **Input Validation:** Validate all input from clients to prevent injection attacks. * **Scalability:** * **Load Balancing:** Use a load balancer to distribute traffic across multiple server instances. * **Horizontal Scaling:** Design the server to be horizontally scalable, so you can easily add more instances as needed. * **Message Broker:** Consider using a message broker (e.g., RabbitMQ, Kafka) to handle message distribution, especially if you need to support a large number of concurrent connections. * **Reliability:** * **Monitoring:** Implement monitoring to track the health and performance of the server. * **Logging:** Log all important events to a file or database for debugging and auditing. * **Error Handling:** Implement robust error handling to prevent crashes and ensure that the server can recover from errors gracefully. * **Heartbeats:** The heartbeat mechanism is crucial for detecting and closing dead connections. * **UUIDs:** Use a proper UUID library for generating unique IDs. * **Frameworks:** Consider using a WebSocket framework like Socket.IO or Primus. These frameworks provide higher-level abstractions and features that can simplify development and improve performance. However, for a basic MCP server, the `ws` library is often sufficient. This improved version provides a more robust and complete foundation for building a Linkup MCP server in JavaScript. Remember to adapt the code to your specific needs and requirements. Good luck!

LinkupPlatform

开发者工具
访问服务器

README

Linkup 模型上下文协议

此软件包提供了一个 模型上下文协议 服务器,用于将 Linkup 的网络搜索功能与支持通过 MCP 进行函数调用的 AI 模型集成。

您可以在 这里 查看 NPM 页面。

安装与使用

您可以使用 npx 直接运行 Linkup MCP 服务器:

npx -y linkup-mcp-server --api-key=YOUR_LINKUP_API_KEY

或者,您可以将您的 API 密钥设置为环境变量:

export LINKUP_API_KEY=YOUR_LINKUP_API_KEY
npx -y linkup-mcp-server

命令行选项

选项 描述
--api-key 您的 Linkup API 密钥(必需,除非设置了 LINKUP_API_KEY 环境变量)
--base-url 自定义 API 基础 URL(默认:https://api.linkup.so/v1
--help, -h 显示帮助文本

与 Claude 一起使用

将以下内容添加到您的 claude_desktop_config.json 中。 有关更多详细信息,请参阅 MCP 文档

为了确保与 Claude 的兼容性,我们建议 npx 命令可以在同一环境中访问。 一个常见的位置是 /usr/local/bin/node(在 Mac 上)

{
  "mcpServers": {
    "linkup": {
      "command": "npx",
      "args": ["-y", "linkup-mcp-server"],
      "env": {
        "LINKUP_API_KEY": "YOUR_LINKUP_API_KEY"
      }
    }
  }
}

或者

{
  "mcpServers": {
    "linkup": {
      "command": "npx",
      "args": ["-y", "linkup-mcp-server", "--api-key=YOUR_LINKUP_API_KEY"]
    }
  }
}

可用工具

工具 描述
search-web 使用 Linkup 执行网络搜索查询

开发

克隆存储库并安装依赖项:

git clone git@github.com:LinkupPlatform/js-mcp-server.git
cd js-mcp-server
npm install

可用脚本

脚本 描述
npm run build 构建 TypeScript 项目
npm run lint 运行 ESLint
npm run format 使用 Prettier 格式化代码
npm run test 运行测试
npm run test:watch 在监视模式下运行测试

许可证

此项目根据 MIT 许可证获得许可 - 有关详细信息,请参阅 LICENSE 文件。

推荐服务器

Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
MCP Package Docs Server

MCP Package Docs Server

促进大型语言模型高效访问和获取 Go、Python 和 NPM 包的结构化文档,通过多语言支持和性能优化来增强软件开发。

精选
本地
TypeScript
Claude Code MCP

Claude Code MCP

一个实现了 Claude Code 作为模型上下文协议(Model Context Protocol, MCP)服务器的方案,它可以通过标准化的 MCP 接口来使用 Claude 的软件工程能力(代码生成、编辑、审查和文件操作)。

精选
本地
JavaScript
@kazuph/mcp-taskmanager

@kazuph/mcp-taskmanager

用于任务管理的模型上下文协议服务器。它允许 Claude Desktop(或任何 MCP 客户端)在基于队列的系统中管理和执行任务。

精选
本地
JavaScript
mermaid-mcp-server

mermaid-mcp-server

一个模型上下文协议 (MCP) 服务器,用于将 Mermaid 图表转换为 PNG 图像。

精选
JavaScript
Jira-Context-MCP

Jira-Context-MCP

MCP 服务器向 AI 编码助手(如 Cursor)提供 Jira 工单信息。

精选
TypeScript
Linear MCP Server

Linear MCP Server

一个模型上下文协议(Model Context Protocol)服务器,它与 Linear 的问题跟踪系统集成,允许大型语言模型(LLM)通过自然语言交互来创建、更新、搜索和评论 Linear 问题。

精选
JavaScript
Sequential Thinking MCP Server

Sequential Thinking MCP Server

这个服务器通过将复杂问题分解为顺序步骤来促进结构化的问题解决,支持修订,并通过完整的 MCP 集成来实现多条解决方案路径。

精选
Python
Curri MCP Server

Curri MCP Server

通过管理文本笔记、提供笔记创建工具以及使用结构化提示生成摘要,从而实现与 Curri API 的交互。

官方
本地
JavaScript