mirror of
https://github.com/ILoveBingLu/CipherTalk.git
synced 2026-05-23 13:01:41 +08:00
Add embedded MCP server with shared API facade
This commit is contained in:
@@ -111,6 +111,10 @@ interface AISummarySettingsProps {
|
||||
setEnableThinking: (val: boolean) => void
|
||||
messageLimit: number
|
||||
setMessageLimit: (val: number) => void
|
||||
mcpEnabled: boolean
|
||||
setMcpEnabled: (val: boolean) => void
|
||||
mcpExposeMediaPaths: boolean
|
||||
setMcpExposeMediaPaths: (val: boolean) => void
|
||||
showMessage: (text: string, success: boolean) => void
|
||||
}
|
||||
|
||||
@@ -133,6 +137,10 @@ function AISummarySettings({
|
||||
setEnableThinking,
|
||||
messageLimit,
|
||||
setMessageLimit,
|
||||
mcpEnabled,
|
||||
setMcpEnabled,
|
||||
mcpExposeMediaPaths,
|
||||
setMcpExposeMediaPaths,
|
||||
showMessage
|
||||
}: AISummarySettingsProps) {
|
||||
const [showApiKey, setShowApiKey] = useState(false)
|
||||
@@ -750,6 +758,55 @@ function AISummarySettings({
|
||||
</>
|
||||
)}
|
||||
|
||||
<h3 className="section-title">MCP Server</h3>
|
||||
<div className="settings-form" style={{ marginTop: '8px' }}>
|
||||
<div className="form-group">
|
||||
<label className="toggle-label">
|
||||
<div className="toggle-header">
|
||||
<span className="toggle-title">启用内嵌 MCP Server</span>
|
||||
<span className="toggle-switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={mcpEnabled}
|
||||
onChange={(e) => setMcpEnabled(e.target.checked)}
|
||||
/>
|
||||
<span className="toggle-slider"></span>
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
<div className="toggle-description">
|
||||
<p>为 Claude Desktop、Codex、Cherry Studio 等 MCP 宿主暴露 CipherTalk 数据读取能力。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label className="toggle-label">
|
||||
<div className="toggle-header">
|
||||
<span className="toggle-title">默认暴露媒体本地路径</span>
|
||||
<span className="toggle-switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={mcpExposeMediaPaths}
|
||||
onChange={(e) => setMcpExposeMediaPaths(e.target.checked)}
|
||||
/>
|
||||
<span className="toggle-slider"></span>
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
<div className="toggle-description">
|
||||
<p>控制 MCP `get_messages` 默认是否解析并返回图片、视频、文件等本地路径。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label>启动命令</label>
|
||||
<input className="api-key-input" type="text" value="npm run build:mcp && node scripts/mcp-runner.js" readOnly />
|
||||
<div className="form-hint">
|
||||
首批工具:`health_check`、`get_status`、`list_sessions`、`get_messages`、`list_contacts`
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="info-box-simple">
|
||||
<p>💡 提示:API 密钥存储在本地,不会上传到任何服务器。摘要内容仅用于本地展示。</p>
|
||||
</div>
|
||||
|
||||
@@ -140,6 +140,8 @@ function SettingsPage() {
|
||||
const [aiCustomSystemPrompt, setAiCustomSystemPromptState] = useState<string>('')
|
||||
const [aiEnableThinking, setAiEnableThinkingState] = useState<boolean>(true)
|
||||
const [aiMessageLimit, setAiMessageLimitState] = useState<number>(3000)
|
||||
const [mcpEnabled, setMcpEnabledState] = useState<boolean>(false)
|
||||
const [mcpExposeMediaPaths, setMcpExposeMediaPathsState] = useState<boolean>(true)
|
||||
|
||||
// 日志相关状态
|
||||
const [logFiles, setLogFiles] = useState<Array<{ name: string; size: number; mtime: Date }>>([])
|
||||
@@ -219,6 +221,8 @@ function SettingsPage() {
|
||||
const savedAiCustomSystemPrompt = await configService.getAiCustomSystemPrompt()
|
||||
const savedAiEnableThinking = await configService.getAiEnableThinking()
|
||||
const savedAiMessageLimit = await configService.getAiMessageLimit()
|
||||
const savedMcpEnabled = await configService.getMcpEnabled()
|
||||
const savedMcpExposeMediaPaths = await configService.getMcpExposeMediaPaths()
|
||||
|
||||
setAiProviderState(savedAiProvider)
|
||||
setAiApiKeyState(savedAiApiKey)
|
||||
@@ -229,6 +233,8 @@ function SettingsPage() {
|
||||
setAiCustomSystemPromptState(savedAiCustomSystemPrompt)
|
||||
setAiEnableThinkingState(savedAiEnableThinking)
|
||||
setAiMessageLimitState(savedAiMessageLimit)
|
||||
setMcpEnabledState(savedMcpEnabled)
|
||||
setMcpExposeMediaPathsState(savedMcpExposeMediaPaths)
|
||||
|
||||
// 加载关闭行为配置
|
||||
const savedCloseToTray = await configService.getCloseToTray()
|
||||
@@ -262,6 +268,8 @@ function SettingsPage() {
|
||||
aiCustomSystemPrompt: savedAiCustomSystemPrompt,
|
||||
aiEnableThinking: savedAiEnableThinking,
|
||||
aiMessageLimit: savedAiMessageLimit,
|
||||
mcpEnabled: savedMcpEnabled,
|
||||
mcpExposeMediaPaths: savedMcpExposeMediaPaths,
|
||||
closeToTray: savedCloseToTray
|
||||
})
|
||||
|
||||
@@ -310,6 +318,8 @@ function SettingsPage() {
|
||||
aiCustomSystemPrompt,
|
||||
aiEnableThinking,
|
||||
aiMessageLimit,
|
||||
mcpEnabled,
|
||||
mcpExposeMediaPaths,
|
||||
closeToTray
|
||||
}
|
||||
|
||||
@@ -323,6 +333,7 @@ function SettingsPage() {
|
||||
quoteStyle, exportDefaultDateRange, exportDefaultAvatars,
|
||||
aiProvider, aiApiKey, aiModel, aiDefaultTimeRange, aiSummaryDetail,
|
||||
aiSystemPromptPreset, aiCustomSystemPrompt, aiEnableThinking, aiMessageLimit,
|
||||
mcpEnabled, mcpExposeMediaPaths,
|
||||
closeToTray, initialConfig
|
||||
])
|
||||
|
||||
@@ -848,6 +859,8 @@ function SettingsPage() {
|
||||
await configService.setAiCustomSystemPrompt(aiCustomSystemPrompt)
|
||||
await configService.setAiEnableThinking(aiEnableThinking)
|
||||
await configService.setAiMessageLimit(aiMessageLimit)
|
||||
await configService.setMcpEnabled(mcpEnabled)
|
||||
await configService.setMcpExposeMediaPaths(mcpExposeMediaPaths)
|
||||
|
||||
// 保存关闭行为配置
|
||||
await configService.setCloseToTray(closeToTray)
|
||||
@@ -887,6 +900,8 @@ function SettingsPage() {
|
||||
aiCustomSystemPrompt,
|
||||
aiEnableThinking,
|
||||
aiMessageLimit,
|
||||
mcpEnabled,
|
||||
mcpExposeMediaPaths,
|
||||
closeToTray
|
||||
})
|
||||
setHasUnsavedChanges(false)
|
||||
@@ -2787,6 +2802,10 @@ function SettingsPage() {
|
||||
setEnableThinking={setAiEnableThinkingState}
|
||||
messageLimit={aiMessageLimit}
|
||||
setMessageLimit={setAiMessageLimitState}
|
||||
mcpEnabled={mcpEnabled}
|
||||
setMcpEnabled={setMcpEnabledState}
|
||||
mcpExposeMediaPaths={mcpExposeMediaPaths}
|
||||
setMcpExposeMediaPaths={setMcpExposeMediaPathsState}
|
||||
showMessage={showMessage}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -28,6 +28,8 @@ export const CONFIG_KEYS = {
|
||||
HTTP_API_ENABLED: 'httpApiEnabled',
|
||||
HTTP_API_PORT: 'httpApiPort',
|
||||
HTTP_API_TOKEN: 'httpApiToken',
|
||||
MCP_ENABLED: 'mcpEnabled',
|
||||
MCP_EXPOSE_MEDIA_PATHS: 'mcpExposeMediaPaths',
|
||||
AUTH_ENABLED: 'authEnabled',
|
||||
AUTH_CREDENTIAL_ID: 'authCredentialId',
|
||||
AUTH_PASSWORD_HASH: 'authPasswordHash',
|
||||
@@ -509,6 +511,26 @@ export async function setAiMessageLimit(limit: number): Promise<void> {
|
||||
await config.set('aiMessageLimit', limit)
|
||||
}
|
||||
|
||||
// --- MCP 配置 ---
|
||||
|
||||
export async function getMcpEnabled(): Promise<boolean> {
|
||||
const value = await config.get(CONFIG_KEYS.MCP_ENABLED)
|
||||
return value !== undefined ? (value as boolean) : false
|
||||
}
|
||||
|
||||
export async function setMcpEnabled(enabled: boolean): Promise<void> {
|
||||
await config.set(CONFIG_KEYS.MCP_ENABLED, enabled)
|
||||
}
|
||||
|
||||
export async function getMcpExposeMediaPaths(): Promise<boolean> {
|
||||
const value = await config.get(CONFIG_KEYS.MCP_EXPOSE_MEDIA_PATHS)
|
||||
return value !== undefined ? (value as boolean) : true
|
||||
}
|
||||
|
||||
export async function setMcpExposeMediaPaths(enabled: boolean): Promise<void> {
|
||||
await config.set(CONFIG_KEYS.MCP_EXPOSE_MEDIA_PATHS, enabled)
|
||||
}
|
||||
|
||||
// --- AI 配置预设 ---
|
||||
|
||||
export interface AiConfigPreset {
|
||||
|
||||
Reference in New Issue
Block a user