@xmemo/client 0.4.154 → 0.4.156
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/package.json +2 -2
- package/src/args.js +63 -0
- package/src/auth.js +199 -0
- package/src/base-url.js +12 -0
- package/src/cli.js +23 -3962
- package/src/commands/auth.js +229 -0
- package/src/commands/diagnostics.js +196 -0
- package/src/commands/mcp.js +187 -0
- package/src/commands/profile.js +56 -0
- package/src/commands/setup.js +190 -0
- package/src/commands/update.js +57 -0
- package/src/constants.js +32 -0
- package/src/discovery.js +102 -0
- package/src/env.js +81 -0
- package/src/errors.js +6 -0
- package/src/help.js +58 -0
- package/src/http.js +160 -0
- package/src/io.js +16 -0
- package/src/mcp/clients.js +80 -0
- package/src/mcp/codex.js +147 -0
- package/src/mcp/copilot-proxy.js +43 -0
- package/src/mcp/detect.js +50 -0
- package/src/mcp/hermes.js +71 -0
- package/src/mcp/identity.js +62 -0
- package/src/mcp/json-clients.js +354 -0
- package/src/mcp/names.js +12 -0
- package/src/mcp/paths.js +154 -0
- package/src/mcp/proxy.js +111 -0
- package/src/mcp/registry.js +67 -0
- package/src/mcp/templates.js +155 -0
- package/src/path-config.js +25 -0
- package/src/profile.js +532 -0
- package/src/runtime.js +144 -0
- package/src/setup.js +243 -0
- package/src/version.js +1 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
AGENT_INSTANCE_ENV_VAR,
|
|
6
|
+
AGENT_ID_HEADER,
|
|
7
|
+
AGENT_INSTANCE_HEADER,
|
|
8
|
+
MCP_SERVER_NAME,
|
|
9
|
+
TOKEN_ENV_VAR
|
|
10
|
+
} from '../constants.js';
|
|
11
|
+
import { UsageError } from '../errors.js';
|
|
12
|
+
import {
|
|
13
|
+
bestEffortChmod,
|
|
14
|
+
isPlainObject,
|
|
15
|
+
parseJsonConfig,
|
|
16
|
+
readTextIfExists
|
|
17
|
+
} from '../runtime.js';
|
|
18
|
+
import { envReferenceIdentity } from './identity.js';
|
|
19
|
+
import { existingJsonMcpServerName } from './names.js';
|
|
20
|
+
|
|
21
|
+
export const JSON_MCP_CLIENT_DEFINITIONS = Object.freeze([
|
|
22
|
+
httpClientDefinition('cursor', 'Cursor', 'defaultCursorConfigPath', { urlKey: 'url', authentication: 'env-bearer' }),
|
|
23
|
+
httpClientDefinition('gemini-cli', 'Gemini CLI', 'defaultGeminiConfigPath', { urlKey: 'httpUrl', authentication: 'oauth' }),
|
|
24
|
+
httpClientDefinition('antigravity', 'Antigravity', 'defaultAntigravityConfigPath', { urlKey: 'serverUrl', authentication: 'oauth' }),
|
|
25
|
+
httpClientDefinition('antigravity-ide', 'Antigravity IDE', 'defaultAntigravityIdeConfigPath', { urlKey: 'url', authentication: 'oauth', defaultIdentityId: 'antigravity', extra: { type: 'http' } }),
|
|
26
|
+
httpClientDefinition('antigravity2', 'Antigravity 2.0', 'defaultAntigravity2ConfigPath', { urlKey: 'url', authentication: 'oauth', defaultIdentityId: 'antigravity', extra: { type: 'http' } }),
|
|
27
|
+
httpClientDefinition('antigravity-cli', 'Antigravity CLI', 'defaultAntigravityCliConfigPath', { urlKey: 'httpUrl', authentication: 'oauth', defaultIdentityId: 'antigravity' }),
|
|
28
|
+
httpClientDefinition('windsurf', 'Windsurf', 'defaultWindsurfConfigPath', { urlKey: 'serverUrl', authentication: 'env-bearer' }),
|
|
29
|
+
httpClientDefinition('cline', 'Cline', 'defaultClineConfigPath', { urlKey: 'httpUrl', authentication: 'env-bearer' }),
|
|
30
|
+
nestedTransportClientDefinition('continue', 'Continue', 'defaultContinueConfigPath'),
|
|
31
|
+
commandClientDefinition('claude-desktop', 'Claude Desktop', 'defaultClaudeConfigPath'),
|
|
32
|
+
httpClientDefinition('openclaw', 'OpenClaw', 'defaultOpenclawConfigPath', { urlKey: 'url', authentication: 'env-bearer' }),
|
|
33
|
+
httpClientDefinition('kiro', 'Kiro', 'defaultKiroConfigPath', { urlKey: 'url', authentication: 'env-bearer' }),
|
|
34
|
+
commandClientDefinition('zed', 'Zed', 'defaultZedConfigPath', { section: 'context_servers' }),
|
|
35
|
+
nestedTransportClientDefinition('jetbrains', 'JetBrains', 'defaultJetbrainsConfigPath'),
|
|
36
|
+
remoteClientDefinition('opencode', 'OpenCode', 'defaultOpencodeConfigPath'),
|
|
37
|
+
httpClientDefinition('qwen', 'Qwen', 'defaultQwenConfigPath', { urlKey: 'httpUrl', authentication: 'oauth' }),
|
|
38
|
+
commandClientDefinition('trae', 'Trae', 'defaultTraeConfigPath'),
|
|
39
|
+
commandClientDefinition('trae-solo', 'Trae Solo', 'defaultTraeSoloConfigPath'),
|
|
40
|
+
commandClientDefinition('claude-code', 'Claude Code', 'defaultClaudecodeConfigPath')
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
const JSON_MCP_CLIENTS_BY_ID = new Map(JSON_MCP_CLIENT_DEFINITIONS.map((definition) => [definition.id, definition]));
|
|
44
|
+
|
|
45
|
+
function httpClientDefinition(id, label, defaultConfigPath, options) {
|
|
46
|
+
return {
|
|
47
|
+
id,
|
|
48
|
+
label,
|
|
49
|
+
defaultConfigPath,
|
|
50
|
+
configKind: 'json',
|
|
51
|
+
section: 'mcpServers',
|
|
52
|
+
serverKind: 'http',
|
|
53
|
+
bearerSyntax: 'env-colon',
|
|
54
|
+
...options
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function nestedTransportClientDefinition(id, label, defaultConfigPath) {
|
|
59
|
+
return {
|
|
60
|
+
id,
|
|
61
|
+
label,
|
|
62
|
+
defaultConfigPath,
|
|
63
|
+
configKind: 'json',
|
|
64
|
+
section: 'mcpServers',
|
|
65
|
+
serverKind: 'nested-transport',
|
|
66
|
+
authentication: 'env-bearer',
|
|
67
|
+
bearerSyntax: 'plain',
|
|
68
|
+
mergeExperimentalModelContextProtocolServers: true
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function commandClientDefinition(id, label, defaultConfigPath, options = {}) {
|
|
73
|
+
return {
|
|
74
|
+
id,
|
|
75
|
+
label,
|
|
76
|
+
defaultConfigPath,
|
|
77
|
+
configKind: 'json',
|
|
78
|
+
section: 'mcpServers',
|
|
79
|
+
serverKind: 'mcp-remote-command',
|
|
80
|
+
authentication: 'env-bearer',
|
|
81
|
+
...options
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function remoteClientDefinition(id, label, defaultConfigPath) {
|
|
86
|
+
return {
|
|
87
|
+
id,
|
|
88
|
+
label,
|
|
89
|
+
defaultConfigPath,
|
|
90
|
+
configKind: 'json',
|
|
91
|
+
section: 'mcp',
|
|
92
|
+
serverKind: 'remote',
|
|
93
|
+
authentication: 'oauth'
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function jsonMcpClientDefinition(clientId) {
|
|
98
|
+
return JSON_MCP_CLIENTS_BY_ID.get(clientId) ?? null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function jsonMcpClientIds() {
|
|
102
|
+
return JSON_MCP_CLIENT_DEFINITIONS.map((definition) => definition.id);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function jsonClientConfig(clientId, mcpUrl, identity) {
|
|
106
|
+
const definition = requireJsonMcpClientDefinition(clientId);
|
|
107
|
+
return sectionConfig(definition.section, jsonClientServerConfig(clientId, mcpUrl, identity));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function jsonClientSnippet(clientId, mcpUrl, identity) {
|
|
111
|
+
return `${JSON.stringify(jsonClientConfig(clientId, mcpUrl, identity), null, 2)}\n`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function jsonClientServerConfig(clientId, mcpUrl, identity) {
|
|
115
|
+
const definition = requireJsonMcpClientDefinition(clientId);
|
|
116
|
+
const resolvedIdentity = identity ?? envReferenceIdentity(definition.defaultIdentityId ?? definition.id);
|
|
117
|
+
return serverConfigFromDefinition(definition, mcpUrl, resolvedIdentity);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export async function mergeJsonClientMcpConfig(clientId, configPath, mcpUrl, identity) {
|
|
121
|
+
const definition = requireJsonMcpClientDefinition(clientId);
|
|
122
|
+
const serverConfig = serverConfigFromDefinition(definition, mcpUrl, identity);
|
|
123
|
+
await mergeJsonSectionConfig(configPath, definition.section, serverConfig, definition.section, (parsed) => {
|
|
124
|
+
if (definition.mergeExperimentalModelContextProtocolServers && isPlainObject(parsed.experimental)) {
|
|
125
|
+
mergeExperimentalModelContextProtocolServers(parsed, serverConfig, mcpUrl);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function requireJsonMcpClientDefinition(clientId) {
|
|
131
|
+
const definition = jsonMcpClientDefinition(clientId);
|
|
132
|
+
if (!definition) {
|
|
133
|
+
throw new UsageError(`Unsupported JSON MCP client: ${clientId}`);
|
|
134
|
+
}
|
|
135
|
+
return definition;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function sectionConfig(sectionName, serverConfig) {
|
|
139
|
+
return {
|
|
140
|
+
[sectionName]: {
|
|
141
|
+
[MCP_SERVER_NAME]: serverConfig
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function serverConfigFromDefinition(definition, mcpUrl, identity) {
|
|
147
|
+
if (definition.serverKind === 'mcp-remote-command') {
|
|
148
|
+
return mcpRemoteCommandJsonServerConfig(mcpUrl, identity);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (definition.serverKind === 'nested-transport') {
|
|
152
|
+
return {
|
|
153
|
+
transport: {
|
|
154
|
+
type: 'streamable-http',
|
|
155
|
+
url: mcpUrl,
|
|
156
|
+
headers: headersForDefinition(definition, identity)
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (definition.serverKind === 'remote') {
|
|
162
|
+
return {
|
|
163
|
+
type: 'remote',
|
|
164
|
+
url: mcpUrl,
|
|
165
|
+
enabled: true,
|
|
166
|
+
headers: headersForDefinition(definition, identity)
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
...(definition.extra ?? {}),
|
|
172
|
+
[definition.urlKey]: mcpUrl,
|
|
173
|
+
headers: headersForDefinition(definition, identity)
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function headersForDefinition(definition, identity) {
|
|
178
|
+
const headers = {
|
|
179
|
+
[AGENT_ID_HEADER]: identity.agentId,
|
|
180
|
+
[AGENT_INSTANCE_HEADER]: identity.agentInstanceId
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
if (definition.authentication === 'env-bearer') {
|
|
184
|
+
headers.Authorization = authorizationHeader(definition.bearerSyntax);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return orderedHeaders(headers);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function orderedHeaders(headers) {
|
|
191
|
+
if (!headers.Authorization) {
|
|
192
|
+
return headers;
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
Authorization: headers.Authorization,
|
|
196
|
+
[AGENT_ID_HEADER]: headers[AGENT_ID_HEADER],
|
|
197
|
+
[AGENT_INSTANCE_HEADER]: headers[AGENT_INSTANCE_HEADER]
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function authorizationHeader(syntax) {
|
|
202
|
+
if (syntax === 'plain') {
|
|
203
|
+
return `Bearer \${${TOKEN_ENV_VAR}}`;
|
|
204
|
+
}
|
|
205
|
+
return `Bearer \${env:${TOKEN_ENV_VAR}}`;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function mcpRemoteCommandJsonServerConfig(mcpUrl, identity) {
|
|
209
|
+
return {
|
|
210
|
+
command: 'npx',
|
|
211
|
+
args: [
|
|
212
|
+
'-y',
|
|
213
|
+
'mcp-remote',
|
|
214
|
+
mcpUrl,
|
|
215
|
+
'--header',
|
|
216
|
+
`Authorization:Bearer \${${TOKEN_ENV_VAR}}`,
|
|
217
|
+
'--header',
|
|
218
|
+
`${AGENT_ID_HEADER}:${identity.agentId}`,
|
|
219
|
+
'--header',
|
|
220
|
+
`${AGENT_INSTANCE_HEADER}:\${${AGENT_INSTANCE_ENV_VAR}}`
|
|
221
|
+
],
|
|
222
|
+
env: {
|
|
223
|
+
[TOKEN_ENV_VAR]: `\${env:${TOKEN_ENV_VAR}}`,
|
|
224
|
+
[AGENT_INSTANCE_ENV_VAR]: identity.agentInstanceId
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function mergeJsonSectionConfig(configPath, sectionName, serverConfig, duplicatePath = sectionName, afterMerge) {
|
|
230
|
+
const existing = await readTextIfExists(configPath);
|
|
231
|
+
const parsed = existing.trim().length === 0 ? {} : parseJsonConfig(existing, configPath);
|
|
232
|
+
if (!isPlainObject(parsed)) {
|
|
233
|
+
throw new UsageError(`MCP JSON config must be an object: ${configPath}`);
|
|
234
|
+
}
|
|
235
|
+
if (!isPlainObject(parsed[sectionName])) {
|
|
236
|
+
parsed[sectionName] = {};
|
|
237
|
+
}
|
|
238
|
+
const existingName = existingJsonMcpServerName(parsed[sectionName]);
|
|
239
|
+
if (existingName) {
|
|
240
|
+
throw new UsageError(`MCP config already contains ${duplicatePath}.${existingName}. Edit ${configPath} manually to avoid duplicate server definitions.`);
|
|
241
|
+
}
|
|
242
|
+
parsed[sectionName][MCP_SERVER_NAME] = serverConfig;
|
|
243
|
+
afterMerge?.(parsed);
|
|
244
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true, mode: 0o700 });
|
|
245
|
+
await fs.writeFile(configPath, `${JSON.stringify(parsed, null, 2)}\n`, { mode: 0o600 });
|
|
246
|
+
await bestEffortChmod(configPath, 0o600);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function mergeExperimentalModelContextProtocolServers(parsed, serverConfig, mcpUrl) {
|
|
250
|
+
if (!Array.isArray(parsed.experimental.modelContextProtocolServers)) {
|
|
251
|
+
parsed.experimental.modelContextProtocolServers = [];
|
|
252
|
+
}
|
|
253
|
+
const hasXMemo = parsed.experimental.modelContextProtocolServers.some(
|
|
254
|
+
(srv) => srv.transport && srv.transport.url === mcpUrl
|
|
255
|
+
);
|
|
256
|
+
if (!hasXMemo) {
|
|
257
|
+
parsed.experimental.modelContextProtocolServers.push(serverConfig);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export const cursorJsonConfig = (mcpUrl, identity = envReferenceIdentity('cursor')) => jsonClientConfig('cursor', mcpUrl, identity);
|
|
262
|
+
export const cursorJsonSnippet = (mcpUrl, identity = envReferenceIdentity('cursor')) => jsonClientSnippet('cursor', mcpUrl, identity);
|
|
263
|
+
export const cursorJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('cursor')) => jsonClientServerConfig('cursor', mcpUrl, identity);
|
|
264
|
+
export const mergeJsonMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('cursor', configPath, mcpUrl, identity);
|
|
265
|
+
|
|
266
|
+
export const geminiJsonConfig = (mcpUrl, identity = envReferenceIdentity('gemini-cli')) => jsonClientConfig('gemini-cli', mcpUrl, identity);
|
|
267
|
+
export const geminiJsonSnippet = (mcpUrl, identity = envReferenceIdentity('gemini-cli')) => jsonClientSnippet('gemini-cli', mcpUrl, identity);
|
|
268
|
+
export const geminiJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('gemini-cli')) => jsonClientServerConfig('gemini-cli', mcpUrl, identity);
|
|
269
|
+
export const mergeGeminiMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('gemini-cli', configPath, mcpUrl, identity);
|
|
270
|
+
|
|
271
|
+
export const antigravityJsonConfig = (mcpUrl, identity = envReferenceIdentity('antigravity')) => jsonClientConfig('antigravity', mcpUrl, identity);
|
|
272
|
+
export const antigravityJsonSnippet = (mcpUrl, identity = envReferenceIdentity('antigravity')) => jsonClientSnippet('antigravity', mcpUrl, identity);
|
|
273
|
+
export const antigravityJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('antigravity')) => jsonClientServerConfig('antigravity', mcpUrl, identity);
|
|
274
|
+
export const mergeAntigravityMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('antigravity', configPath, mcpUrl, identity);
|
|
275
|
+
|
|
276
|
+
export const antigravityIdeJsonConfig = (mcpUrl, identity = envReferenceIdentity('antigravity')) => jsonClientConfig('antigravity-ide', mcpUrl, identity);
|
|
277
|
+
export const antigravityIdeJsonSnippet = (mcpUrl, identity = envReferenceIdentity('antigravity')) => jsonClientSnippet('antigravity-ide', mcpUrl, identity);
|
|
278
|
+
export const antigravityIdeJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('antigravity')) => jsonClientServerConfig('antigravity-ide', mcpUrl, identity);
|
|
279
|
+
export const mergeAntigravityIdeMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('antigravity-ide', configPath, mcpUrl, identity);
|
|
280
|
+
|
|
281
|
+
export const antigravity2JsonConfig = (mcpUrl, identity = envReferenceIdentity('antigravity')) => jsonClientConfig('antigravity2', mcpUrl, identity);
|
|
282
|
+
export const antigravity2JsonSnippet = (mcpUrl, identity = envReferenceIdentity('antigravity')) => jsonClientSnippet('antigravity2', mcpUrl, identity);
|
|
283
|
+
export const antigravity2JsonServerConfig = (mcpUrl, identity = envReferenceIdentity('antigravity')) => jsonClientServerConfig('antigravity2', mcpUrl, identity);
|
|
284
|
+
export const mergeAntigravity2McpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('antigravity2', configPath, mcpUrl, identity);
|
|
285
|
+
|
|
286
|
+
export const antigravityCliJsonConfig = (mcpUrl, identity = envReferenceIdentity('antigravity')) => jsonClientConfig('antigravity-cli', mcpUrl, identity);
|
|
287
|
+
export const antigravityCliJsonSnippet = (mcpUrl, identity = envReferenceIdentity('antigravity')) => jsonClientSnippet('antigravity-cli', mcpUrl, identity);
|
|
288
|
+
export const antigravityCliJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('antigravity')) => jsonClientServerConfig('antigravity-cli', mcpUrl, identity);
|
|
289
|
+
export const mergeAntigravityCliMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('antigravity-cli', configPath, mcpUrl, identity);
|
|
290
|
+
|
|
291
|
+
export const windsurfJsonConfig = (mcpUrl, identity = envReferenceIdentity('windsurf')) => jsonClientConfig('windsurf', mcpUrl, identity);
|
|
292
|
+
export const windsurfJsonSnippet = (mcpUrl, identity = envReferenceIdentity('windsurf')) => jsonClientSnippet('windsurf', mcpUrl, identity);
|
|
293
|
+
export const windsurfJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('windsurf')) => jsonClientServerConfig('windsurf', mcpUrl, identity);
|
|
294
|
+
export const mergeWindsurfMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('windsurf', configPath, mcpUrl, identity);
|
|
295
|
+
|
|
296
|
+
export const clineJsonConfig = (mcpUrl, identity = envReferenceIdentity('cline')) => jsonClientConfig('cline', mcpUrl, identity);
|
|
297
|
+
export const clineJsonSnippet = (mcpUrl, identity = envReferenceIdentity('cline')) => jsonClientSnippet('cline', mcpUrl, identity);
|
|
298
|
+
export const clineJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('cline')) => jsonClientServerConfig('cline', mcpUrl, identity);
|
|
299
|
+
export const mergeClineMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('cline', configPath, mcpUrl, identity);
|
|
300
|
+
|
|
301
|
+
export const continueJsonConfig = (mcpUrl, identity = envReferenceIdentity('continue')) => jsonClientConfig('continue', mcpUrl, identity);
|
|
302
|
+
export const continueJsonSnippet = (mcpUrl, identity = envReferenceIdentity('continue')) => jsonClientSnippet('continue', mcpUrl, identity);
|
|
303
|
+
export const continueJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('continue')) => jsonClientServerConfig('continue', mcpUrl, identity);
|
|
304
|
+
export const mergeContinueMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('continue', configPath, mcpUrl, identity);
|
|
305
|
+
|
|
306
|
+
export const claudeJsonConfig = (mcpUrl, identity = envReferenceIdentity('claude-desktop')) => jsonClientConfig('claude-desktop', mcpUrl, identity);
|
|
307
|
+
export const claudeJsonSnippet = (mcpUrl, identity = envReferenceIdentity('claude-desktop')) => jsonClientSnippet('claude-desktop', mcpUrl, identity);
|
|
308
|
+
export const claudeJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('claude-desktop')) => jsonClientServerConfig('claude-desktop', mcpUrl, identity);
|
|
309
|
+
export const mergeClaudeMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('claude-desktop', configPath, mcpUrl, identity);
|
|
310
|
+
|
|
311
|
+
export const openclawJsonConfig = (mcpUrl, identity = envReferenceIdentity('openclaw')) => jsonClientConfig('openclaw', mcpUrl, identity);
|
|
312
|
+
export const openclawJsonSnippet = (mcpUrl, identity = envReferenceIdentity('openclaw')) => jsonClientSnippet('openclaw', mcpUrl, identity);
|
|
313
|
+
export const openclawJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('openclaw')) => jsonClientServerConfig('openclaw', mcpUrl, identity);
|
|
314
|
+
export const mergeOpenclawMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('openclaw', configPath, mcpUrl, identity);
|
|
315
|
+
|
|
316
|
+
export const kiroJsonConfig = (mcpUrl, identity = envReferenceIdentity('kiro')) => jsonClientConfig('kiro', mcpUrl, identity);
|
|
317
|
+
export const kiroJsonSnippet = (mcpUrl, identity = envReferenceIdentity('kiro')) => jsonClientSnippet('kiro', mcpUrl, identity);
|
|
318
|
+
export const kiroJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('kiro')) => jsonClientServerConfig('kiro', mcpUrl, identity);
|
|
319
|
+
export const mergeKiroMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('kiro', configPath, mcpUrl, identity);
|
|
320
|
+
|
|
321
|
+
export const zedJsonConfig = (mcpUrl, identity = envReferenceIdentity('zed')) => jsonClientConfig('zed', mcpUrl, identity);
|
|
322
|
+
export const zedJsonSnippet = (mcpUrl, identity = envReferenceIdentity('zed')) => jsonClientSnippet('zed', mcpUrl, identity);
|
|
323
|
+
export const zedJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('zed')) => jsonClientServerConfig('zed', mcpUrl, identity);
|
|
324
|
+
export const mergeZedMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('zed', configPath, mcpUrl, identity);
|
|
325
|
+
|
|
326
|
+
export const jetbrainsJsonConfig = (mcpUrl, identity = envReferenceIdentity('jetbrains')) => jsonClientConfig('jetbrains', mcpUrl, identity);
|
|
327
|
+
export const jetbrainsJsonSnippet = (mcpUrl, identity = envReferenceIdentity('jetbrains')) => jsonClientSnippet('jetbrains', mcpUrl, identity);
|
|
328
|
+
export const jetbrainsJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('jetbrains')) => jsonClientServerConfig('jetbrains', mcpUrl, identity);
|
|
329
|
+
export const mergeJetbrainsMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('jetbrains', configPath, mcpUrl, identity);
|
|
330
|
+
|
|
331
|
+
export const opencodeJsonConfig = (mcpUrl, identity = envReferenceIdentity('opencode')) => jsonClientConfig('opencode', mcpUrl, identity);
|
|
332
|
+
export const opencodeJsonSnippet = (mcpUrl, identity = envReferenceIdentity('opencode')) => jsonClientSnippet('opencode', mcpUrl, identity);
|
|
333
|
+
export const opencodeJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('opencode')) => jsonClientServerConfig('opencode', mcpUrl, identity);
|
|
334
|
+
export const mergeOpencodeMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('opencode', configPath, mcpUrl, identity);
|
|
335
|
+
|
|
336
|
+
export const qwenJsonConfig = (mcpUrl, identity = envReferenceIdentity('qwen')) => jsonClientConfig('qwen', mcpUrl, identity);
|
|
337
|
+
export const qwenJsonSnippet = (mcpUrl, identity = envReferenceIdentity('qwen')) => jsonClientSnippet('qwen', mcpUrl, identity);
|
|
338
|
+
export const qwenJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('qwen')) => jsonClientServerConfig('qwen', mcpUrl, identity);
|
|
339
|
+
export const mergeQwenMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('qwen', configPath, mcpUrl, identity);
|
|
340
|
+
|
|
341
|
+
export const traeJsonConfig = (mcpUrl, identity = envReferenceIdentity('trae')) => jsonClientConfig('trae', mcpUrl, identity);
|
|
342
|
+
export const traeJsonSnippet = (mcpUrl, identity = envReferenceIdentity('trae')) => jsonClientSnippet('trae', mcpUrl, identity);
|
|
343
|
+
export const traeJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('trae')) => jsonClientServerConfig('trae', mcpUrl, identity);
|
|
344
|
+
export const mergeTraeMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('trae', configPath, mcpUrl, identity);
|
|
345
|
+
|
|
346
|
+
export const traeSoloJsonConfig = (mcpUrl, identity = envReferenceIdentity('trae-solo')) => jsonClientConfig('trae-solo', mcpUrl, identity);
|
|
347
|
+
export const traeSoloJsonSnippet = (mcpUrl, identity = envReferenceIdentity('trae-solo')) => jsonClientSnippet('trae-solo', mcpUrl, identity);
|
|
348
|
+
export const traeSoloJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('trae-solo')) => jsonClientServerConfig('trae-solo', mcpUrl, identity);
|
|
349
|
+
export const mergeTraeSoloMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('trae-solo', configPath, mcpUrl, identity);
|
|
350
|
+
|
|
351
|
+
export const claudecodeJsonConfig = (mcpUrl, identity = envReferenceIdentity('claude-code')) => jsonClientConfig('claude-code', mcpUrl, identity);
|
|
352
|
+
export const claudecodeJsonSnippet = (mcpUrl, identity = envReferenceIdentity('claude-code')) => jsonClientSnippet('claude-code', mcpUrl, identity);
|
|
353
|
+
export const claudecodeJsonServerConfig = (mcpUrl, identity = envReferenceIdentity('claude-code')) => jsonClientServerConfig('claude-code', mcpUrl, identity);
|
|
354
|
+
export const mergeClaudecodeMcpConfig = (configPath, mcpUrl, identity) => mergeJsonClientMcpConfig('claude-code', configPath, mcpUrl, identity);
|
package/src/mcp/names.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LEGACY_MCP_SERVER_NAMES,
|
|
3
|
+
MCP_SERVER_NAME
|
|
4
|
+
} from '../constants.js';
|
|
5
|
+
|
|
6
|
+
export function knownMcpServerNames() {
|
|
7
|
+
return [MCP_SERVER_NAME, ...LEGACY_MCP_SERVER_NAMES];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function existingJsonMcpServerName(mcpServers) {
|
|
11
|
+
return knownMcpServerNames().find((name) => mcpServers[name]);
|
|
12
|
+
}
|
package/src/mcp/paths.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
export function configRoot(env) {
|
|
5
|
+
if (env.XMEMO_CONFIG_HOME) {
|
|
6
|
+
return env.XMEMO_CONFIG_HOME;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (env.MEMORY_OS_CONFIG_HOME) {
|
|
10
|
+
return env.MEMORY_OS_CONFIG_HOME;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (process.platform === 'win32' && env.LOCALAPPDATA) {
|
|
14
|
+
return path.join(env.LOCALAPPDATA, 'XMemo', 'CLI');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (env.XDG_CONFIG_HOME) {
|
|
18
|
+
return path.join(env.XDG_CONFIG_HOME, 'xmemo');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const home = env.HOME || os.homedir();
|
|
22
|
+
return path.join(home, '.config', 'xmemo');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function defaultCodexConfigPath(env) {
|
|
26
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
27
|
+
return path.join(home, '.codex', 'config.toml');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function defaultCursorConfigPath(env) {
|
|
31
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
32
|
+
return path.join(home, '.cursor', 'mcp.json');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function defaultGeminiConfigPath(env) {
|
|
36
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
37
|
+
return path.join(home, '.gemini', 'settings.json');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function defaultAntigravityConfigPath(env) {
|
|
41
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
42
|
+
return path.join(home, '.gemini', 'config', 'mcp_config.json');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function defaultAntigravityIdeConfigPath(env) {
|
|
46
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
47
|
+
return path.join(home, '.gemini', 'config', 'mcp_config.json');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function defaultAntigravity2ConfigPath(env) {
|
|
51
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
52
|
+
return path.join(home, '.gemini', 'config', 'mcp_config.json');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function defaultAntigravityCliConfigPath(env) {
|
|
56
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
57
|
+
return path.join(home, '.gemini', 'config', 'mcp_config.json');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function defaultCopilotConfigPath(env) {
|
|
61
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
62
|
+
return path.join(env.COPILOT_HOME ?? path.join(home, '.copilot'), 'mcp-config.json');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function defaultWindsurfConfigPath(env) {
|
|
66
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
67
|
+
return path.join(home, '.codeium', 'windsurf', 'mcp_config.json');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function defaultClineConfigPath(env) {
|
|
71
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
72
|
+
return path.join(home, 'Documents', 'Cline', 'MCP', 'cline_mcp_settings.json');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function defaultContinueConfigPath(env) {
|
|
76
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
77
|
+
return path.join(home, '.continue', 'config.json');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function defaultClaudeConfigPath(env) {
|
|
81
|
+
if (process.platform === 'win32' && env.APPDATA) {
|
|
82
|
+
return path.join(env.APPDATA, 'Claude', 'claude_desktop_config.json');
|
|
83
|
+
}
|
|
84
|
+
const home = env.HOME || os.homedir();
|
|
85
|
+
if (process.platform === 'darwin') {
|
|
86
|
+
return path.join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
87
|
+
}
|
|
88
|
+
return path.join(home, '.config', 'Claude', 'claude_desktop_config.json');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function defaultOpenclawConfigPath(env) {
|
|
92
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
93
|
+
return path.join(home, '.openclaw', 'openclaw.json');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function defaultKiroConfigPath(env) {
|
|
97
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
98
|
+
return path.join(home, '.kiro', 'settings', 'mcp.json');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function defaultZedConfigPath(env) {
|
|
102
|
+
if (process.platform === 'win32' && env.APPDATA) {
|
|
103
|
+
return path.join(env.APPDATA, 'Zed', 'settings.json');
|
|
104
|
+
}
|
|
105
|
+
const home = env.HOME || env.USERPROFILE || os.homedir();
|
|
106
|
+
return path.join(home, '.config', 'zed', 'settings.json');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function defaultJetbrainsConfigPath(env) {
|
|
110
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
111
|
+
return path.join(home, '.continue', 'config.json');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function defaultOpencodeConfigPath(env) {
|
|
115
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
116
|
+
return path.join(home, '.config', 'opencode', 'opencode.json');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function defaultHermesConfigPath(env) {
|
|
120
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
121
|
+
return path.join(home, '.hermes', 'config.yaml');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function defaultQwenConfigPath(env) {
|
|
125
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
126
|
+
return path.join(home, '.qwen', 'settings.json');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function defaultTraeConfigPath(env) {
|
|
130
|
+
if (process.platform === 'win32' && env.APPDATA) {
|
|
131
|
+
return path.join(env.APPDATA, 'Trae', 'User', 'mcp.json');
|
|
132
|
+
}
|
|
133
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
134
|
+
if (process.platform === 'darwin') {
|
|
135
|
+
return path.join(home, 'Library', 'Application Support', 'Trae', 'User', 'mcp.json');
|
|
136
|
+
}
|
|
137
|
+
return path.join(home, '.config', 'Trae', 'User', 'mcp.json');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function defaultTraeSoloConfigPath(env) {
|
|
141
|
+
if (process.platform === 'win32' && env.APPDATA) {
|
|
142
|
+
return path.join(env.APPDATA, 'TRAE SOLO', 'User', 'mcp.json');
|
|
143
|
+
}
|
|
144
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
145
|
+
if (process.platform === 'darwin') {
|
|
146
|
+
return path.join(home, 'Library', 'Application Support', 'TRAE SOLO', 'User', 'mcp.json');
|
|
147
|
+
}
|
|
148
|
+
return path.join(home, '.config', 'TRAE SOLO', 'User', 'mcp.json');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function defaultClaudecodeConfigPath(env) {
|
|
152
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
153
|
+
return path.join(home, '.claude.json');
|
|
154
|
+
}
|
package/src/mcp/proxy.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
|
|
3
|
+
import { optionValue, parsePositiveInteger } from '../args.js';
|
|
4
|
+
import {
|
|
5
|
+
AGENT_ID_HEADER,
|
|
6
|
+
AGENT_INSTANCE_HEADER,
|
|
7
|
+
CLI_VERSION,
|
|
8
|
+
COMMAND_NAME,
|
|
9
|
+
DEFAULT_SERVICE_URL,
|
|
10
|
+
DEFAULT_PROXY_HOST,
|
|
11
|
+
DEFAULT_PROXY_PORT,
|
|
12
|
+
PRODUCT_NAME,
|
|
13
|
+
TOKEN_ENV_VAR
|
|
14
|
+
} from '../constants.js';
|
|
15
|
+
import { credentialsPath, resolveCredentialToken, validateToken } from '../auth.js';
|
|
16
|
+
import { endpointUrl, normalizeBaseUrl } from '../http.js';
|
|
17
|
+
import { UsageError } from '../errors.js';
|
|
18
|
+
import { writeLine } from '../io.js';
|
|
19
|
+
import { closeServer, readAll, waitForShutdown } from '../runtime.js';
|
|
20
|
+
|
|
21
|
+
export async function mcpProxyCommand(args, io, { agentIdentity }) {
|
|
22
|
+
const baseUrl = normalizeBaseUrl(baseUrlOption(args, io.env));
|
|
23
|
+
const mcpUrl = endpointUrl(baseUrl, '/mcp');
|
|
24
|
+
const host = optionValue(args, '--host') ?? DEFAULT_PROXY_HOST;
|
|
25
|
+
const port = parsePositiveInteger(optionValue(args, '--port') ?? String(DEFAULT_PROXY_PORT), '--port');
|
|
26
|
+
const token = await resolveCredentialToken(io.env);
|
|
27
|
+
if (!token) {
|
|
28
|
+
throw new UsageError(`No token found. Run \`${COMMAND_NAME} login\` or \`${COMMAND_NAME} token add --from-stdin\` first.`);
|
|
29
|
+
}
|
|
30
|
+
validateToken(token);
|
|
31
|
+
const identity = await agentIdentity('copilot-cli', io.env);
|
|
32
|
+
|
|
33
|
+
const server = http.createServer(async (request, response) => {
|
|
34
|
+
try {
|
|
35
|
+
await handleMcpProxyRequest({ request, response, mcpUrl, token, identity, io });
|
|
36
|
+
} catch (error) {
|
|
37
|
+
response.statusCode = 502;
|
|
38
|
+
response.setHeader('content-type', 'application/json');
|
|
39
|
+
response.end(JSON.stringify({ error: 'mcp_proxy_error', message: error.message }));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
await new Promise((resolve, reject) => {
|
|
44
|
+
server.once('error', reject);
|
|
45
|
+
server.listen(port, host, () => {
|
|
46
|
+
server.off('error', reject);
|
|
47
|
+
resolve();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
writeLine(io.stdout, `${PRODUCT_NAME} MCP proxy listening on http://${host}:${port}/mcp`);
|
|
52
|
+
writeLine(io.stdout, `Forwarding to ${mcpUrl}`);
|
|
53
|
+
writeLine(io.stdout, `Credential source: ${TOKEN_ENV_VAR} or ${credentialsPath(io.env)}`);
|
|
54
|
+
if (io.keepAlive === false) {
|
|
55
|
+
await closeServer(server);
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
await waitForShutdown(server, io);
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function handleMcpProxyRequest({ request, response, mcpUrl, token, identity, io }) {
|
|
64
|
+
const requestUrl = new URL(request.url ?? '/', `http://${request.headers.host ?? `${DEFAULT_PROXY_HOST}:${DEFAULT_PROXY_PORT}`}`);
|
|
65
|
+
if (request.method !== 'POST' || requestUrl.pathname !== '/mcp') {
|
|
66
|
+
response.statusCode = 404;
|
|
67
|
+
response.setHeader('content-type', 'application/json');
|
|
68
|
+
response.end(JSON.stringify({ error: 'not_found' }));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const body = await readAll(request);
|
|
73
|
+
const upstreamHeaders = {
|
|
74
|
+
accept: String(request.headers.accept || 'application/json, text/event-stream'),
|
|
75
|
+
'content-type': String(request.headers['content-type'] || 'application/json'),
|
|
76
|
+
authorization: `Bearer ${token}`,
|
|
77
|
+
[AGENT_ID_HEADER]: identity.agentId,
|
|
78
|
+
[AGENT_INSTANCE_HEADER]: identity.agentInstanceId,
|
|
79
|
+
'user-agent': `XMemo-CLI-Proxy/${CLI_VERSION} (+https://github.com/yonro/memory-os-cli)`
|
|
80
|
+
};
|
|
81
|
+
const sessionId = request.headers['mcp-session-id'];
|
|
82
|
+
if (sessionId) {
|
|
83
|
+
upstreamHeaders['mcp-session-id'] = Array.isArray(sessionId) ? sessionId[0] : sessionId;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const upstream = await io.fetch(mcpUrl, {
|
|
87
|
+
method: 'POST',
|
|
88
|
+
headers: upstreamHeaders,
|
|
89
|
+
body
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
response.statusCode = upstream.status;
|
|
93
|
+
for (const header of ['content-type', 'mcp-session-id']) {
|
|
94
|
+
const value = upstream.headers.get(header);
|
|
95
|
+
if (value) {
|
|
96
|
+
response.setHeader(header, value);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const buffer = Buffer.from(await upstream.arrayBuffer());
|
|
100
|
+
response.end(buffer);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function baseUrlOption(args, env) {
|
|
104
|
+
return optionValue(args, '--url')
|
|
105
|
+
?? optionValue(args, '--base-url')
|
|
106
|
+
?? env.XMEMO_URL
|
|
107
|
+
?? env.XMEMO_BASE_URL
|
|
108
|
+
?? env.MEMORY_OS_URL
|
|
109
|
+
?? env.MEMORY_OS_BASE_URL
|
|
110
|
+
?? DEFAULT_SERVICE_URL;
|
|
111
|
+
}
|