Skip to content

Commit 4e157b9

Browse files
authored
feat(cloud-mode): add cloud mode support for MCP server 🚀 (#137)
* feat(cloud-mode): add cloud mode support for MCP server 🚀 - Add cloud mode detection and management utilities - Implement authentication state construction from environment variables - Add CLI parameter --cloud-mode support (Node.js 18.15+ compatible) - Filter incompatible plugins (interactive, setup) in cloud mode - Skip local file operations when environment variables are present - Add comprehensive tests and documentation - Fix type compatibility issues with authentication state changes Resolves cross-process cache pollution and tool filtering for cloud deployment * feat(cloud-mode): enhance tool-level conditional registration 🛠️ - Add shouldRegisterTool() and conditionalRegisterTool() functions - Implement dynamic tool filtering based on cloud mode - Filter cloud-incompatible tools: uploadFile, uploadFiles, updateFunctionCode, createFunction, downloadTemplate, downloadRemoteFile, interactiveDialog - Update all tool registration to use conditional registration - Maintain backward compatibility for local mode - Add comprehensive tool filtering mechanism documentation Resolves tool compatibility issues for cloud deployment environments
1 parent 1930e51 commit 4e157b9

9 files changed

Lines changed: 321 additions & 12 deletions

File tree

mcp/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ export type {
2727

2828
export { getLoginState, logout } from "./auth.js";
2929

30+
export { isCloudMode, enableCloudMode, getCloudModeStatus, shouldRegisterTool, conditionalRegisterTool } from "./utils/cloud-mode.js";
31+
3032
export {
3133
getCloudBaseManager,
3234
getEnvId,

mcp/src/tools/download.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as https from "https";
88
import * as http from "http";
99
import { URL } from "url";
1010
import * as net from "net";
11+
import { conditionalRegisterTool } from '../utils/cloud-mode.js';
1112
import * as dns from "dns";
1213
import { getCloudBaseManager } from '../cloudbase-manager.js'
1314
import { ExtendedMcpServer } from '../server.js';
@@ -243,7 +244,9 @@ function downloadFile(url: string): Promise<{
243244
}
244245

245246
export function registerDownloadTools(server: ExtendedMcpServer) {
246-
server.registerTool?.(
247+
// downloadRemoteFile - 下载远程文件 (cloud-incompatible)
248+
conditionalRegisterTool(
249+
server,
247250
"downloadRemoteFile",
248251
{
249252
title: "下载远程文件",

mcp/src/tools/functions.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { z } from "zod";
22
import { getCloudBaseManager } from '../cloudbase-manager.js'
33
import { ExtendedMcpServer } from '../server.js';
4+
import { conditionalRegisterTool } from '../utils/cloud-mode.js';
45
import path from 'path';
56

67
// 支持的 Node.js 运行时列表
@@ -94,8 +95,9 @@ export function registerFunctionTools(server: ExtendedMcpServer) {
9495
}
9596
);
9697

97-
// createFunction - 创建云函数
98-
server.registerTool?.(
98+
// createFunction - 创建云函数 (cloud-incompatible)
99+
conditionalRegisterTool(
100+
server,
99101
"createFunction",
100102
{
101103
title: "创建云函数",
@@ -182,8 +184,9 @@ export function registerFunctionTools(server: ExtendedMcpServer) {
182184
}
183185
);
184186

185-
// updateFunctionCode - 更新函数代码
186-
server.registerTool?.(
187+
// updateFunctionCode - 更新函数代码 (cloud-incompatible)
188+
conditionalRegisterTool(
189+
server,
187190
"updateFunctionCode",
188191
{
189192
title: "更新云函数代码",

mcp/src/tools/hosting.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { z } from "zod";
22
import { getCloudBaseManager } from '../cloudbase-manager.js'
33
import { ExtendedMcpServer } from '../server.js';
4+
import { conditionalRegisterTool } from '../utils/cloud-mode.js';
45

56
// 定义扩展的EnvInfo接口,包含StaticStorages属性
67
interface ExtendedEnvInfo {
@@ -21,8 +22,9 @@ export function registerHostingTools(server: ExtendedMcpServer) {
2122
// 创建闭包函数来获取 CloudBase Manager
2223
const getManager = () => getCloudBaseManager({ cloudBaseOptions });
2324

24-
// uploadFiles - 上传文件到静态网站托管
25-
server.registerTool?.(
25+
// uploadFiles - 上传文件到静态网站托管 (cloud-incompatible)
26+
conditionalRegisterTool(
27+
server,
2628
"uploadFiles",
2729
{
2830
title: "上传静态文件",

mcp/src/tools/interactive.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ import fs from 'fs/promises';
77
import path from 'path';
88
import os from 'os';
99
import { ExtendedMcpServer } from '../server.js';
10+
import { conditionalRegisterTool } from '../utils/cloud-mode.js';
1011

1112
export function registerInteractiveTools(server: ExtendedMcpServer) {
12-
// 统一的交互式对话工具
13-
server.registerTool?.(
13+
// 统一的交互式对话工具 (cloud-incompatible)
14+
conditionalRegisterTool(
15+
server,
1416
"interactiveDialog",
1517
{
1618
title: "交互式对话",

mcp/src/tools/setup.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as http from "http";
88
import { execSync } from "child_process";
99
import AdmZip from "adm-zip";
1010
import { ExtendedMcpServer } from '../server.js';
11+
import { conditionalRegisterTool } from '../utils/cloud-mode.js';
1112

1213
// 构建时注入的版本号
1314
// @ts-ignore
@@ -313,7 +314,9 @@ function filterFilesByIDE(files: string[], ide: string): string[] {
313314
}
314315

315316
export function registerSetupTools(server: ExtendedMcpServer) {
316-
server.registerTool?.(
317+
// downloadTemplate - 下载项目模板 (cloud-incompatible)
318+
conditionalRegisterTool(
319+
server,
317320
"downloadTemplate",
318321
{
319322
title: "下载项目模板",

mcp/src/tools/storage.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { z } from "zod";
22
import { getCloudBaseManager } from '../cloudbase-manager.js'
33
import { ExtendedMcpServer } from '../server.js';
4+
import { conditionalRegisterTool } from '../utils/cloud-mode.js';
45

56
export function registerStorageTools(server: ExtendedMcpServer) {
67
// 获取 cloudBaseOptions,如果没有则为 undefined
@@ -9,8 +10,9 @@ export function registerStorageTools(server: ExtendedMcpServer) {
910
// 创建闭包函数来获取 CloudBase Manager
1011
const getManager = () => getCloudBaseManager({ cloudBaseOptions });
1112

12-
// uploadFile - 上传文件到云存储
13-
server.registerTool?.(
13+
// uploadFile - 上传文件到云存储 (cloud-incompatible)
14+
conditionalRegisterTool(
15+
server,
1416
"uploadFile",
1517
{
1618
title: "上传文件到云存储",

mcp/src/utils/cloud-mode.ts

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { debug } from './logger.js';
2+
3+
/**
4+
* Check if MCP is running in cloud mode
5+
* Cloud mode is enabled by:
6+
* 1. Command line argument --cloud-mode
7+
* 2. Environment variable CLOUDBASE_MCP_CLOUD_MODE=true
8+
* 3. Environment variable MCP_CLOUD_MODE=true
9+
*/
10+
export function isCloudMode(): boolean {
11+
const cloudModeEnabled = process.env.CLOUDBASE_MCP_CLOUD_MODE === 'true' ||
12+
process.env.MCP_CLOUD_MODE === 'true';
13+
14+
if (cloudModeEnabled) {
15+
debug('Cloud mode is enabled');
16+
}
17+
18+
return cloudModeEnabled;
19+
}
20+
21+
/**
22+
* Enable cloud mode by setting environment variable
23+
*/
24+
export function enableCloudMode(): void {
25+
process.env.CLOUDBASE_MCP_CLOUD_MODE = 'true';
26+
debug('Cloud mode enabled via API call');
27+
}
28+
29+
/**
30+
* Get cloud mode status for logging/debugging
31+
*/
32+
export function getCloudModeStatus(): {
33+
enabled: boolean;
34+
source: string | null;
35+
} {
36+
if (process.env.CLOUDBASE_MCP_CLOUD_MODE === 'true') {
37+
return { enabled: true, source: 'CLOUDBASE_MCP_CLOUD_MODE' };
38+
}
39+
if (process.env.MCP_CLOUD_MODE === 'true') {
40+
return { enabled: true, source: 'MCP_CLOUD_MODE' };
41+
}
42+
return { enabled: false, source: null };
43+
}
44+
45+
/**
46+
* Check if a tool should be registered in cloud mode
47+
* @param toolName - The name of the tool
48+
* @returns true if the tool should be registered in current mode
49+
*/
50+
export function shouldRegisterTool(toolName: string): boolean {
51+
// If not in cloud mode, register all tools
52+
if (!isCloudMode()) {
53+
return true;
54+
}
55+
56+
// Cloud-incompatible tools that involve local file operations
57+
const cloudIncompatibleTools = [
58+
// Storage tools - local file uploads
59+
'uploadFile',
60+
61+
// Hosting tools - local file uploads
62+
'uploadFiles',
63+
64+
// Function tools - local code uploads
65+
'updateFunctionCode',
66+
'createFunction', // also involves local files
67+
68+
// Miniprogram tools - local code uploads
69+
'uploadMiniprogramCode',
70+
71+
// Download tools - local file downloads
72+
'downloadTemplate',
73+
74+
// Setup tools - local config file operations
75+
'setupEnvironmentId',
76+
'clearUserEnvId',
77+
78+
// Interactive tools - local server and file operations
79+
'interactiveDialog'
80+
];
81+
82+
const shouldRegister = !cloudIncompatibleTools.includes(toolName);
83+
84+
if (!shouldRegister) {
85+
debug(`Cloud mode: skipping registration of incompatible tool: ${toolName}`);
86+
}
87+
88+
return shouldRegister;
89+
}
90+
91+
/**
92+
* Conditional tool registration wrapper
93+
* Only registers the tool if it's compatible with current mode
94+
*/
95+
export function conditionalRegisterTool(
96+
server: any,
97+
toolName: string,
98+
toolConfig: any,
99+
handler: any
100+
): void {
101+
if (shouldRegisterTool(toolName)) {
102+
server.registerTool?.(toolName, toolConfig, handler);
103+
} else {
104+
debug(`Skipped registering tool '${toolName}' in cloud mode`);
105+
}
106+
}

0 commit comments

Comments
 (0)