feat: 新增 CipherTalk MCP 服务

This commit is contained in:
ILoveBingLu
2026-04-01 19:41:54 +08:00
parent 2ca9f08ea5
commit f5ca04ad51
23 changed files with 1543 additions and 286 deletions
+66
View File
@@ -0,0 +1,66 @@
"use strict";
const os = require("os");
const path = require("path");
const Module = require("module");
const appDir = path.dirname(process.execPath);
const appAsarPath = path.join(appDir, "resources", "app.asar");
function getUserDataPath() {
const appData = process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming");
return path.join(appData, "ciphertalk");
}
function getDocumentsPath() {
return path.join(os.homedir(), "Documents");
}
const electronShim = {
app: {
isPackaged: true,
getPath(name) {
switch (name) {
case "userData":
return getUserDataPath();
case "documents":
return getDocumentsPath();
case "exe":
return process.execPath;
default:
return appDir;
}
},
getAppPath() {
return appAsarPath;
},
getVersion() {
try {
return require(path.join(appAsarPath, "package.json")).version || "0.0.0";
} catch {
return "0.0.0";
}
},
},
BrowserWindow: {
getAllWindows() {
return [];
},
},
};
const originalLoad = Module._load;
Module._load = function patchedLoad(request, parent, isMain) {
if (request === "electron") {
return electronShim;
}
return originalLoad.call(this, request, parent, isMain);
};
const entry = String(process.env.CIPHERTALK_MCP_ENTRY || "").trim();
if (!entry) {
process.stderr.write("[CipherTalk MCP Bootstrap] CIPHERTALK_MCP_ENTRY is not set\n");
process.exit(1);
}
require(entry);
+32
View File
@@ -0,0 +1,32 @@
@echo off
setlocal
set "APP_DIR=%~dp0"
set "EXE_PATH=%APP_DIR%CipherTalk.exe"
set "MCP_ARCHIVE=%APP_DIR%resources\app.asar"
set "MCP_ENTRY_UNPACKED=%APP_DIR%resources\app.asar.unpacked\dist-electron\mcp.js"
set "MCP_ENTRY=%MCP_ARCHIVE%\dist-electron\mcp.js"
set "MCP_BOOTSTRAP=%APP_DIR%ciphertalk-mcp-bootstrap.cjs"
if not exist "%EXE_PATH%" (
>&2 echo [CipherTalk MCP Launcher] CipherTalk.exe not found at "%EXE_PATH%"
exit /b 1
)
if not exist "%MCP_BOOTSTRAP%" (
>&2 echo [CipherTalk MCP Launcher] MCP bootstrap not found at "%MCP_BOOTSTRAP%"
exit /b 1
)
if exist "%MCP_ENTRY_UNPACKED%" (
set "MCP_ENTRY=%MCP_ENTRY_UNPACKED%"
) else if not exist "%MCP_ARCHIVE%" (
>&2 echo [CipherTalk MCP Launcher] app.asar not found at "%MCP_ARCHIVE%"
exit /b 1
)
set "ELECTRON_RUN_AS_NODE=1"
set "CIPHERTALK_MCP_LAUNCHER=packaged-launcher"
set "CIPHERTALK_MCP_ENTRY=%MCP_ENTRY%"
"%EXE_PATH%" "%MCP_BOOTSTRAP%" %*
+53
View File
@@ -0,0 +1,53 @@
const path = require('path')
async function main() {
const { Client } = await import('@modelcontextprotocol/sdk/client/index.js')
const { StdioClientTransport } = await import('@modelcontextprotocol/sdk/client/stdio.js')
const mode = process.argv[2] || 'dev'
const cwd = process.cwd()
let command
let args
let transportCwd = cwd
if (mode === 'packaged') {
const launcherPath = process.argv[3] || path.join(cwd, 'ciphertalk-mcp.cmd')
command = launcherPath
args = []
transportCwd = path.dirname(launcherPath)
} else {
command = process.platform === 'win32' ? 'npm.cmd' : 'npm'
args = ['run', 'mcp']
}
const transport = new StdioClientTransport({
command,
args,
cwd: transportCwd,
stderr: 'pipe'
})
const client = new Client({
name: 'ciphertalk-mcp-probe',
version: '1.0.0'
})
try {
await client.connect(transport)
const tools = await client.listTools()
const health = await client.callTool({ name: 'health_check', arguments: {} })
console.log(JSON.stringify({
mode,
tools: (tools.tools || []).map((tool) => tool.name),
health
}, null, 2))
} finally {
await client.close()
}
}
main().catch((error) => {
console.error('[CipherTalk MCP Probe] failed:', error)
process.exit(1)
})
+20 -1
View File
@@ -1,15 +1,34 @@
const { spawn } = require('child_process')
const { spawnSync } = require('child_process')
const fs = require('fs')
const path = require('path')
const electronBinary = require('electron')
const rootDir = path.resolve(__dirname, '..')
const entry = path.join(rootDir, 'dist-electron', 'mcp.js')
if (!fs.existsSync(entry)) {
process.stderr.write('[CipherTalk MCP Runner] dist-electron/mcp.js not found, running build:mcp...\n')
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'
const build = spawnSync(npmCmd, ['run', 'build:mcp'], {
cwd: rootDir,
env: process.env,
stdio: 'inherit',
windowsHide: true
})
if (build.status !== 0 || !fs.existsSync(entry)) {
process.stderr.write('[CipherTalk MCP Runner] build:mcp failed, cannot start MCP server\n')
process.exit(build.status ?? 1)
}
}
const child = spawn(electronBinary, [entry], {
cwd: rootDir,
env: {
...process.env,
ELECTRON_RUN_AS_NODE: '1'
ELECTRON_RUN_AS_NODE: '1',
CIPHERTALK_MCP_LAUNCHER: 'dev-runner'
},
stdio: ['pipe', 'pipe', 'pipe'],
windowsHide: true