mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-05-19 12:10:17 +09:00
feat: add ENABLE_MCP env var to toggle MCP feature globally and in Docker
This commit is contained in:
parent
0112b54bc7
commit
bc71ae247b
@ -7,6 +7,11 @@ CODE=your-password
|
|||||||
# You can start service behind a proxy. (optional)
|
# You can start service behind a proxy. (optional)
|
||||||
PROXY_URL=http://localhost:7890
|
PROXY_URL=http://localhost:7890
|
||||||
|
|
||||||
|
# Enable MCP functionality (optional)
|
||||||
|
# Default: Empty (disabled)
|
||||||
|
# Set to "true" to enable MCP functionality
|
||||||
|
ENABLE_MCP=
|
||||||
|
|
||||||
# (optional)
|
# (optional)
|
||||||
# Default: Empty
|
# Default: Empty
|
||||||
# Google Gemini Pro API key, set if you want to use Google Gemini Pro API.
|
# Google Gemini Pro API key, set if you want to use Google Gemini Pro API.
|
||||||
|
@ -34,12 +34,16 @@ ENV PROXY_URL=""
|
|||||||
ENV OPENAI_API_KEY=""
|
ENV OPENAI_API_KEY=""
|
||||||
ENV GOOGLE_API_KEY=""
|
ENV GOOGLE_API_KEY=""
|
||||||
ENV CODE=""
|
ENV CODE=""
|
||||||
|
ENV ENABLE_MCP=""
|
||||||
|
|
||||||
COPY --from=builder /app/public ./public
|
COPY --from=builder /app/public ./public
|
||||||
COPY --from=builder /app/.next/standalone ./
|
COPY --from=builder /app/.next/standalone ./
|
||||||
COPY --from=builder /app/.next/static ./.next/static
|
COPY --from=builder /app/.next/static ./.next/static
|
||||||
COPY --from=builder /app/.next/server ./.next/server
|
COPY --from=builder /app/.next/server ./.next/server
|
||||||
|
|
||||||
|
RUN mkdir -p /app/app/mcp && chmod 777 /app/app/mcp
|
||||||
|
COPY --from=builder /app/app/mcp/mcp_config.json /app/app/mcp/
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
CMD if [ -n "$PROXY_URL" ]; then \
|
CMD if [ -n "$PROXY_URL" ]; then \
|
||||||
|
@ -122,7 +122,7 @@ import { isEmpty } from "lodash-es";
|
|||||||
import { getModelProvider } from "../utils/model";
|
import { getModelProvider } from "../utils/model";
|
||||||
import { RealtimeChat } from "@/app/components/realtime-chat";
|
import { RealtimeChat } from "@/app/components/realtime-chat";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { getAvailableClientsCount } from "../mcp/actions";
|
import { getAvailableClientsCount, isMcpEnabled } from "../mcp/actions";
|
||||||
|
|
||||||
const localStorage = safeLocalStorage();
|
const localStorage = safeLocalStorage();
|
||||||
|
|
||||||
@ -135,15 +135,22 @@ const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
|
|||||||
const MCPAction = () => {
|
const MCPAction = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [count, setCount] = useState<number>(0);
|
const [count, setCount] = useState<number>(0);
|
||||||
|
const [mcpEnabled, setMcpEnabled] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadCount = async () => {
|
const checkMcpStatus = async () => {
|
||||||
const count = await getAvailableClientsCount();
|
const enabled = await isMcpEnabled();
|
||||||
setCount(count);
|
setMcpEnabled(enabled);
|
||||||
|
if (enabled) {
|
||||||
|
const count = await getAvailableClientsCount();
|
||||||
|
setCount(count);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
loadCount();
|
checkMcpStatus();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
if (!mcpEnabled) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChatAction
|
<ChatAction
|
||||||
onClick={() => navigate(Path.McpMarket)}
|
onClick={() => navigate(Path.McpMarket)}
|
||||||
|
@ -29,8 +29,7 @@ import { getClientConfig } from "../config/client";
|
|||||||
import { type ClientApi, getClientApi } from "../client/api";
|
import { type ClientApi, getClientApi } from "../client/api";
|
||||||
import { useAccessStore } from "../store";
|
import { useAccessStore } from "../store";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { initializeMcpSystem } from "../mcp/actions";
|
import { initializeMcpSystem, isMcpEnabled } from "../mcp/actions";
|
||||||
import { showToast } from "./ui-lib";
|
|
||||||
|
|
||||||
export function Loading(props: { noLogo?: boolean }) {
|
export function Loading(props: { noLogo?: boolean }) {
|
||||||
return (
|
return (
|
||||||
@ -243,14 +242,20 @@ export function Home() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("[Config] got config from build time", getClientConfig());
|
console.log("[Config] got config from build time", getClientConfig());
|
||||||
useAccessStore.getState().fetch();
|
useAccessStore.getState().fetch();
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
const initMcp = async () => {
|
||||||
// 初始化 MCP 系统
|
try {
|
||||||
initializeMcpSystem().catch((error) => {
|
const enabled = await isMcpEnabled();
|
||||||
console.error("Failed to initialize MCP system:", error);
|
if (enabled) {
|
||||||
showToast("Failed to initialize MCP system");
|
console.log("[MCP] initializing...");
|
||||||
});
|
await initializeMcpSystem();
|
||||||
|
console.log("[MCP] initialized");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("[MCP] failed to initialize:", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
initMcp();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!useHasHydrated()) {
|
if (!useHasHydrated()) {
|
||||||
|
@ -16,8 +16,9 @@ import {
|
|||||||
getClientStatus,
|
getClientStatus,
|
||||||
getClientTools,
|
getClientTools,
|
||||||
getMcpConfigFromFile,
|
getMcpConfigFromFile,
|
||||||
restartAllClients,
|
isMcpEnabled,
|
||||||
pauseMcpServer,
|
pauseMcpServer,
|
||||||
|
restartAllClients,
|
||||||
resumeMcpServer,
|
resumeMcpServer,
|
||||||
} from "../mcp/actions";
|
} from "../mcp/actions";
|
||||||
import {
|
import {
|
||||||
@ -30,6 +31,7 @@ import {
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import PlayIcon from "../icons/play.svg";
|
import PlayIcon from "../icons/play.svg";
|
||||||
import StopIcon from "../icons/pause.svg";
|
import StopIcon from "../icons/pause.svg";
|
||||||
|
import { Path } from "../constant";
|
||||||
|
|
||||||
interface ConfigProperty {
|
interface ConfigProperty {
|
||||||
type: string;
|
type: string;
|
||||||
@ -40,6 +42,7 @@ interface ConfigProperty {
|
|||||||
|
|
||||||
export function McpMarketPage() {
|
export function McpMarketPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [mcpEnabled, setMcpEnabled] = useState(false);
|
||||||
const [searchText, setSearchText] = useState("");
|
const [searchText, setSearchText] = useState("");
|
||||||
const [userConfig, setUserConfig] = useState<Record<string, any>>({});
|
const [userConfig, setUserConfig] = useState<Record<string, any>>({});
|
||||||
const [editingServerId, setEditingServerId] = useState<string | undefined>();
|
const [editingServerId, setEditingServerId] = useState<string | undefined>();
|
||||||
@ -56,8 +59,22 @@ export function McpMarketPage() {
|
|||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 检查 MCP 是否启用
|
||||||
|
useEffect(() => {
|
||||||
|
const checkMcpStatus = async () => {
|
||||||
|
const enabled = await isMcpEnabled();
|
||||||
|
setMcpEnabled(enabled);
|
||||||
|
if (!enabled) {
|
||||||
|
navigate(Path.Home);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkMcpStatus();
|
||||||
|
}, [navigate]);
|
||||||
|
|
||||||
|
// 加载预设服务器
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadPresetServers = async () => {
|
const loadPresetServers = async () => {
|
||||||
|
if (!mcpEnabled) return;
|
||||||
try {
|
try {
|
||||||
setLoadingPresets(true);
|
setLoadingPresets(true);
|
||||||
const response = await fetch("https://nextchat.club/mcp/list");
|
const response = await fetch("https://nextchat.club/mcp/list");
|
||||||
@ -73,17 +90,13 @@ export function McpMarketPage() {
|
|||||||
setLoadingPresets(false);
|
setLoadingPresets(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
loadPresetServers().then();
|
loadPresetServers();
|
||||||
}, []);
|
}, [mcpEnabled]);
|
||||||
|
|
||||||
// 检查服务器是否已添加
|
// 加载初始状态
|
||||||
const isServerAdded = (id: string) => {
|
|
||||||
return id in (config?.mcpServers ?? {});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 从服务器获取初始状态
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadInitialState = async () => {
|
const loadInitialState = async () => {
|
||||||
|
if (!mcpEnabled) return;
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const config = await getMcpConfigFromFile();
|
const config = await getMcpConfigFromFile();
|
||||||
@ -103,42 +116,50 @@ export function McpMarketPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
loadInitialState();
|
loadInitialState();
|
||||||
}, []);
|
}, [mcpEnabled]);
|
||||||
|
|
||||||
// 加载当前编辑服务器的配置
|
// 加载当前编辑服务器的配置
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (editingServerId && config) {
|
if (!editingServerId || !config) return;
|
||||||
const currentConfig = config.mcpServers[editingServerId];
|
const currentConfig = config.mcpServers[editingServerId];
|
||||||
if (currentConfig) {
|
if (currentConfig) {
|
||||||
// 从当前配置中提取用户配置
|
// 从当前配置中提取用户配置
|
||||||
const preset = presetServers.find((s) => s.id === editingServerId);
|
const preset = presetServers.find((s) => s.id === editingServerId);
|
||||||
if (preset?.configSchema) {
|
if (preset?.configSchema) {
|
||||||
const userConfig: Record<string, any> = {};
|
const userConfig: Record<string, any> = {};
|
||||||
Object.entries(preset.argsMapping || {}).forEach(([key, mapping]) => {
|
Object.entries(preset.argsMapping || {}).forEach(([key, mapping]) => {
|
||||||
if (mapping.type === "spread") {
|
if (mapping.type === "spread") {
|
||||||
// 对于 spread 类型,从 args 中提取数组
|
// For spread types, extract the array from args.
|
||||||
const startPos = mapping.position ?? 0;
|
const startPos = mapping.position ?? 0;
|
||||||
userConfig[key] = currentConfig.args.slice(startPos);
|
userConfig[key] = currentConfig.args.slice(startPos);
|
||||||
} else if (mapping.type === "single") {
|
} else if (mapping.type === "single") {
|
||||||
// 对于 single 类型,获取单个值
|
// For single types, get a single value
|
||||||
userConfig[key] = currentConfig.args[mapping.position ?? 0];
|
userConfig[key] = currentConfig.args[mapping.position ?? 0];
|
||||||
} else if (
|
} else if (
|
||||||
mapping.type === "env" &&
|
mapping.type === "env" &&
|
||||||
mapping.key &&
|
mapping.key &&
|
||||||
currentConfig.env
|
currentConfig.env
|
||||||
) {
|
) {
|
||||||
// 对于 env 类型,从环境变量中获取值
|
// For env types, get values from environment variables
|
||||||
userConfig[key] = currentConfig.env[mapping.key];
|
userConfig[key] = currentConfig.env[mapping.key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setUserConfig(userConfig);
|
setUserConfig(userConfig);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setUserConfig({});
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setUserConfig({});
|
||||||
}
|
}
|
||||||
}, [editingServerId, config, presetServers]);
|
}, [editingServerId, config, presetServers]);
|
||||||
|
|
||||||
|
if (!mcpEnabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查服务器是否已添加
|
||||||
|
const isServerAdded = (id: string) => {
|
||||||
|
return id in (config?.mcpServers ?? {});
|
||||||
|
};
|
||||||
|
|
||||||
// 保存服务器配置
|
// 保存服务器配置
|
||||||
const saveServerConfig = async () => {
|
const saveServerConfig = async () => {
|
||||||
const preset = presetServers.find((s) => s.id === editingServerId);
|
const preset = presetServers.find((s) => s.id === editingServerId);
|
||||||
@ -291,8 +312,8 @@ export function McpMarketPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 修改恢复服务器函数
|
// Restart server
|
||||||
const resumeServer = async (id: string) => {
|
const restartServer = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
updateLoadingState(id, "Starting server...");
|
updateLoadingState(id, "Starting server...");
|
||||||
|
|
||||||
@ -320,7 +341,7 @@ export function McpMarketPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 修改重启所有客户端函数
|
// Restart all clients
|
||||||
const handleRestartAll = async () => {
|
const handleRestartAll = async () => {
|
||||||
try {
|
try {
|
||||||
updateLoadingState("all", "Restarting all servers...");
|
updateLoadingState("all", "Restarting all servers...");
|
||||||
@ -342,7 +363,7 @@ export function McpMarketPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 渲染配置表单
|
// Render configuration form
|
||||||
const renderConfigForm = () => {
|
const renderConfigForm = () => {
|
||||||
const preset = presetServers.find((s) => s.id === editingServerId);
|
const preset = presetServers.find((s) => s.id === editingServerId);
|
||||||
if (!preset?.configSchema) return null;
|
if (!preset?.configSchema) return null;
|
||||||
@ -422,12 +443,10 @@ export function McpMarketPage() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 检查服务器状态
|
|
||||||
const checkServerStatus = (clientId: string) => {
|
const checkServerStatus = (clientId: string) => {
|
||||||
return clientStatuses[clientId] || { status: "undefined", errorMsg: null };
|
return clientStatuses[clientId] || { status: "undefined", errorMsg: null };
|
||||||
};
|
};
|
||||||
|
|
||||||
// 修改状态显示逻辑
|
|
||||||
const getServerStatusDisplay = (clientId: string) => {
|
const getServerStatusDisplay = (clientId: string) => {
|
||||||
const status = checkServerStatus(clientId);
|
const status = checkServerStatus(clientId);
|
||||||
|
|
||||||
@ -450,7 +469,7 @@ export function McpMarketPage() {
|
|||||||
return statusMap[status.status];
|
return statusMap[status.status];
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取操作状态的类型
|
// Get the type of operation status
|
||||||
const getOperationStatusType = (message: string) => {
|
const getOperationStatusType = (message: string) => {
|
||||||
if (message.toLowerCase().includes("stopping")) return "stopping";
|
if (message.toLowerCase().includes("stopping")) return "stopping";
|
||||||
if (message.toLowerCase().includes("starting")) return "starting";
|
if (message.toLowerCase().includes("starting")) return "starting";
|
||||||
@ -496,15 +515,15 @@ export function McpMarketPage() {
|
|||||||
|
|
||||||
// 定义状态优先级
|
// 定义状态优先级
|
||||||
const statusPriority: Record<string, number> = {
|
const statusPriority: Record<string, number> = {
|
||||||
error: 0, // 错误状态最高优先级
|
error: 0, // Highest priority for error status
|
||||||
active: 1, // 已启动次之
|
active: 1, // Second for active
|
||||||
starting: 2, // 正在启动
|
starting: 2, // Starting
|
||||||
stopping: 3, // 正在停止
|
stopping: 3, // Stopping
|
||||||
paused: 4, // 已暂停
|
paused: 4, // Paused
|
||||||
undefined: 5, // 未配置最低优先级
|
undefined: 5, // Lowest priority for undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取实际状态(包括加载状态)
|
// Get actual status (including loading status)
|
||||||
const getEffectiveStatus = (status: string, loading?: string) => {
|
const getEffectiveStatus = (status: string, loading?: string) => {
|
||||||
if (loading) {
|
if (loading) {
|
||||||
const operationType = getOperationStatusType(loading);
|
const operationType = getOperationStatusType(loading);
|
||||||
@ -524,7 +543,7 @@ export function McpMarketPage() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 状态相同时按名称排序
|
// Sort by name when statuses are the same
|
||||||
return a.name.localeCompare(b.name);
|
return a.name.localeCompare(b.name);
|
||||||
})
|
})
|
||||||
.map((server) => (
|
.map((server) => (
|
||||||
@ -591,7 +610,7 @@ export function McpMarketPage() {
|
|||||||
<IconButton
|
<IconButton
|
||||||
icon={<PlayIcon />}
|
icon={<PlayIcon />}
|
||||||
text="Start"
|
text="Start"
|
||||||
onClick={() => resumeServer(server.id)}
|
onClick={() => restartServer(server.id)}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
{/* <IconButton
|
{/* <IconButton
|
||||||
@ -720,7 +739,6 @@ export function McpMarketPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/*支持的Tools*/}
|
|
||||||
{viewingServerId && (
|
{viewingServerId && (
|
||||||
<div className="modal-mask">
|
<div className="modal-mask">
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useMemo, useState, Fragment } from "react";
|
import React, { Fragment, useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
|
||||||
import styles from "./home.module.scss";
|
import styles from "./home.module.scss";
|
||||||
|
|
||||||
@ -30,8 +30,9 @@ import {
|
|||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import { isIOS, useMobileScreen } from "../utils";
|
import { isIOS, useMobileScreen } from "../utils";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import { showConfirm, Selector } from "./ui-lib";
|
import { Selector, showConfirm } from "./ui-lib";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
import { isMcpEnabled } from "../mcp/actions";
|
||||||
|
|
||||||
const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, {
|
const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, {
|
||||||
loading: () => null,
|
loading: () => null,
|
||||||
@ -129,6 +130,7 @@ export function useDragSideBar() {
|
|||||||
shouldNarrow,
|
shouldNarrow,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SideBarContainer(props: {
|
export function SideBarContainer(props: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
onDragStart: (e: MouseEvent) => void;
|
onDragStart: (e: MouseEvent) => void;
|
||||||
@ -224,6 +226,17 @@ export function SideBar(props: { className?: string }) {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const config = useAppConfig();
|
const config = useAppConfig();
|
||||||
const chatStore = useChatStore();
|
const chatStore = useChatStore();
|
||||||
|
const [mcpEnabled, setMcpEnabled] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// 检查 MCP 是否启用
|
||||||
|
const checkMcpStatus = async () => {
|
||||||
|
const enabled = await isMcpEnabled();
|
||||||
|
setMcpEnabled(enabled);
|
||||||
|
console.log("[SideBar] MCP enabled:", enabled);
|
||||||
|
};
|
||||||
|
checkMcpStatus();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SideBarContainer
|
<SideBarContainer
|
||||||
@ -251,15 +264,17 @@ export function SideBar(props: { className?: string }) {
|
|||||||
}}
|
}}
|
||||||
shadow
|
shadow
|
||||||
/>
|
/>
|
||||||
<IconButton
|
{mcpEnabled && (
|
||||||
icon={<McpIcon />}
|
<IconButton
|
||||||
text={shouldNarrow ? undefined : Locale.Mcp.Name}
|
icon={<McpIcon />}
|
||||||
className={styles["sidebar-bar-button"]}
|
text={shouldNarrow ? undefined : Locale.Mcp.Name}
|
||||||
onClick={() => {
|
className={styles["sidebar-bar-button"]}
|
||||||
navigate(Path.McpMarket, { state: { fromHome: true } });
|
onClick={() => {
|
||||||
}}
|
navigate(Path.McpMarket, { state: { fromHome: true } });
|
||||||
shadow
|
}}
|
||||||
/>
|
shadow
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={<DiscoveryIcon />}
|
icon={<DiscoveryIcon />}
|
||||||
text={shouldNarrow ? undefined : Locale.Discovery.Name}
|
text={shouldNarrow ? undefined : Locale.Discovery.Name}
|
||||||
|
@ -81,6 +81,8 @@ declare global {
|
|||||||
|
|
||||||
// custom template for preprocessing user input
|
// custom template for preprocessing user input
|
||||||
DEFAULT_INPUT_TEMPLATE?: string;
|
DEFAULT_INPUT_TEMPLATE?: string;
|
||||||
|
|
||||||
|
ENABLE_MCP?: string; // enable mcp functionality
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,7 +131,9 @@ export const getServerSideConfig = () => {
|
|||||||
if (customModels) customModels += ",";
|
if (customModels) customModels += ",";
|
||||||
customModels += DEFAULT_MODELS.filter(
|
customModels += DEFAULT_MODELS.filter(
|
||||||
(m) =>
|
(m) =>
|
||||||
(m.name.startsWith("gpt-4") || m.name.startsWith("chatgpt-4o") || m.name.startsWith("o1")) &&
|
(m.name.startsWith("gpt-4") ||
|
||||||
|
m.name.startsWith("chatgpt-4o") ||
|
||||||
|
m.name.startsWith("o1")) &&
|
||||||
!m.name.startsWith("gpt-4o-mini"),
|
!m.name.startsWith("gpt-4o-mini"),
|
||||||
)
|
)
|
||||||
.map((m) => "-" + m.name)
|
.map((m) => "-" + m.name)
|
||||||
@ -249,5 +253,6 @@ export const getServerSideConfig = () => {
|
|||||||
customModels,
|
customModels,
|
||||||
defaultModel,
|
defaultModel,
|
||||||
allowedWebDavEndpoints,
|
allowedWebDavEndpoints,
|
||||||
|
enableMcp: !!process.env.ENABLE_MCP,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -5,9 +5,8 @@ import "./styles/highlight.scss";
|
|||||||
import { getClientConfig } from "./config/client";
|
import { getClientConfig } from "./config/client";
|
||||||
import type { Metadata, Viewport } from "next";
|
import type { Metadata, Viewport } from "next";
|
||||||
import { SpeedInsights } from "@vercel/speed-insights/next";
|
import { SpeedInsights } from "@vercel/speed-insights/next";
|
||||||
import { getServerSideConfig } from "./config/server";
|
|
||||||
import { GoogleTagManager, GoogleAnalytics } from "@next/third-parties/google";
|
import { GoogleTagManager, GoogleAnalytics } from "@next/third-parties/google";
|
||||||
const serverConfig = getServerSideConfig();
|
import { getServerSideConfig } from "./config/server";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "NextChat",
|
title: "NextChat",
|
||||||
@ -33,6 +32,8 @@ export default function RootLayout({
|
|||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
|
const serverConfig = getServerSideConfig();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
} from "./types";
|
} from "./types";
|
||||||
import fs from "fs/promises";
|
import fs from "fs/promises";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
import { getServerSideConfig } from "../config/server";
|
||||||
|
|
||||||
const logger = new MCPClientLogger("MCP Actions");
|
const logger = new MCPClientLogger("MCP Actions");
|
||||||
const CONFIG_PATH = path.join(process.cwd(), "app/mcp/mcp_config.json");
|
const CONFIG_PATH = path.join(process.cwd(), "app/mcp/mcp_config.json");
|
||||||
@ -117,6 +118,12 @@ async function initializeSingleClient(
|
|||||||
export async function initializeMcpSystem() {
|
export async function initializeMcpSystem() {
|
||||||
logger.info("MCP Actions starting...");
|
logger.info("MCP Actions starting...");
|
||||||
try {
|
try {
|
||||||
|
// 检查是否已有活跃的客户端
|
||||||
|
if (clientsMap.size > 0) {
|
||||||
|
logger.info("MCP system already initialized, skipping...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const config = await getMcpConfigFromFile();
|
const config = await getMcpConfigFromFile();
|
||||||
// 初始化所有客户端
|
// 初始化所有客户端
|
||||||
for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) {
|
for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) {
|
||||||
@ -352,3 +359,14 @@ export async function reinitializeClient(clientId: string) {
|
|||||||
}
|
}
|
||||||
await initializeSingleClient(clientId, serverConfig);
|
await initializeSingleClient(clientId, serverConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查 MCP 是否启用
|
||||||
|
export async function isMcpEnabled() {
|
||||||
|
try {
|
||||||
|
const serverConfig = getServerSideConfig();
|
||||||
|
return !!serverConfig.enableMcp;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`Failed to check MCP status: ${error}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
import { Analytics } from "@vercel/analytics/react";
|
import { Analytics } from "@vercel/analytics/react";
|
||||||
import { Home } from "./components/home";
|
import { Home } from "./components/home";
|
||||||
import { getServerSideConfig } from "./config/server";
|
import { getServerSideConfig } from "./config/server";
|
||||||
import { initializeMcpSystem } from "./mcp/actions";
|
|
||||||
|
|
||||||
const serverConfig = getServerSideConfig();
|
const serverConfig = getServerSideConfig();
|
||||||
|
|
||||||
export default async function App() {
|
export default async function App() {
|
||||||
// 初始化 MCP 系统
|
|
||||||
await initializeMcpSystem();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Home />
|
<Home />
|
||||||
|
Loading…
Reference in New Issue
Block a user