@xiaozhi-client/config 1.9.7-beta.17 → 1.9.7-beta.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -9
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/adapter.test.ts +16 -30
- package/src/adapter.ts +77 -106
|
@@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
2
2
|
import type { Mock } from "vitest";
|
|
3
3
|
import {
|
|
4
4
|
ConfigValidationError,
|
|
5
|
-
|
|
5
|
+
normalizeServiceConfig,
|
|
6
6
|
isModelScopeURL,
|
|
7
7
|
MCPTransportType,
|
|
8
8
|
} from "../adapter.js";
|
|
@@ -34,13 +34,13 @@ describe("ConfigAdapter 配置适配器测试", () => {
|
|
|
34
34
|
describe("SSE 类型推断", () => {
|
|
35
35
|
it("应该根据 /sse 路径推断为 SSE 类型", () => {
|
|
36
36
|
const config = { url: "https://example.com/sse" };
|
|
37
|
-
const result =
|
|
37
|
+
const result = normalizeServiceConfig(config);
|
|
38
38
|
expect(result.type).toBe(MCPTransportType.SSE);
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
it("应该正确处理带有查询参数的 SSE URL", () => {
|
|
42
42
|
const config = { url: "https://mcp.amap.com/sse?key=test&token=abc" };
|
|
43
|
-
const result =
|
|
43
|
+
const result = normalizeServiceConfig(config);
|
|
44
44
|
expect(result.type).toBe(MCPTransportType.SSE);
|
|
45
45
|
});
|
|
46
46
|
|
|
@@ -52,14 +52,14 @@ describe("ConfigAdapter 配置适配器测试", () => {
|
|
|
52
52
|
];
|
|
53
53
|
|
|
54
54
|
for (const url of testCases) {
|
|
55
|
-
const result =
|
|
55
|
+
const result = normalizeServiceConfig({ url });
|
|
56
56
|
expect(result.type).toBe(MCPTransportType.SSE);
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
it("应该正确处理带端口的 SSE URL", () => {
|
|
61
61
|
const config = { url: "https://localhost:3000/sse" };
|
|
62
|
-
const result =
|
|
62
|
+
const result = normalizeServiceConfig(config);
|
|
63
63
|
expect(result.type).toBe(MCPTransportType.SSE);
|
|
64
64
|
});
|
|
65
65
|
});
|
|
@@ -69,7 +69,7 @@ describe("ConfigAdapter 配置适配器测试", () => {
|
|
|
69
69
|
const config = {
|
|
70
70
|
url: "https://mcp.api-inference.modelscope.net/8928ccc99fa34b/mcp",
|
|
71
71
|
};
|
|
72
|
-
const result =
|
|
72
|
+
const result = normalizeServiceConfig(config);
|
|
73
73
|
expect(result.type).toBe(MCPTransportType.HTTP);
|
|
74
74
|
});
|
|
75
75
|
|
|
@@ -81,7 +81,7 @@ describe("ConfigAdapter 配置适配器测试", () => {
|
|
|
81
81
|
];
|
|
82
82
|
|
|
83
83
|
for (const url of testCases) {
|
|
84
|
-
const result =
|
|
84
|
+
const result = normalizeServiceConfig({ url });
|
|
85
85
|
expect(result.type).toBe(MCPTransportType.HTTP);
|
|
86
86
|
}
|
|
87
87
|
});
|
|
@@ -90,7 +90,7 @@ describe("ConfigAdapter 配置适配器测试", () => {
|
|
|
90
90
|
const config = {
|
|
91
91
|
url: "https://mcp.api-inference.modelscope.net/8928ccc99fa34b/mcp",
|
|
92
92
|
};
|
|
93
|
-
const result =
|
|
93
|
+
const result = normalizeServiceConfig(config);
|
|
94
94
|
expect(result.type).toBe(MCPTransportType.HTTP);
|
|
95
95
|
});
|
|
96
96
|
});
|
|
@@ -98,7 +98,7 @@ describe("ConfigAdapter 配置适配器测试", () => {
|
|
|
98
98
|
describe("无效 URL 处理", () => {
|
|
99
99
|
it("应该为无效 URL 默认推断为 HTTP", () => {
|
|
100
100
|
const config = { url: "not-a-valid-url" };
|
|
101
|
-
const result =
|
|
101
|
+
const result = normalizeServiceConfig(config);
|
|
102
102
|
expect(result.type).toBe(MCPTransportType.HTTP);
|
|
103
103
|
});
|
|
104
104
|
});
|
|
@@ -107,7 +107,7 @@ describe("ConfigAdapter 配置适配器测试", () => {
|
|
|
107
107
|
describe("显式类型指定", () => {
|
|
108
108
|
it("应该优先使用显式指定的 sse 类型", () => {
|
|
109
109
|
const config = { type: "sse" as const, url: "https://example.com/custom" };
|
|
110
|
-
const result =
|
|
110
|
+
const result = normalizeServiceConfig(config);
|
|
111
111
|
expect(result.type).toBe(MCPTransportType.SSE);
|
|
112
112
|
});
|
|
113
113
|
|
|
@@ -116,7 +116,7 @@ describe("ConfigAdapter 配置适配器测试", () => {
|
|
|
116
116
|
type: "http" as const,
|
|
117
117
|
url: "https://example.com/sse",
|
|
118
118
|
};
|
|
119
|
-
const result =
|
|
119
|
+
const result = normalizeServiceConfig(config);
|
|
120
120
|
expect(result.type).toBe(MCPTransportType.HTTP);
|
|
121
121
|
});
|
|
122
122
|
});
|
|
@@ -136,14 +136,6 @@ describe("ConfigAdapter 配置适配器测试", () => {
|
|
|
136
136
|
expect(isModelScopeURL("https://example.com/sse")).toBe(false);
|
|
137
137
|
expect(isModelScopeURL("https://mcp.amap.com/sse")).toBe(false);
|
|
138
138
|
});
|
|
139
|
-
|
|
140
|
-
it("应该为 ModelScope SSE 服务添加认证标识", () => {
|
|
141
|
-
const config = {
|
|
142
|
-
url: "https://mcp.api-inference.modelscope.net/f0fed2f733514b/sse",
|
|
143
|
-
};
|
|
144
|
-
const result = convertLegacyToNew("modelscope-service", config);
|
|
145
|
-
expect(result.modelScopeAuth).toBe(true);
|
|
146
|
-
});
|
|
147
139
|
});
|
|
148
140
|
|
|
149
141
|
describe("本地 stdio 配置", () => {
|
|
@@ -152,7 +144,7 @@ describe("ConfigAdapter 配置适配器测试", () => {
|
|
|
152
144
|
command: "node",
|
|
153
145
|
args: ["./server.js"],
|
|
154
146
|
};
|
|
155
|
-
const result =
|
|
147
|
+
const result = normalizeServiceConfig(config);
|
|
156
148
|
expect(result.type).toBe(MCPTransportType.STDIO);
|
|
157
149
|
expect(result.command).toBe("node");
|
|
158
150
|
// 相对路径会被解析为绝对路径
|
|
@@ -165,7 +157,7 @@ describe("ConfigAdapter 配置适配器测试", () => {
|
|
|
165
157
|
command: "python",
|
|
166
158
|
args: ["./script.py", "./config.json"],
|
|
167
159
|
};
|
|
168
|
-
const result =
|
|
160
|
+
const result = normalizeServiceConfig(config);
|
|
169
161
|
// 验证 args 已被解析为绝对路径
|
|
170
162
|
expect(result.args).toBeDefined();
|
|
171
163
|
expect(result.args![0]).toMatch(/\/script\.py$/);
|
|
@@ -174,21 +166,15 @@ describe("ConfigAdapter 配置适配器测试", () => {
|
|
|
174
166
|
});
|
|
175
167
|
|
|
176
168
|
describe("错误处理", () => {
|
|
177
|
-
it("应该为缺少服务名称的配置抛出错误", () => {
|
|
178
|
-
expect(() => convertLegacyToNew("", { url: "https://example.com/sse" })).toThrow(
|
|
179
|
-
ConfigValidationError
|
|
180
|
-
);
|
|
181
|
-
});
|
|
182
|
-
|
|
183
169
|
it("应该为空配置对象抛出错误", () => {
|
|
184
170
|
expect(() =>
|
|
185
|
-
|
|
171
|
+
normalizeServiceConfig(null as unknown as any)
|
|
186
172
|
).toThrow(ConfigValidationError);
|
|
187
173
|
});
|
|
188
174
|
|
|
189
175
|
it("应该为无效的传输类型抛出错误", () => {
|
|
190
176
|
const config = { type: "invalid-type" as any, url: "https://example.com" };
|
|
191
|
-
expect(() =>
|
|
177
|
+
expect(() => normalizeServiceConfig(config)).toThrow(
|
|
192
178
|
ConfigValidationError
|
|
193
179
|
);
|
|
194
180
|
});
|
|
@@ -225,7 +211,7 @@ describe("ConfigAdapter 配置适配器测试", () => {
|
|
|
225
211
|
|
|
226
212
|
for (const { url, expected, description } of testCases) {
|
|
227
213
|
it(`应该正确推断: ${description}`, () => {
|
|
228
|
-
const result =
|
|
214
|
+
const result = normalizeServiceConfig({ url });
|
|
229
215
|
expect(result.type).toBe(expected);
|
|
230
216
|
});
|
|
231
217
|
}
|
package/src/adapter.ts
CHANGED
|
@@ -7,8 +7,6 @@ import { isAbsolute, resolve, dirname } from "node:path";
|
|
|
7
7
|
import type {
|
|
8
8
|
LocalMCPServerConfig,
|
|
9
9
|
MCPServerConfig,
|
|
10
|
-
SSEMCPServerConfig,
|
|
11
|
-
StreamableHTTPMCPServerConfig,
|
|
12
10
|
} from "./manager.js";
|
|
13
11
|
import { ConfigResolver } from "./resolver.js";
|
|
14
12
|
|
|
@@ -20,10 +18,7 @@ import { ConfigResolver } from "./resolver.js";
|
|
|
20
18
|
* 配置验证错误类
|
|
21
19
|
*/
|
|
22
20
|
export class ConfigValidationError extends Error {
|
|
23
|
-
constructor(
|
|
24
|
-
message: string,
|
|
25
|
-
public readonly configName?: string
|
|
26
|
-
) {
|
|
21
|
+
constructor(message: string) {
|
|
27
22
|
super(message);
|
|
28
23
|
this.name = "ConfigValidationError";
|
|
29
24
|
}
|
|
@@ -38,14 +33,12 @@ export enum MCPTransportType {
|
|
|
38
33
|
|
|
39
34
|
// 定义简化的 MCPServiceConfig 接口
|
|
40
35
|
export interface MCPServiceConfig {
|
|
41
|
-
name: string;
|
|
42
36
|
type: MCPTransportType;
|
|
43
37
|
command?: string;
|
|
44
38
|
args?: string[];
|
|
45
39
|
env?: Record<string, string>;
|
|
46
40
|
url?: string;
|
|
47
41
|
headers?: Record<string, string>;
|
|
48
|
-
modelScopeAuth?: boolean;
|
|
49
42
|
}
|
|
50
43
|
|
|
51
44
|
/**
|
|
@@ -74,39 +67,33 @@ function inferTransportTypeFromUrl(url: string): MCPTransportType {
|
|
|
74
67
|
}
|
|
75
68
|
|
|
76
69
|
/**
|
|
77
|
-
*
|
|
70
|
+
* 将各种配置格式标准化为统一的服务配置格式
|
|
78
71
|
*/
|
|
79
|
-
export function
|
|
80
|
-
|
|
81
|
-
legacyConfig: MCPServerConfig
|
|
72
|
+
export function normalizeServiceConfig(
|
|
73
|
+
config: MCPServerConfig
|
|
82
74
|
): MCPServiceConfig {
|
|
83
|
-
console.log("转换配置", {
|
|
75
|
+
console.log("转换配置", { config });
|
|
84
76
|
|
|
85
77
|
try {
|
|
86
78
|
// 验证输入参数
|
|
87
|
-
if (!
|
|
88
|
-
throw new ConfigValidationError("
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (!legacyConfig || typeof legacyConfig !== "object") {
|
|
92
|
-
throw new ConfigValidationError("配置对象不能为空", serviceName);
|
|
79
|
+
if (!config || typeof config !== "object") {
|
|
80
|
+
throw new ConfigValidationError("配置对象不能为空");
|
|
93
81
|
}
|
|
94
82
|
|
|
95
83
|
// 根据配置类型进行转换
|
|
96
|
-
const newConfig = convertByConfigType(
|
|
84
|
+
const newConfig = convertByConfigType(config);
|
|
97
85
|
|
|
98
86
|
// 验证转换后的配置
|
|
99
87
|
validateNewConfig(newConfig);
|
|
100
88
|
|
|
101
|
-
console.log("配置转换成功", {
|
|
89
|
+
console.log("配置转换成功", { type: newConfig.type });
|
|
102
90
|
return newConfig;
|
|
103
91
|
} catch (error) {
|
|
104
|
-
console.error("配置转换失败", {
|
|
92
|
+
console.error("配置转换失败", { error });
|
|
105
93
|
throw error instanceof ConfigValidationError
|
|
106
94
|
? error
|
|
107
95
|
: new ConfigValidationError(
|
|
108
|
-
`配置转换失败: ${error instanceof Error ? error.message : String(error)}
|
|
109
|
-
serviceName
|
|
96
|
+
`配置转换失败: ${error instanceof Error ? error.message : String(error)}`
|
|
110
97
|
);
|
|
111
98
|
}
|
|
112
99
|
}
|
|
@@ -115,66 +102,66 @@ export function convertLegacyToNew(
|
|
|
115
102
|
* 根据配置类型进行转换
|
|
116
103
|
*/
|
|
117
104
|
function convertByConfigType(
|
|
118
|
-
|
|
119
|
-
legacyConfig: MCPServerConfig
|
|
105
|
+
config: MCPServerConfig
|
|
120
106
|
): MCPServiceConfig {
|
|
121
107
|
// 检查是否为本地 stdio 配置(最高优先级)
|
|
122
|
-
if (isLocalConfig(
|
|
123
|
-
return convertLocalConfig(
|
|
108
|
+
if (isLocalConfig(config)) {
|
|
109
|
+
return convertLocalConfig(config);
|
|
124
110
|
}
|
|
125
111
|
|
|
126
112
|
// 检查是否有显式指定的类型
|
|
127
|
-
if ("type" in
|
|
128
|
-
switch (
|
|
113
|
+
if ("type" in config) {
|
|
114
|
+
switch (config.type) {
|
|
129
115
|
case "sse":
|
|
130
|
-
return convertSSEConfig(
|
|
116
|
+
return convertSSEConfig(config);
|
|
131
117
|
case "http":
|
|
132
118
|
case "streamable-http": // 向后兼容
|
|
133
|
-
return convertHTTPConfig(
|
|
119
|
+
return convertHTTPConfig(config);
|
|
134
120
|
default:
|
|
135
121
|
throw new ConfigValidationError(
|
|
136
|
-
`不支持的传输类型: ${
|
|
137
|
-
serviceName
|
|
122
|
+
`不支持的传输类型: ${config.type}`
|
|
138
123
|
);
|
|
139
124
|
}
|
|
140
125
|
}
|
|
141
126
|
|
|
142
127
|
// 检查是否为网络配置(自动推断类型)
|
|
143
|
-
if ("url" in
|
|
128
|
+
if ("url" in config) {
|
|
144
129
|
// 如果 URL 是 undefined 或 null,抛出错误
|
|
145
|
-
if (
|
|
146
|
-
throw new ConfigValidationError(
|
|
147
|
-
"网络配置必须包含有效的 url 字段",
|
|
148
|
-
serviceName
|
|
149
|
-
);
|
|
130
|
+
if (config.url === undefined || config.url === null) {
|
|
131
|
+
throw new ConfigValidationError("网络配置必须包含有效的 url 字段");
|
|
150
132
|
}
|
|
151
133
|
|
|
152
134
|
// 先推断类型,然后根据推断的类型选择正确的转换函数
|
|
153
|
-
const inferredType = inferTransportTypeFromUrl(
|
|
135
|
+
const inferredType = inferTransportTypeFromUrl(config.url || "");
|
|
154
136
|
|
|
155
137
|
if (inferredType === MCPTransportType.SSE) {
|
|
156
138
|
// 为SSE类型添加显式type字段
|
|
157
|
-
const sseConfig = { ...
|
|
158
|
-
return convertSSEConfig(
|
|
139
|
+
const sseConfig = { ...config, type: "sse" as const };
|
|
140
|
+
return convertSSEConfig(sseConfig);
|
|
159
141
|
}
|
|
160
142
|
// 为HTTP类型添加显式type字段
|
|
161
|
-
const httpConfig = { ...
|
|
162
|
-
return convertHTTPConfig(
|
|
143
|
+
const httpConfig = { ...config, type: "http" as const };
|
|
144
|
+
return convertHTTPConfig(httpConfig);
|
|
163
145
|
}
|
|
164
146
|
|
|
165
|
-
throw new ConfigValidationError("无法识别的配置类型"
|
|
147
|
+
throw new ConfigValidationError("无法识别的配置类型");
|
|
166
148
|
}
|
|
167
149
|
|
|
168
|
-
/**
|
|
150
|
+
/**
|
|
151
|
+
* 转换本地 stdio 配置
|
|
152
|
+
*/
|
|
169
153
|
function convertLocalConfig(
|
|
170
|
-
|
|
171
|
-
config: LocalMCPServerConfig
|
|
154
|
+
config: MCPServerConfig
|
|
172
155
|
): MCPServiceConfig {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
156
|
+
// 类型守卫:确保是 LocalMCPServerConfig
|
|
157
|
+
if (!isLocalConfig(config)) {
|
|
158
|
+
throw new ConfigValidationError("无效的本地配置类型");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const { command, args, env } = config;
|
|
162
|
+
|
|
163
|
+
if (!command) {
|
|
164
|
+
throw new ConfigValidationError("本地配置必须包含 command 字段");
|
|
178
165
|
}
|
|
179
166
|
|
|
180
167
|
// 获取配置文件所在目录作为工作目录
|
|
@@ -195,18 +182,18 @@ function convertLocalConfig(
|
|
|
195
182
|
}
|
|
196
183
|
|
|
197
184
|
// 解析 command 中的相对路径
|
|
198
|
-
let resolvedCommand =
|
|
199
|
-
if (isRelativePath(
|
|
200
|
-
resolvedCommand = resolve(workingDir,
|
|
185
|
+
let resolvedCommand = command;
|
|
186
|
+
if (isRelativePath(command)) {
|
|
187
|
+
resolvedCommand = resolve(workingDir, command);
|
|
201
188
|
console.log("解析 command 相对路径", {
|
|
202
|
-
command
|
|
189
|
+
command,
|
|
203
190
|
resolvedCommand,
|
|
204
191
|
workingDir,
|
|
205
192
|
});
|
|
206
193
|
}
|
|
207
194
|
|
|
208
195
|
// 解析 args 中的相对路径
|
|
209
|
-
const resolvedArgs = (
|
|
196
|
+
const resolvedArgs = (args || []).map((arg: string) => {
|
|
210
197
|
// 检查是否为相对路径(以 ./ 开头或不以 / 开头且包含文件扩展名)
|
|
211
198
|
if (isRelativePath(arg)) {
|
|
212
199
|
const resolvedPath = resolve(workingDir, arg);
|
|
@@ -217,11 +204,10 @@ function convertLocalConfig(
|
|
|
217
204
|
});
|
|
218
205
|
|
|
219
206
|
return {
|
|
220
|
-
name: serviceName,
|
|
221
207
|
type: MCPTransportType.STDIO,
|
|
222
208
|
command: resolvedCommand,
|
|
223
209
|
args: resolvedArgs,
|
|
224
|
-
env
|
|
210
|
+
...(env !== undefined && { env }), // 只在 env 存在时添加该字段
|
|
225
211
|
};
|
|
226
212
|
}
|
|
227
213
|
|
|
@@ -229,82 +215,71 @@ function convertLocalConfig(
|
|
|
229
215
|
* 转换 SSE 配置
|
|
230
216
|
*/
|
|
231
217
|
function convertSSEConfig(
|
|
232
|
-
|
|
233
|
-
config: SSEMCPServerConfig
|
|
218
|
+
config: MCPServerConfig
|
|
234
219
|
): MCPServiceConfig {
|
|
235
|
-
|
|
236
|
-
|
|
220
|
+
const url = (config as any).url;
|
|
221
|
+
const type = (config as any).type;
|
|
222
|
+
const headers = (config as any).headers;
|
|
223
|
+
|
|
224
|
+
if (url === undefined || url === null) {
|
|
225
|
+
throw new ConfigValidationError("SSE 配置必须包含 url 字段");
|
|
237
226
|
}
|
|
238
227
|
|
|
239
228
|
// 优先使用显式指定的类型,如果没有则进行推断
|
|
240
229
|
const inferredType =
|
|
241
|
-
|
|
230
|
+
type === "sse"
|
|
242
231
|
? MCPTransportType.SSE
|
|
243
|
-
: inferTransportTypeFromUrl(
|
|
244
|
-
const isModelScope =
|
|
245
|
-
|
|
246
|
-
const baseConfig: MCPServiceConfig = {
|
|
247
|
-
name: serviceName,
|
|
248
|
-
type: inferredType,
|
|
249
|
-
url: config.url,
|
|
250
|
-
headers: config.headers,
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
// 如果是 ModelScope 服务,添加特殊配置
|
|
254
|
-
if (isModelScope) {
|
|
255
|
-
baseConfig.modelScopeAuth = true;
|
|
256
|
-
}
|
|
232
|
+
: inferTransportTypeFromUrl(url || "");
|
|
233
|
+
const isModelScope = url ? isModelScopeURL(url) : false;
|
|
257
234
|
|
|
258
235
|
console.log("SSE配置转换", {
|
|
259
|
-
|
|
260
|
-
url: config.url,
|
|
236
|
+
url,
|
|
261
237
|
inferredType,
|
|
262
238
|
isModelScope,
|
|
263
239
|
});
|
|
264
240
|
|
|
265
|
-
return
|
|
241
|
+
return {
|
|
242
|
+
type: inferredType,
|
|
243
|
+
url,
|
|
244
|
+
headers,
|
|
245
|
+
};
|
|
266
246
|
}
|
|
267
247
|
|
|
268
248
|
/**
|
|
269
249
|
* 转换 HTTP 配置
|
|
270
250
|
*/
|
|
271
251
|
function convertHTTPConfig(
|
|
272
|
-
|
|
273
|
-
config: StreamableHTTPMCPServerConfig
|
|
252
|
+
config: MCPServerConfig
|
|
274
253
|
): MCPServiceConfig {
|
|
254
|
+
const url = (config as any).url;
|
|
255
|
+
const headers = (config as any).headers;
|
|
256
|
+
|
|
275
257
|
// 检查 URL 是否存在
|
|
276
|
-
if (
|
|
277
|
-
throw new ConfigValidationError(
|
|
278
|
-
"HTTP 配置必须包含 url 字段",
|
|
279
|
-
serviceName
|
|
280
|
-
);
|
|
258
|
+
if (url === undefined || url === null) {
|
|
259
|
+
throw new ConfigValidationError("HTTP 配置必须包含 url 字段");
|
|
281
260
|
}
|
|
282
261
|
|
|
283
|
-
const url = config.url || "";
|
|
284
|
-
|
|
285
262
|
return {
|
|
286
|
-
name: serviceName,
|
|
287
263
|
type: MCPTransportType.HTTP,
|
|
288
|
-
url,
|
|
289
|
-
headers
|
|
264
|
+
url: url || "",
|
|
265
|
+
headers,
|
|
290
266
|
};
|
|
291
267
|
}
|
|
292
268
|
|
|
293
269
|
/**
|
|
294
|
-
*
|
|
270
|
+
* 批量标准化配置
|
|
295
271
|
*/
|
|
296
|
-
export function
|
|
272
|
+
export function normalizeServiceConfigBatch(
|
|
297
273
|
legacyConfigs: Record<string, MCPServerConfig>
|
|
298
274
|
): Record<string, MCPServiceConfig> {
|
|
299
275
|
const newConfigs: Record<string, MCPServiceConfig> = {};
|
|
300
|
-
const errors: Array<{
|
|
276
|
+
const errors: Array<{ error: Error }> = [];
|
|
301
277
|
|
|
302
|
-
for (const [
|
|
278
|
+
for (const [name, config] of Object.entries(legacyConfigs)) {
|
|
303
279
|
try {
|
|
304
|
-
newConfigs[
|
|
280
|
+
newConfigs[name] = normalizeServiceConfig(config);
|
|
305
281
|
} catch (error) {
|
|
306
282
|
errors.push({
|
|
307
|
-
serviceName,
|
|
308
283
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
309
284
|
});
|
|
310
285
|
}
|
|
@@ -312,7 +287,7 @@ export function convertLegacyConfigBatch(
|
|
|
312
287
|
|
|
313
288
|
if (errors.length > 0) {
|
|
314
289
|
const errorMessages = errors
|
|
315
|
-
.map(({
|
|
290
|
+
.map(({ error }, index) => `[${index}]: ${error.message}`)
|
|
316
291
|
.join("; ");
|
|
317
292
|
throw new ConfigValidationError(`批量配置转换失败: ${errorMessages}`);
|
|
318
293
|
}
|
|
@@ -378,10 +353,6 @@ export function isModelScopeURL(url: string): boolean {
|
|
|
378
353
|
* 验证新配置格式
|
|
379
354
|
*/
|
|
380
355
|
function validateNewConfig(config: MCPServiceConfig): void {
|
|
381
|
-
if (!config.name || typeof config.name !== "string") {
|
|
382
|
-
throw new ConfigValidationError("配置必须包含有效的 name 字段");
|
|
383
|
-
}
|
|
384
|
-
|
|
385
356
|
if (config.type && !Object.values(MCPTransportType).includes(config.type)) {
|
|
386
357
|
throw new ConfigValidationError(`无效的传输类型: ${config.type}`);
|
|
387
358
|
}
|