mirror of
https://github.com/Yidadaa/ChatGPT-Next-Web.git
synced 2025-08-08 07:10:16 +08:00
feat: Optimize MCP configuration logic
This commit is contained in:
@@ -1,236 +1,217 @@
|
||||
"use server";
|
||||
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||
import {
|
||||
createClient,
|
||||
executeRequest,
|
||||
listPrimitives,
|
||||
Primitive,
|
||||
listTools,
|
||||
removeClient,
|
||||
} from "./client";
|
||||
import { MCPClientLogger } from "./logger";
|
||||
import { McpRequestMessage, McpConfig, ServerConfig } from "./types";
|
||||
import {
|
||||
DEFAULT_MCP_CONFIG,
|
||||
McpClientData,
|
||||
McpConfigData,
|
||||
McpRequestMessage,
|
||||
ServerConfig,
|
||||
} from "./types";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
const logger = new MCPClientLogger("MCP Actions");
|
||||
|
||||
// Use Map to store all clients
|
||||
const clientsMap = new Map<
|
||||
string,
|
||||
{ client: Client | null; primitives: Primitive[]; errorMsg: string | null }
|
||||
>();
|
||||
|
||||
// Whether initialized
|
||||
let initialized = false;
|
||||
|
||||
// Store failed clients
|
||||
let errorClients: string[] = [];
|
||||
|
||||
const CONFIG_PATH = path.join(process.cwd(), "app/mcp/mcp_config.json");
|
||||
|
||||
// 获取 MCP 配置
|
||||
export async function getMcpConfig(): Promise<McpConfig> {
|
||||
try {
|
||||
const configStr = await fs.readFile(CONFIG_PATH, "utf-8");
|
||||
return JSON.parse(configStr);
|
||||
} catch (error) {
|
||||
console.error("Failed to read MCP config:", error);
|
||||
return { mcpServers: {} };
|
||||
}
|
||||
const clientsMap = new Map<string, McpClientData>();
|
||||
|
||||
// 获取客户端状态
|
||||
export async function getClientStatus(clientId: string) {
|
||||
const status = clientsMap.get(clientId);
|
||||
if (!status) return { status: "undefined" as const, errorMsg: null };
|
||||
|
||||
return {
|
||||
status: status.errorMsg ? ("error" as const) : ("active" as const),
|
||||
errorMsg: status.errorMsg,
|
||||
};
|
||||
}
|
||||
|
||||
// 更新 MCP 配置
|
||||
export async function updateMcpConfig(config: McpConfig): Promise<void> {
|
||||
try {
|
||||
await fs.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
|
||||
} catch (error) {
|
||||
console.error("Failed to write MCP config:", error);
|
||||
throw error;
|
||||
}
|
||||
// 获取客户端工具
|
||||
export async function getClientTools(clientId: string) {
|
||||
return clientsMap.get(clientId)?.tools ?? null;
|
||||
}
|
||||
|
||||
// 重新初始化所有客户端
|
||||
export async function reinitializeMcpClients() {
|
||||
logger.info("Reinitializing MCP clients...");
|
||||
// 遍历所有客户端,关闭
|
||||
try {
|
||||
for (const [clientId, clientData] of clientsMap.entries()) {
|
||||
clientData.client?.close();
|
||||
// 获取可用客户端数量
|
||||
export async function getAvailableClientsCount() {
|
||||
let count = 0;
|
||||
clientsMap.forEach((map) => {
|
||||
if (!map.errorMsg) {
|
||||
count += map?.tools?.tools?.length ?? 0;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Failed to close clients: ${error}`);
|
||||
}
|
||||
// 清空状态
|
||||
clientsMap.clear();
|
||||
errorClients = [];
|
||||
initialized = false;
|
||||
// 重新初始化
|
||||
return initializeMcpClients();
|
||||
});
|
||||
return count;
|
||||
}
|
||||
|
||||
// Initialize all configured clients
|
||||
export async function initializeMcpClients() {
|
||||
// If already initialized, return
|
||||
if (initialized) {
|
||||
return { errorClients };
|
||||
// 获取所有客户端工具
|
||||
export async function getAllTools() {
|
||||
const result = [];
|
||||
for (const [clientId, status] of clientsMap.entries()) {
|
||||
result.push({
|
||||
clientId,
|
||||
tools: status.tools,
|
||||
});
|
||||
}
|
||||
|
||||
logger.info("Starting to initialize MCP clients...");
|
||||
errorClients = [];
|
||||
|
||||
const config = await getMcpConfig();
|
||||
// Initialize all clients, key is clientId, value is client config
|
||||
for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) {
|
||||
try {
|
||||
logger.info(`Initializing MCP client: ${clientId}`);
|
||||
const client = await createClient(serverConfig as ServerConfig, clientId);
|
||||
const primitives = await listPrimitives(client);
|
||||
clientsMap.set(clientId, { client, primitives, errorMsg: null });
|
||||
logger.success(
|
||||
`Client [${clientId}] initialized, ${primitives.length} primitives supported`,
|
||||
);
|
||||
} catch (error) {
|
||||
errorClients.push(clientId);
|
||||
clientsMap.set(clientId, {
|
||||
client: null,
|
||||
primitives: [],
|
||||
errorMsg: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
logger.error(`Failed to initialize client ${clientId}: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
||||
if (errorClients.length > 0) {
|
||||
logger.warn(`Failed to initialize clients: ${errorClients.join(", ")}`);
|
||||
} else {
|
||||
logger.success("All MCP clients initialized");
|
||||
}
|
||||
|
||||
const availableClients = await getAvailableClients();
|
||||
logger.info(`Available clients: ${availableClients.join(",")}`);
|
||||
|
||||
return { errorClients };
|
||||
return result;
|
||||
}
|
||||
|
||||
// Execute MCP request
|
||||
export async function executeMcpAction(
|
||||
// 初始化单个客户端
|
||||
async function initializeSingleClient(
|
||||
clientId: string,
|
||||
request: McpRequestMessage,
|
||||
serverConfig: ServerConfig,
|
||||
) {
|
||||
logger.info(`Initializing client [${clientId}]...`);
|
||||
try {
|
||||
// Find the corresponding client
|
||||
const client = clientsMap.get(clientId)?.client;
|
||||
if (!client) {
|
||||
logger.error(`Client ${clientId} not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info(`Executing MCP request for ${clientId}`);
|
||||
|
||||
// Execute request and return result
|
||||
return await executeRequest(client, request);
|
||||
const client = await createClient(clientId, serverConfig);
|
||||
const tools = await listTools(client);
|
||||
clientsMap.set(clientId, { client, tools, errorMsg: null });
|
||||
logger.success(`Client [${clientId}] initialized successfully`);
|
||||
} catch (error) {
|
||||
logger.error(`MCP execution error: ${error}`);
|
||||
clientsMap.set(clientId, {
|
||||
client: null,
|
||||
tools: null,
|
||||
errorMsg: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
logger.error(`Failed to initialize client [${clientId}]: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化系统
|
||||
export async function initializeMcpSystem() {
|
||||
logger.info("MCP Actions starting...");
|
||||
try {
|
||||
const config = await getMcpConfigFromFile();
|
||||
// 初始化所有客户端
|
||||
for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) {
|
||||
await initializeSingleClient(clientId, serverConfig);
|
||||
}
|
||||
return config;
|
||||
} catch (error) {
|
||||
logger.error(`Failed to initialize MCP system: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Get all available client IDs
|
||||
export async function getAvailableClients() {
|
||||
return Array.from(clientsMap.entries())
|
||||
.filter(([_, data]) => data.errorMsg === null)
|
||||
.map(([clientId]) => clientId);
|
||||
}
|
||||
|
||||
// Get all primitives from all clients
|
||||
export async function getAllPrimitives(): Promise<
|
||||
{
|
||||
clientId: string;
|
||||
primitives: Primitive[];
|
||||
}[]
|
||||
> {
|
||||
return Array.from(clientsMap.entries()).map(([clientId, { primitives }]) => ({
|
||||
clientId,
|
||||
primitives,
|
||||
}));
|
||||
}
|
||||
|
||||
// 获取客户端的 Primitives
|
||||
export async function getClientPrimitives(clientId: string) {
|
||||
// 添加服务器
|
||||
export async function addMcpServer(clientId: string, config: ServerConfig) {
|
||||
try {
|
||||
const clientData = clientsMap.get(clientId);
|
||||
if (!clientData) {
|
||||
console.warn(`Client ${clientId} not found in map`);
|
||||
return null;
|
||||
}
|
||||
if (clientData.errorMsg) {
|
||||
console.warn(`Client ${clientId} has error: ${clientData.errorMsg}`);
|
||||
return null;
|
||||
}
|
||||
return clientData.primitives;
|
||||
const currentConfig = await getMcpConfigFromFile();
|
||||
const newConfig = {
|
||||
...currentConfig,
|
||||
mcpServers: {
|
||||
...currentConfig.mcpServers,
|
||||
[clientId]: config,
|
||||
},
|
||||
};
|
||||
await updateMcpConfig(newConfig);
|
||||
// 只初始化新添加的服务器
|
||||
await initializeSingleClient(clientId, config);
|
||||
return newConfig;
|
||||
} catch (error) {
|
||||
console.error(`Failed to get primitives for client ${clientId}:`, error);
|
||||
return null;
|
||||
logger.error(`Failed to add server [${clientId}]: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 移除服务器
|
||||
export async function removeMcpServer(clientId: string) {
|
||||
try {
|
||||
const currentConfig = await getMcpConfigFromFile();
|
||||
const { [clientId]: _, ...rest } = currentConfig.mcpServers;
|
||||
const newConfig = {
|
||||
...currentConfig,
|
||||
mcpServers: rest,
|
||||
};
|
||||
await updateMcpConfig(newConfig);
|
||||
|
||||
// 关闭并移除客户端
|
||||
const client = clientsMap.get(clientId);
|
||||
if (client?.client) {
|
||||
await removeClient(client.client);
|
||||
}
|
||||
clientsMap.delete(clientId);
|
||||
|
||||
return newConfig;
|
||||
} catch (error) {
|
||||
logger.error(`Failed to remove server [${clientId}]: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 重启所有客户端
|
||||
export async function restartAllClients() {
|
||||
logger.info("Restarting all MCP clients...");
|
||||
|
||||
// 清空状态
|
||||
clientsMap.clear();
|
||||
errorClients = [];
|
||||
initialized = false;
|
||||
|
||||
// 重新初始化
|
||||
await initializeMcpClients();
|
||||
|
||||
return {
|
||||
success: errorClients.length === 0,
|
||||
errorClients,
|
||||
};
|
||||
}
|
||||
|
||||
// 获取所有客户端状态
|
||||
export async function getAllClientStatus(): Promise<
|
||||
Record<string, string | null>
|
||||
> {
|
||||
const status: Record<string, string | null> = {};
|
||||
for (const [clientId, data] of clientsMap.entries()) {
|
||||
status[clientId] = data.errorMsg;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// 检查客户端状态
|
||||
export async function getClientErrors(): Promise<
|
||||
Record<string, string | null>
|
||||
> {
|
||||
const errors: Record<string, string | null> = {};
|
||||
for (const [clientId, data] of clientsMap.entries()) {
|
||||
errors[clientId] = data.errorMsg;
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
// 获取客户端状态,不重新初始化
|
||||
export async function refreshClientStatus() {
|
||||
logger.info("Refreshing client status...");
|
||||
|
||||
// 如果还没初始化过,则初始化
|
||||
if (!initialized) {
|
||||
return initializeMcpClients();
|
||||
}
|
||||
|
||||
// 否则只更新错误状态
|
||||
errorClients = [];
|
||||
for (const [clientId, clientData] of clientsMap.entries()) {
|
||||
if (clientData.errorMsg !== null) {
|
||||
errorClients.push(clientId);
|
||||
logger.info("Restarting all clients...");
|
||||
try {
|
||||
// 关闭所有客户端
|
||||
for (const client of clientsMap.values()) {
|
||||
if (client.client) {
|
||||
await removeClient(client.client);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 清空状态
|
||||
clientsMap.clear();
|
||||
|
||||
return { errorClients };
|
||||
// 重新初始化
|
||||
const config = await getMcpConfigFromFile();
|
||||
for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) {
|
||||
await initializeSingleClient(clientId, serverConfig);
|
||||
}
|
||||
return config;
|
||||
} catch (error) {
|
||||
logger.error(`Failed to restart clients: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 执行 MCP 请求
|
||||
export async function executeMcpAction(
|
||||
clientId: string,
|
||||
request: McpRequestMessage,
|
||||
) {
|
||||
try {
|
||||
const client = clientsMap.get(clientId);
|
||||
if (!client?.client) {
|
||||
throw new Error(`Client ${clientId} not found`);
|
||||
}
|
||||
logger.info(`Executing request for [${clientId}]`);
|
||||
return await executeRequest(client.client, request);
|
||||
} catch (error) {
|
||||
logger.error(`Failed to execute request for [${clientId}]: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取 MCP 配置文件
|
||||
export async function getMcpConfigFromFile(): Promise<McpConfigData> {
|
||||
try {
|
||||
const configStr = await fs.readFile(CONFIG_PATH, "utf-8");
|
||||
return JSON.parse(configStr);
|
||||
} catch (error) {
|
||||
logger.error(`Failed to load MCP config, using default config: ${error}`);
|
||||
return DEFAULT_MCP_CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新 MCP 配置文件
|
||||
async function updateMcpConfig(config: McpConfigData): Promise<void> {
|
||||
try {
|
||||
await fs.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 重新初始化单个客户端
|
||||
export async function reinitializeClient(clientId: string) {
|
||||
const config = await getMcpConfigFromFile();
|
||||
const serverConfig = config.mcpServers[clientId];
|
||||
if (!serverConfig) {
|
||||
throw new Error(`Server config not found for client ${clientId}`);
|
||||
}
|
||||
await initializeSingleClient(clientId, serverConfig);
|
||||
}
|
||||
|
@@ -1,85 +1,45 @@
|
||||
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
||||
import { MCPClientLogger } from "./logger";
|
||||
import { McpRequestMessage } from "./types";
|
||||
import { ListToolsResponse, McpRequestMessage, ServerConfig } from "./types";
|
||||
import { z } from "zod";
|
||||
|
||||
export interface ServerConfig {
|
||||
command: string;
|
||||
args?: string[];
|
||||
env?: Record<string, string>;
|
||||
}
|
||||
|
||||
const logger = new MCPClientLogger();
|
||||
|
||||
export async function createClient(
|
||||
serverConfig: ServerConfig,
|
||||
name: string,
|
||||
id: string,
|
||||
config: ServerConfig,
|
||||
): Promise<Client> {
|
||||
logger.info(`Creating client for server ${name}`);
|
||||
logger.info(`Creating client for ${id}...`);
|
||||
|
||||
const transport = new StdioClientTransport({
|
||||
command: serverConfig.command,
|
||||
args: serverConfig.args,
|
||||
env: serverConfig.env,
|
||||
command: config.command,
|
||||
args: config.args,
|
||||
env: config.env,
|
||||
});
|
||||
|
||||
const client = new Client(
|
||||
{
|
||||
name: `nextchat-mcp-client-${name}`,
|
||||
name: `nextchat-mcp-client-${id}`,
|
||||
version: "1.0.0",
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
// roots: {
|
||||
// listChanged: true,
|
||||
// },
|
||||
},
|
||||
capabilities: {},
|
||||
},
|
||||
);
|
||||
await client.connect(transport);
|
||||
return client;
|
||||
}
|
||||
|
||||
export interface Primitive {
|
||||
type: "resource" | "tool" | "prompt";
|
||||
value: any;
|
||||
export async function removeClient(client: Client) {
|
||||
logger.info(`Removing client...`);
|
||||
await client.close();
|
||||
}
|
||||
|
||||
/** List all resources, tools, and prompts */
|
||||
export async function listPrimitives(client: Client): Promise<Primitive[]> {
|
||||
const capabilities = client.getServerCapabilities();
|
||||
const primitives: Primitive[] = [];
|
||||
const promises = [];
|
||||
if (capabilities?.resources) {
|
||||
promises.push(
|
||||
client.listResources().then(({ resources }) => {
|
||||
resources.forEach((item) =>
|
||||
primitives.push({ type: "resource", value: item }),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (capabilities?.tools) {
|
||||
promises.push(
|
||||
client.listTools().then(({ tools }) => {
|
||||
tools.forEach((item) => primitives.push({ type: "tool", value: item }));
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (capabilities?.prompts) {
|
||||
promises.push(
|
||||
client.listPrompts().then(({ prompts }) => {
|
||||
prompts.forEach((item) =>
|
||||
primitives.push({ type: "prompt", value: item }),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
await Promise.all(promises);
|
||||
return primitives;
|
||||
export async function listTools(client: Client): Promise<ListToolsResponse> {
|
||||
return client.listTools();
|
||||
}
|
||||
|
||||
/** Execute a request */
|
||||
export async function executeRequest(
|
||||
client: Client,
|
||||
request: McpRequestMessage,
|
||||
|
@@ -1,27 +1,23 @@
|
||||
import { createClient, listPrimitives } from "@/app/mcp/client";
|
||||
import { createClient, listTools } from "@/app/mcp/client";
|
||||
import { MCPClientLogger } from "@/app/mcp/logger";
|
||||
import conf from "./mcp_config.json";
|
||||
|
||||
const logger = new MCPClientLogger("MCP Server Example", true);
|
||||
|
||||
const TEST_SERVER = "everything";
|
||||
const TEST_SERVER = "filesystem";
|
||||
|
||||
async function main() {
|
||||
logger.info(`All MCP servers: ${Object.keys(conf.mcpServers).join(", ")}`);
|
||||
|
||||
logger.info(`Connecting to server ${TEST_SERVER}...`);
|
||||
|
||||
const client = await createClient(conf.mcpServers[TEST_SERVER], TEST_SERVER);
|
||||
const primitives = await listPrimitives(client);
|
||||
const client = await createClient(TEST_SERVER, conf.mcpServers[TEST_SERVER]);
|
||||
const tools = await listTools(client);
|
||||
|
||||
logger.success(`Connected to server ${TEST_SERVER}`);
|
||||
|
||||
logger.info(
|
||||
`${TEST_SERVER} supported primitives:\n${JSON.stringify(
|
||||
primitives.filter((i) => i.type === "tool"),
|
||||
null,
|
||||
2,
|
||||
)}`,
|
||||
`${TEST_SERVER} supported primitives:\n${JSON.stringify(tools, null, 2)}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -1,3 +1,12 @@
|
||||
{
|
||||
"mcpServers": {}
|
||||
}
|
||||
"mcpServers": {
|
||||
"filesystem": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@modelcontextprotocol/server-filesystem",
|
||||
"."
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,7 +2,9 @@
|
||||
{
|
||||
"id": "filesystem",
|
||||
"name": "Filesystem",
|
||||
"description": "Secure file operations with configurable access controls",
|
||||
"description": "Secure file operations with configurable access controlsSecure file operations with configurable access controlsSecure file operations with configurable access controlsSecure file operations with configurable access controls",
|
||||
"repo": "https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem",
|
||||
"tags": ["filesystem", "storage", "local"],
|
||||
"command": "npx",
|
||||
"baseArgs": ["-y", "@modelcontextprotocol/server-filesystem"],
|
||||
"configurable": true,
|
||||
@@ -12,7 +14,9 @@
|
||||
"type": "array",
|
||||
"description": "Allowed file system paths",
|
||||
"required": true,
|
||||
"minItems": 1
|
||||
"minItems": 1,
|
||||
"itemLabel": "Path",
|
||||
"addButtonText": "Add Path"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -27,6 +31,8 @@
|
||||
"id": "github",
|
||||
"name": "GitHub",
|
||||
"description": "Repository management, file operations, and GitHub API integration",
|
||||
"repo": "https://github.com/modelcontextprotocol/servers/tree/main/src/github",
|
||||
"tags": ["github", "git", "api", "vcs"],
|
||||
"command": "npx",
|
||||
"baseArgs": ["-y", "@modelcontextprotocol/server-github"],
|
||||
"configurable": true,
|
||||
@@ -50,6 +56,8 @@
|
||||
"id": "gdrive",
|
||||
"name": "Google Drive",
|
||||
"description": "File access and search capabilities for Google Drive",
|
||||
"repo": "https://github.com/modelcontextprotocol/servers/tree/main/src/gdrive",
|
||||
"tags": ["google", "drive", "storage", "cloud"],
|
||||
"command": "npx",
|
||||
"baseArgs": ["-y", "@modelcontextprotocol/server-gdrive"],
|
||||
"configurable": false
|
||||
@@ -58,6 +66,8 @@
|
||||
"id": "playwright",
|
||||
"name": "Playwright",
|
||||
"description": "Browser automation and webscrapping with Playwright",
|
||||
"repo": "https://github.com/executeautomation/mcp-playwright",
|
||||
"tags": ["browser", "automation", "scraping"],
|
||||
"command": "npx",
|
||||
"baseArgs": ["-y", "@executeautomation/playwright-mcp-server"],
|
||||
"configurable": false
|
||||
@@ -66,6 +76,8 @@
|
||||
"id": "mongodb",
|
||||
"name": "MongoDB",
|
||||
"description": "Direct interaction with MongoDB databases",
|
||||
"repo": "",
|
||||
"tags": ["database", "mongodb", "nosql"],
|
||||
"command": "node",
|
||||
"baseArgs": ["dist/index.js"],
|
||||
"configurable": true,
|
||||
@@ -89,6 +101,8 @@
|
||||
"id": "difyworkflow",
|
||||
"name": "Dify Workflow",
|
||||
"description": "Tools to query and execute Dify workflows",
|
||||
"repo": "https://github.com/gotoolkits/mcp-difyworkflow-server",
|
||||
"tags": ["workflow", "automation", "dify"],
|
||||
"command": "mcp-difyworkflow-server",
|
||||
"baseArgs": ["-base-url"],
|
||||
"configurable": true,
|
||||
@@ -130,6 +144,8 @@
|
||||
"id": "postgres",
|
||||
"name": "PostgreSQL",
|
||||
"description": "Read-only database access with schema inspection",
|
||||
"repo": "https://github.com/modelcontextprotocol/servers/tree/main/src/postgres",
|
||||
"tags": ["database", "postgresql", "sql"],
|
||||
"command": "docker",
|
||||
"baseArgs": ["run", "-i", "--rm", "mcp/postgres"],
|
||||
"configurable": true,
|
||||
@@ -153,6 +169,8 @@
|
||||
"id": "brave-search",
|
||||
"name": "Brave Search",
|
||||
"description": "Web and local search using Brave's Search API",
|
||||
"repo": "https://github.com/modelcontextprotocol/servers/tree/main/src/brave-search",
|
||||
"tags": ["search", "brave", "api"],
|
||||
"command": "npx",
|
||||
"baseArgs": ["-y", "@modelcontextprotocol/server-brave-search"],
|
||||
"configurable": true,
|
||||
@@ -176,6 +194,8 @@
|
||||
"id": "google-maps",
|
||||
"name": "Google Maps",
|
||||
"description": "Location services, directions, and place details",
|
||||
"repo": "https://github.com/modelcontextprotocol/servers/tree/main/src/google-maps",
|
||||
"tags": ["maps", "google", "location", "api"],
|
||||
"command": "npx",
|
||||
"baseArgs": ["-y", "@modelcontextprotocol/server-google-maps"],
|
||||
"configurable": true,
|
||||
@@ -199,6 +219,8 @@
|
||||
"id": "docker-mcp",
|
||||
"name": "Docker",
|
||||
"description": "Run and manage docker containers, docker compose, and logs",
|
||||
"repo": "https://github.com/QuantGeekDev/docker-mcp",
|
||||
"tags": ["docker", "container", "devops"],
|
||||
"command": "uvx",
|
||||
"baseArgs": ["docker-mcp"],
|
||||
"configurable": false
|
||||
|
@@ -1,6 +1,7 @@
|
||||
// ref: https://spec.modelcontextprotocol.io/specification/basic/messages/
|
||||
|
||||
import { z } from "zod";
|
||||
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||
|
||||
export interface McpRequestMessage {
|
||||
jsonrpc?: "2.0";
|
||||
@@ -60,6 +61,32 @@ export const McpNotificationsSchema: z.ZodType<McpNotifications> = z.object({
|
||||
params: z.record(z.unknown()).optional(),
|
||||
});
|
||||
|
||||
////////////
|
||||
// Next Chat
|
||||
////////////
|
||||
export interface ListToolsResponse {
|
||||
tools: {
|
||||
name?: string;
|
||||
description?: string;
|
||||
inputSchema?: object;
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
export type McpClientData = McpActiveClient | McpErrorClient;
|
||||
|
||||
interface McpActiveClient {
|
||||
client: Client;
|
||||
tools: ListToolsResponse;
|
||||
errorMsg: null;
|
||||
}
|
||||
|
||||
interface McpErrorClient {
|
||||
client: null;
|
||||
tools: null;
|
||||
errorMsg: string;
|
||||
}
|
||||
|
||||
// MCP 服务器配置相关类型
|
||||
export interface ServerConfig {
|
||||
command: string;
|
||||
@@ -67,23 +94,52 @@ export interface ServerConfig {
|
||||
env?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface McpConfig {
|
||||
export interface McpConfigData {
|
||||
// MCP Server 的配置
|
||||
mcpServers: Record<string, ServerConfig>;
|
||||
}
|
||||
|
||||
export const DEFAULT_MCP_CONFIG: McpConfigData = {
|
||||
mcpServers: {},
|
||||
};
|
||||
|
||||
export interface ArgsMapping {
|
||||
// 参数映射的类型
|
||||
type: "spread" | "single" | "env";
|
||||
|
||||
// 参数映射的位置
|
||||
position?: number;
|
||||
|
||||
// 参数映射的 key
|
||||
key?: string;
|
||||
}
|
||||
|
||||
export interface PresetServer {
|
||||
// MCP Server 的唯一标识,作为最终配置文件 Json 的 key
|
||||
id: string;
|
||||
|
||||
// MCP Server 的显示名称
|
||||
name: string;
|
||||
|
||||
// MCP Server 的描述
|
||||
description: string;
|
||||
|
||||
// MCP Server 的仓库地址
|
||||
repo: string;
|
||||
|
||||
// MCP Server 的标签
|
||||
tags: string[];
|
||||
|
||||
// MCP Server 的命令
|
||||
command: string;
|
||||
|
||||
// MCP Server 的参数
|
||||
baseArgs: string[];
|
||||
|
||||
// MCP Server 是否需要配置
|
||||
configurable: boolean;
|
||||
|
||||
// MCP Server 的配置 schema
|
||||
configSchema?: {
|
||||
properties: Record<
|
||||
string,
|
||||
@@ -95,5 +151,7 @@ export interface PresetServer {
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
// MCP Server 的参数映射
|
||||
argsMapping?: Record<string, ArgsMapping>;
|
||||
}
|
||||
|
Reference in New Issue
Block a user