@hasna/mcps 0.0.27 → 0.0.29
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/bin/index.js +126 -20
- package/bin/mcp.js +113 -17
- package/dist/index.js +112 -17
- package/dist/lib/registry.d.ts +3 -0
- package/dist/mcp/index.js +113 -17
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -12743,6 +12743,40 @@ function normalizeCandidate(value) {
|
|
|
12743
12743
|
const trimmed = value?.trim();
|
|
12744
12744
|
return trimmed ? trimmed : undefined;
|
|
12745
12745
|
}
|
|
12746
|
+
function normalizeServerTransport(value, fallback = "stdio") {
|
|
12747
|
+
if (value === undefined)
|
|
12748
|
+
return fallback;
|
|
12749
|
+
if (typeof value !== "string") {
|
|
12750
|
+
throw new Error("Invalid transport type");
|
|
12751
|
+
}
|
|
12752
|
+
const transport = value.trim();
|
|
12753
|
+
if (!transport) {
|
|
12754
|
+
throw new Error("Invalid transport type");
|
|
12755
|
+
}
|
|
12756
|
+
if (!VALID_TRANSPORTS.has(transport)) {
|
|
12757
|
+
throw new Error("Invalid transport type");
|
|
12758
|
+
}
|
|
12759
|
+
return transport;
|
|
12760
|
+
}
|
|
12761
|
+
function normalizeServerUrl(value) {
|
|
12762
|
+
if (value === null || value === undefined)
|
|
12763
|
+
return null;
|
|
12764
|
+
if (typeof value !== "string") {
|
|
12765
|
+
throw new Error("URL must be a valid HTTP(S) URL");
|
|
12766
|
+
}
|
|
12767
|
+
const trimmed = value.trim();
|
|
12768
|
+
if (!trimmed)
|
|
12769
|
+
return null;
|
|
12770
|
+
try {
|
|
12771
|
+
const parsed = new URL(trimmed);
|
|
12772
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
12773
|
+
throw new Error("unsupported protocol");
|
|
12774
|
+
}
|
|
12775
|
+
} catch {
|
|
12776
|
+
throw new Error("URL must be a valid HTTP(S) URL");
|
|
12777
|
+
}
|
|
12778
|
+
return trimmed;
|
|
12779
|
+
}
|
|
12746
12780
|
function pickNameFromArgs(args) {
|
|
12747
12781
|
if (!args || args.length === 0)
|
|
12748
12782
|
return;
|
|
@@ -12784,9 +12818,11 @@ function addServer(opts) {
|
|
|
12784
12818
|
if (!id) {
|
|
12785
12819
|
throw new Error("Unable to generate a valid server ID");
|
|
12786
12820
|
}
|
|
12821
|
+
const transport = normalizeServerTransport(opts.transport);
|
|
12822
|
+
const url = normalizeServerUrl(opts.url);
|
|
12787
12823
|
const row = db2.prepare(`INSERT INTO servers (id, name, description, command, args, env, credential_refs, transport, url, source)
|
|
12788
12824
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
12789
|
-
RETURNING *`).get(id, name, opts.description || null, command, JSON.stringify(opts.args || []), JSON.stringify(normalizeLiteralEnv(opts.env)), JSON.stringify(normalizeCredentialRefs(opts.credentialRefs)),
|
|
12825
|
+
RETURNING *`).get(id, name, opts.description || null, command, JSON.stringify(opts.args || []), JSON.stringify(normalizeLiteralEnv(opts.env)), JSON.stringify(normalizeCredentialRefs(opts.credentialRefs)), transport, url, opts.source || "local");
|
|
12790
12826
|
return parseRow(row);
|
|
12791
12827
|
}
|
|
12792
12828
|
function removeServer(id) {
|
|
@@ -12807,6 +12843,14 @@ function updateServer(id, updates) {
|
|
|
12807
12843
|
const db2 = getDb();
|
|
12808
12844
|
const sets = [];
|
|
12809
12845
|
const values = [];
|
|
12846
|
+
let nextTransport;
|
|
12847
|
+
let nextUrl;
|
|
12848
|
+
if (updates.transport !== undefined) {
|
|
12849
|
+
nextTransport = normalizeServerTransport(updates.transport);
|
|
12850
|
+
}
|
|
12851
|
+
if (updates.url !== undefined) {
|
|
12852
|
+
nextUrl = normalizeServerUrl(updates.url);
|
|
12853
|
+
}
|
|
12810
12854
|
if (updates.name !== undefined) {
|
|
12811
12855
|
const name = normalizeCandidate(updates.name);
|
|
12812
12856
|
if (!name) {
|
|
@@ -12841,11 +12885,11 @@ function updateServer(id, updates) {
|
|
|
12841
12885
|
}
|
|
12842
12886
|
if (updates.transport !== undefined) {
|
|
12843
12887
|
sets.push("transport = ?");
|
|
12844
|
-
values.push(
|
|
12888
|
+
values.push(nextTransport);
|
|
12845
12889
|
}
|
|
12846
12890
|
if (updates.url !== undefined) {
|
|
12847
12891
|
sets.push("url = ?");
|
|
12848
|
-
values.push(
|
|
12892
|
+
values.push(nextUrl ?? null);
|
|
12849
12893
|
}
|
|
12850
12894
|
if (updates.enabled !== undefined) {
|
|
12851
12895
|
sets.push("enabled = ?");
|
|
@@ -12953,9 +12997,15 @@ function getCachedTools(serverId) {
|
|
|
12953
12997
|
input_schema: safeJsonParse(r.input_schema, {})
|
|
12954
12998
|
}));
|
|
12955
12999
|
}
|
|
13000
|
+
var VALID_TRANSPORTS;
|
|
12956
13001
|
var init_registry = __esm(() => {
|
|
12957
13002
|
init_db();
|
|
12958
13003
|
init_credentials();
|
|
13004
|
+
VALID_TRANSPORTS = new Set([
|
|
13005
|
+
"stdio",
|
|
13006
|
+
"sse",
|
|
13007
|
+
"streamable-http"
|
|
13008
|
+
]);
|
|
12959
13009
|
});
|
|
12960
13010
|
|
|
12961
13011
|
// node_modules/zod/v3/helpers/util.js
|
|
@@ -34649,14 +34699,11 @@ function buildEnv(extra) {
|
|
|
34649
34699
|
return merged;
|
|
34650
34700
|
}
|
|
34651
34701
|
function requireUrl(entry) {
|
|
34652
|
-
|
|
34702
|
+
const url2 = normalizeServerUrl(entry.url);
|
|
34703
|
+
if (!url2) {
|
|
34653
34704
|
throw new Error(`Server "${entry.id}" is missing a URL for ${entry.transport} transport`);
|
|
34654
34705
|
}
|
|
34655
|
-
|
|
34656
|
-
return new URL(entry.url);
|
|
34657
|
-
} catch {
|
|
34658
|
-
throw new Error(`Server "${entry.id}" has an invalid URL: ${entry.url}`);
|
|
34659
|
-
}
|
|
34706
|
+
return new URL(url2);
|
|
34660
34707
|
}
|
|
34661
34708
|
async function connectToServer(entry, options = {}) {
|
|
34662
34709
|
if (connections.has(entry.id)) {
|
|
@@ -34688,8 +34735,10 @@ async function connectToServer(entry, options = {}) {
|
|
|
34688
34735
|
});
|
|
34689
34736
|
} else if (entry.transport === "sse") {
|
|
34690
34737
|
transport = new SSEClientTransport(requireUrl(entry));
|
|
34691
|
-
} else {
|
|
34738
|
+
} else if (entry.transport === "streamable-http") {
|
|
34692
34739
|
transport = new StreamableHTTPClientTransport(requireUrl(entry));
|
|
34740
|
+
} else {
|
|
34741
|
+
throw new Error(`Unsupported transport type for server "${entry.id}": ${entry.transport}`);
|
|
34693
34742
|
}
|
|
34694
34743
|
await client.connect(transport);
|
|
34695
34744
|
const result = await client.listTools();
|
|
@@ -35318,6 +35367,54 @@ import { execFileSync as execFileSync2 } from "child_process";
|
|
|
35318
35367
|
import { existsSync as existsSync7, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync7 } from "fs";
|
|
35319
35368
|
import { join as join10 } from "path";
|
|
35320
35369
|
import { homedir as homedir8 } from "os";
|
|
35370
|
+
function formatTomlString(value) {
|
|
35371
|
+
return JSON.stringify(value);
|
|
35372
|
+
}
|
|
35373
|
+
function formatTomlKey(key) {
|
|
35374
|
+
return /^[A-Za-z0-9_-]+$/.test(key) ? key : formatTomlString(key);
|
|
35375
|
+
}
|
|
35376
|
+
function formatTomlEnv(env) {
|
|
35377
|
+
return Object.entries(env).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${formatTomlKey(key)} = ${formatTomlString(value)}`).join(`
|
|
35378
|
+
`);
|
|
35379
|
+
}
|
|
35380
|
+
function escapeRegExp(value) {
|
|
35381
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
35382
|
+
}
|
|
35383
|
+
function codexServerHeader(id) {
|
|
35384
|
+
return `[mcp_servers.${id}]`;
|
|
35385
|
+
}
|
|
35386
|
+
function codexEnvHeader(id) {
|
|
35387
|
+
return `[mcp_servers.${id}.env]`;
|
|
35388
|
+
}
|
|
35389
|
+
function formatCodexEnvBlock(id, env) {
|
|
35390
|
+
return `
|
|
35391
|
+
${codexEnvHeader(id)}
|
|
35392
|
+
${formatTomlEnv(env)}
|
|
35393
|
+
`;
|
|
35394
|
+
}
|
|
35395
|
+
function formatCodexServerBlock(entry, env) {
|
|
35396
|
+
return `
|
|
35397
|
+
${codexServerHeader(entry.id)}
|
|
35398
|
+
` + `command = ${formatTomlString(entry.command)}
|
|
35399
|
+
` + `args = [${entry.args.map((a) => formatTomlString(a)).join(", ")}]
|
|
35400
|
+
` + (Object.keys(env).length > 0 ? formatCodexEnvBlock(entry.id, env) : "");
|
|
35401
|
+
}
|
|
35402
|
+
function upsertCodexEnvBlock(config2, id, env) {
|
|
35403
|
+
const envBlock = formatCodexEnvBlock(id, env);
|
|
35404
|
+
const envHeaderPattern = escapeRegExp(codexEnvHeader(id));
|
|
35405
|
+
const envBlockPattern = new RegExp(`(?:\\r?\\n)?[ \\t]*${envHeaderPattern}[ \\t]*\\r?\\n[\\s\\S]*?(?=\\r?\\n[ \\t]*\\[|\\s*$)`);
|
|
35406
|
+
if (envBlockPattern.test(config2)) {
|
|
35407
|
+
return config2.replace(envBlockPattern, () => envBlock);
|
|
35408
|
+
}
|
|
35409
|
+
const serverHeaderPattern = escapeRegExp(codexServerHeader(id));
|
|
35410
|
+
const serverBlockPattern = new RegExp(`([ \\t]*${serverHeaderPattern}[ \\t]*\\r?\\n[\\s\\S]*?)(?=\\r?\\n[ \\t]*\\[|\\s*$)`);
|
|
35411
|
+
let inserted = false;
|
|
35412
|
+
const updated = config2.replace(serverBlockPattern, (_match, serverBlock) => {
|
|
35413
|
+
inserted = true;
|
|
35414
|
+
return `${serverBlock}${envBlock}`;
|
|
35415
|
+
});
|
|
35416
|
+
return inserted ? updated : `${config2}${envBlock}`;
|
|
35417
|
+
}
|
|
35321
35418
|
function installToClaude(entry) {
|
|
35322
35419
|
try {
|
|
35323
35420
|
const args = [
|
|
@@ -35345,16 +35442,15 @@ function installToCodex(entry) {
|
|
|
35345
35442
|
if (!existsSync7(configDir)) {
|
|
35346
35443
|
mkdirSync7(configDir, { recursive: true });
|
|
35347
35444
|
}
|
|
35348
|
-
const
|
|
35349
|
-
[mcp_servers.${entry.id}]
|
|
35350
|
-
` + `command = ${JSON.stringify(entry.command)}
|
|
35351
|
-
` + `args = [${entry.args.map((a) => JSON.stringify(a)).join(", ")}]
|
|
35352
|
-
`;
|
|
35445
|
+
const env = assertAgentInstallEnv(entry);
|
|
35353
35446
|
const existing = existsSync7(configPath) ? readFileSync4(configPath, "utf-8") : "";
|
|
35354
|
-
if (existing.includes(
|
|
35447
|
+
if (existing.includes(codexServerHeader(entry.id))) {
|
|
35448
|
+
if (Object.keys(env).length > 0) {
|
|
35449
|
+
writeFileSync3(configPath, upsertCodexEnvBlock(existing, entry.id, env), "utf-8");
|
|
35450
|
+
}
|
|
35355
35451
|
return { agent: "codex", success: true };
|
|
35356
35452
|
}
|
|
35357
|
-
writeFileSync3(configPath, existing +
|
|
35453
|
+
writeFileSync3(configPath, existing + formatCodexServerBlock(entry, env), "utf-8");
|
|
35358
35454
|
return { agent: "codex", success: true };
|
|
35359
35455
|
} catch (err) {
|
|
35360
35456
|
return { agent: "codex", success: false, error: err.message };
|
|
@@ -36454,7 +36550,7 @@ var init_provider_profiles = __esm(() => {
|
|
|
36454
36550
|
var require_package = __commonJS((exports, module) => {
|
|
36455
36551
|
module.exports = {
|
|
36456
36552
|
name: "@hasna/mcps",
|
|
36457
|
-
version: "0.0.
|
|
36553
|
+
version: "0.0.29",
|
|
36458
36554
|
description: "Meta-MCP registry & CLI \u2014 discover, manage, and proxy MCP servers",
|
|
36459
36555
|
type: "module",
|
|
36460
36556
|
repository: {
|
|
@@ -45430,6 +45526,16 @@ program2.command("import").argument("<file>", "Path to the export JSON file").de
|
|
|
45430
45526
|
}
|
|
45431
45527
|
const literalEnv = normalizeLiteralEnv(s.env ?? {});
|
|
45432
45528
|
const credentialRefs = normalizeCredentialRefs(s.credentialRefs ?? s.credential_refs ?? {});
|
|
45529
|
+
let transport;
|
|
45530
|
+
let url2;
|
|
45531
|
+
try {
|
|
45532
|
+
transport = normalizeServerTransport(s.transport);
|
|
45533
|
+
url2 = normalizeServerUrl(s.url);
|
|
45534
|
+
} catch (err) {
|
|
45535
|
+
console.error(chalk2.red(`Invalid server in import "${s.id ?? "(unknown)"}": ${err.message}`));
|
|
45536
|
+
closeDb();
|
|
45537
|
+
process.exit(1);
|
|
45538
|
+
}
|
|
45433
45539
|
db2.run(`INSERT ${orReplace} INTO servers (id, name, description, command, args, env, credential_refs, transport, url, source, enabled, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)`, [
|
|
45434
45540
|
s.id,
|
|
45435
45541
|
s.name,
|
|
@@ -45438,8 +45544,8 @@ program2.command("import").argument("<file>", "Path to the export JSON file").de
|
|
|
45438
45544
|
JSON.stringify(s.args ?? []),
|
|
45439
45545
|
JSON.stringify(literalEnv),
|
|
45440
45546
|
JSON.stringify(credentialRefs),
|
|
45441
|
-
|
|
45442
|
-
|
|
45547
|
+
transport,
|
|
45548
|
+
url2,
|
|
45443
45549
|
s.source,
|
|
45444
45550
|
s.enabled ? 1 : 0,
|
|
45445
45551
|
s.created_at,
|
package/bin/mcp.js
CHANGED
|
@@ -30759,6 +30759,40 @@ function normalizeCandidate(value) {
|
|
|
30759
30759
|
const trimmed = value?.trim();
|
|
30760
30760
|
return trimmed ? trimmed : undefined;
|
|
30761
30761
|
}
|
|
30762
|
+
function normalizeServerTransport(value, fallback = "stdio") {
|
|
30763
|
+
if (value === undefined)
|
|
30764
|
+
return fallback;
|
|
30765
|
+
if (typeof value !== "string") {
|
|
30766
|
+
throw new Error("Invalid transport type");
|
|
30767
|
+
}
|
|
30768
|
+
const transport = value.trim();
|
|
30769
|
+
if (!transport) {
|
|
30770
|
+
throw new Error("Invalid transport type");
|
|
30771
|
+
}
|
|
30772
|
+
if (!VALID_TRANSPORTS.has(transport)) {
|
|
30773
|
+
throw new Error("Invalid transport type");
|
|
30774
|
+
}
|
|
30775
|
+
return transport;
|
|
30776
|
+
}
|
|
30777
|
+
function normalizeServerUrl(value) {
|
|
30778
|
+
if (value === null || value === undefined)
|
|
30779
|
+
return null;
|
|
30780
|
+
if (typeof value !== "string") {
|
|
30781
|
+
throw new Error("URL must be a valid HTTP(S) URL");
|
|
30782
|
+
}
|
|
30783
|
+
const trimmed = value.trim();
|
|
30784
|
+
if (!trimmed)
|
|
30785
|
+
return null;
|
|
30786
|
+
try {
|
|
30787
|
+
const parsed = new URL(trimmed);
|
|
30788
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
30789
|
+
throw new Error("unsupported protocol");
|
|
30790
|
+
}
|
|
30791
|
+
} catch {
|
|
30792
|
+
throw new Error("URL must be a valid HTTP(S) URL");
|
|
30793
|
+
}
|
|
30794
|
+
return trimmed;
|
|
30795
|
+
}
|
|
30762
30796
|
function pickNameFromArgs(args) {
|
|
30763
30797
|
if (!args || args.length === 0)
|
|
30764
30798
|
return;
|
|
@@ -30800,9 +30834,11 @@ function addServer(opts) {
|
|
|
30800
30834
|
if (!id) {
|
|
30801
30835
|
throw new Error("Unable to generate a valid server ID");
|
|
30802
30836
|
}
|
|
30837
|
+
const transport = normalizeServerTransport(opts.transport);
|
|
30838
|
+
const url2 = normalizeServerUrl(opts.url);
|
|
30803
30839
|
const row = db2.prepare(`INSERT INTO servers (id, name, description, command, args, env, credential_refs, transport, url, source)
|
|
30804
30840
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
30805
|
-
RETURNING *`).get(id, name, opts.description || null, command, JSON.stringify(opts.args || []), JSON.stringify(normalizeLiteralEnv(opts.env)), JSON.stringify(normalizeCredentialRefs(opts.credentialRefs)),
|
|
30841
|
+
RETURNING *`).get(id, name, opts.description || null, command, JSON.stringify(opts.args || []), JSON.stringify(normalizeLiteralEnv(opts.env)), JSON.stringify(normalizeCredentialRefs(opts.credentialRefs)), transport, url2, opts.source || "local");
|
|
30806
30842
|
return parseRow(row);
|
|
30807
30843
|
}
|
|
30808
30844
|
function removeServer(id) {
|
|
@@ -30823,6 +30859,14 @@ function updateServer(id, updates) {
|
|
|
30823
30859
|
const db2 = getDb();
|
|
30824
30860
|
const sets = [];
|
|
30825
30861
|
const values = [];
|
|
30862
|
+
let nextTransport;
|
|
30863
|
+
let nextUrl;
|
|
30864
|
+
if (updates.transport !== undefined) {
|
|
30865
|
+
nextTransport = normalizeServerTransport(updates.transport);
|
|
30866
|
+
}
|
|
30867
|
+
if (updates.url !== undefined) {
|
|
30868
|
+
nextUrl = normalizeServerUrl(updates.url);
|
|
30869
|
+
}
|
|
30826
30870
|
if (updates.name !== undefined) {
|
|
30827
30871
|
const name = normalizeCandidate(updates.name);
|
|
30828
30872
|
if (!name) {
|
|
@@ -30857,11 +30901,11 @@ function updateServer(id, updates) {
|
|
|
30857
30901
|
}
|
|
30858
30902
|
if (updates.transport !== undefined) {
|
|
30859
30903
|
sets.push("transport = ?");
|
|
30860
|
-
values.push(
|
|
30904
|
+
values.push(nextTransport);
|
|
30861
30905
|
}
|
|
30862
30906
|
if (updates.url !== undefined) {
|
|
30863
30907
|
sets.push("url = ?");
|
|
30864
|
-
values.push(
|
|
30908
|
+
values.push(nextUrl ?? null);
|
|
30865
30909
|
}
|
|
30866
30910
|
if (updates.enabled !== undefined) {
|
|
30867
30911
|
sets.push("enabled = ?");
|
|
@@ -30914,9 +30958,15 @@ function getCachedTools(serverId) {
|
|
|
30914
30958
|
input_schema: safeJsonParse(r.input_schema, {})
|
|
30915
30959
|
}));
|
|
30916
30960
|
}
|
|
30961
|
+
var VALID_TRANSPORTS;
|
|
30917
30962
|
var init_registry = __esm(() => {
|
|
30918
30963
|
init_db();
|
|
30919
30964
|
init_credentials();
|
|
30965
|
+
VALID_TRANSPORTS = new Set([
|
|
30966
|
+
"stdio",
|
|
30967
|
+
"sse",
|
|
30968
|
+
"streamable-http"
|
|
30969
|
+
]);
|
|
30920
30970
|
});
|
|
30921
30971
|
|
|
30922
30972
|
// src/lib/local-command-consent.ts
|
|
@@ -31484,6 +31534,54 @@ import { execFileSync } from "child_process";
|
|
|
31484
31534
|
import { existsSync as existsSync10, readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync7 } from "fs";
|
|
31485
31535
|
import { join as join11 } from "path";
|
|
31486
31536
|
import { homedir as homedir8 } from "os";
|
|
31537
|
+
function formatTomlString(value) {
|
|
31538
|
+
return JSON.stringify(value);
|
|
31539
|
+
}
|
|
31540
|
+
function formatTomlKey(key) {
|
|
31541
|
+
return /^[A-Za-z0-9_-]+$/.test(key) ? key : formatTomlString(key);
|
|
31542
|
+
}
|
|
31543
|
+
function formatTomlEnv(env) {
|
|
31544
|
+
return Object.entries(env).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${formatTomlKey(key)} = ${formatTomlString(value)}`).join(`
|
|
31545
|
+
`);
|
|
31546
|
+
}
|
|
31547
|
+
function escapeRegExp(value) {
|
|
31548
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
31549
|
+
}
|
|
31550
|
+
function codexServerHeader(id) {
|
|
31551
|
+
return `[mcp_servers.${id}]`;
|
|
31552
|
+
}
|
|
31553
|
+
function codexEnvHeader(id) {
|
|
31554
|
+
return `[mcp_servers.${id}.env]`;
|
|
31555
|
+
}
|
|
31556
|
+
function formatCodexEnvBlock(id, env) {
|
|
31557
|
+
return `
|
|
31558
|
+
${codexEnvHeader(id)}
|
|
31559
|
+
${formatTomlEnv(env)}
|
|
31560
|
+
`;
|
|
31561
|
+
}
|
|
31562
|
+
function formatCodexServerBlock(entry, env) {
|
|
31563
|
+
return `
|
|
31564
|
+
${codexServerHeader(entry.id)}
|
|
31565
|
+
` + `command = ${formatTomlString(entry.command)}
|
|
31566
|
+
` + `args = [${entry.args.map((a) => formatTomlString(a)).join(", ")}]
|
|
31567
|
+
` + (Object.keys(env).length > 0 ? formatCodexEnvBlock(entry.id, env) : "");
|
|
31568
|
+
}
|
|
31569
|
+
function upsertCodexEnvBlock(config2, id, env) {
|
|
31570
|
+
const envBlock = formatCodexEnvBlock(id, env);
|
|
31571
|
+
const envHeaderPattern = escapeRegExp(codexEnvHeader(id));
|
|
31572
|
+
const envBlockPattern = new RegExp(`(?:\\r?\\n)?[ \\t]*${envHeaderPattern}[ \\t]*\\r?\\n[\\s\\S]*?(?=\\r?\\n[ \\t]*\\[|\\s*$)`);
|
|
31573
|
+
if (envBlockPattern.test(config2)) {
|
|
31574
|
+
return config2.replace(envBlockPattern, () => envBlock);
|
|
31575
|
+
}
|
|
31576
|
+
const serverHeaderPattern = escapeRegExp(codexServerHeader(id));
|
|
31577
|
+
const serverBlockPattern = new RegExp(`([ \\t]*${serverHeaderPattern}[ \\t]*\\r?\\n[\\s\\S]*?)(?=\\r?\\n[ \\t]*\\[|\\s*$)`);
|
|
31578
|
+
let inserted = false;
|
|
31579
|
+
const updated = config2.replace(serverBlockPattern, (_match, serverBlock) => {
|
|
31580
|
+
inserted = true;
|
|
31581
|
+
return `${serverBlock}${envBlock}`;
|
|
31582
|
+
});
|
|
31583
|
+
return inserted ? updated : `${config2}${envBlock}`;
|
|
31584
|
+
}
|
|
31487
31585
|
function installToClaude(entry) {
|
|
31488
31586
|
try {
|
|
31489
31587
|
const args = [
|
|
@@ -31511,16 +31609,15 @@ function installToCodex(entry) {
|
|
|
31511
31609
|
if (!existsSync10(configDir)) {
|
|
31512
31610
|
mkdirSync7(configDir, { recursive: true });
|
|
31513
31611
|
}
|
|
31514
|
-
const
|
|
31515
|
-
[mcp_servers.${entry.id}]
|
|
31516
|
-
` + `command = ${JSON.stringify(entry.command)}
|
|
31517
|
-
` + `args = [${entry.args.map((a) => JSON.stringify(a)).join(", ")}]
|
|
31518
|
-
`;
|
|
31612
|
+
const env = assertAgentInstallEnv(entry);
|
|
31519
31613
|
const existing = existsSync10(configPath) ? readFileSync5(configPath, "utf-8") : "";
|
|
31520
|
-
if (existing.includes(
|
|
31614
|
+
if (existing.includes(codexServerHeader(entry.id))) {
|
|
31615
|
+
if (Object.keys(env).length > 0) {
|
|
31616
|
+
writeFileSync3(configPath, upsertCodexEnvBlock(existing, entry.id, env), "utf-8");
|
|
31617
|
+
}
|
|
31521
31618
|
return { agent: "codex", success: true };
|
|
31522
31619
|
}
|
|
31523
|
-
writeFileSync3(configPath, existing +
|
|
31620
|
+
writeFileSync3(configPath, existing + formatCodexServerBlock(entry, env), "utf-8");
|
|
31524
31621
|
return { agent: "codex", success: true };
|
|
31525
31622
|
} catch (err) {
|
|
31526
31623
|
return { agent: "codex", success: false, error: err.message };
|
|
@@ -34452,14 +34549,11 @@ function buildEnv(extra) {
|
|
|
34452
34549
|
return merged;
|
|
34453
34550
|
}
|
|
34454
34551
|
function requireUrl(entry) {
|
|
34455
|
-
|
|
34552
|
+
const url2 = normalizeServerUrl(entry.url);
|
|
34553
|
+
if (!url2) {
|
|
34456
34554
|
throw new Error(`Server "${entry.id}" is missing a URL for ${entry.transport} transport`);
|
|
34457
34555
|
}
|
|
34458
|
-
|
|
34459
|
-
return new URL(entry.url);
|
|
34460
|
-
} catch {
|
|
34461
|
-
throw new Error(`Server "${entry.id}" has an invalid URL: ${entry.url}`);
|
|
34462
|
-
}
|
|
34556
|
+
return new URL(url2);
|
|
34463
34557
|
}
|
|
34464
34558
|
async function connectToServer(entry, options = {}) {
|
|
34465
34559
|
if (connections.has(entry.id)) {
|
|
@@ -34491,8 +34585,10 @@ async function connectToServer(entry, options = {}) {
|
|
|
34491
34585
|
});
|
|
34492
34586
|
} else if (entry.transport === "sse") {
|
|
34493
34587
|
transport = new SSEClientTransport(requireUrl(entry));
|
|
34494
|
-
} else {
|
|
34588
|
+
} else if (entry.transport === "streamable-http") {
|
|
34495
34589
|
transport = new StreamableHTTPClientTransport(requireUrl(entry));
|
|
34590
|
+
} else {
|
|
34591
|
+
throw new Error(`Unsupported transport type for server "${entry.id}": ${entry.transport}`);
|
|
34496
34592
|
}
|
|
34497
34593
|
await client.connect(transport);
|
|
34498
34594
|
const result = await client.listTools();
|
package/dist/index.js
CHANGED
|
@@ -17441,6 +17441,11 @@ function credentialRefPlaceholders(refs) {
|
|
|
17441
17441
|
}
|
|
17442
17442
|
|
|
17443
17443
|
// src/lib/registry.ts
|
|
17444
|
+
var VALID_TRANSPORTS = new Set([
|
|
17445
|
+
"stdio",
|
|
17446
|
+
"sse",
|
|
17447
|
+
"streamable-http"
|
|
17448
|
+
]);
|
|
17444
17449
|
function parseRow(row) {
|
|
17445
17450
|
return {
|
|
17446
17451
|
id: row.id,
|
|
@@ -17476,6 +17481,40 @@ function normalizeCandidate(value) {
|
|
|
17476
17481
|
const trimmed = value?.trim();
|
|
17477
17482
|
return trimmed ? trimmed : undefined;
|
|
17478
17483
|
}
|
|
17484
|
+
function normalizeServerTransport(value, fallback = "stdio") {
|
|
17485
|
+
if (value === undefined)
|
|
17486
|
+
return fallback;
|
|
17487
|
+
if (typeof value !== "string") {
|
|
17488
|
+
throw new Error("Invalid transport type");
|
|
17489
|
+
}
|
|
17490
|
+
const transport = value.trim();
|
|
17491
|
+
if (!transport) {
|
|
17492
|
+
throw new Error("Invalid transport type");
|
|
17493
|
+
}
|
|
17494
|
+
if (!VALID_TRANSPORTS.has(transport)) {
|
|
17495
|
+
throw new Error("Invalid transport type");
|
|
17496
|
+
}
|
|
17497
|
+
return transport;
|
|
17498
|
+
}
|
|
17499
|
+
function normalizeServerUrl(value) {
|
|
17500
|
+
if (value === null || value === undefined)
|
|
17501
|
+
return null;
|
|
17502
|
+
if (typeof value !== "string") {
|
|
17503
|
+
throw new Error("URL must be a valid HTTP(S) URL");
|
|
17504
|
+
}
|
|
17505
|
+
const trimmed = value.trim();
|
|
17506
|
+
if (!trimmed)
|
|
17507
|
+
return null;
|
|
17508
|
+
try {
|
|
17509
|
+
const parsed = new URL(trimmed);
|
|
17510
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
17511
|
+
throw new Error("unsupported protocol");
|
|
17512
|
+
}
|
|
17513
|
+
} catch {
|
|
17514
|
+
throw new Error("URL must be a valid HTTP(S) URL");
|
|
17515
|
+
}
|
|
17516
|
+
return trimmed;
|
|
17517
|
+
}
|
|
17479
17518
|
function pickNameFromArgs(args) {
|
|
17480
17519
|
if (!args || args.length === 0)
|
|
17481
17520
|
return;
|
|
@@ -17517,9 +17556,11 @@ function addServer(opts) {
|
|
|
17517
17556
|
if (!id) {
|
|
17518
17557
|
throw new Error("Unable to generate a valid server ID");
|
|
17519
17558
|
}
|
|
17559
|
+
const transport = normalizeServerTransport(opts.transport);
|
|
17560
|
+
const url = normalizeServerUrl(opts.url);
|
|
17520
17561
|
const row = db2.prepare(`INSERT INTO servers (id, name, description, command, args, env, credential_refs, transport, url, source)
|
|
17521
17562
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
17522
|
-
RETURNING *`).get(id, name, opts.description || null, command, JSON.stringify(opts.args || []), JSON.stringify(normalizeLiteralEnv(opts.env)), JSON.stringify(normalizeCredentialRefs(opts.credentialRefs)),
|
|
17563
|
+
RETURNING *`).get(id, name, opts.description || null, command, JSON.stringify(opts.args || []), JSON.stringify(normalizeLiteralEnv(opts.env)), JSON.stringify(normalizeCredentialRefs(opts.credentialRefs)), transport, url, opts.source || "local");
|
|
17523
17564
|
return parseRow(row);
|
|
17524
17565
|
}
|
|
17525
17566
|
function removeServer(id) {
|
|
@@ -17540,6 +17581,14 @@ function updateServer(id, updates) {
|
|
|
17540
17581
|
const db2 = getDb();
|
|
17541
17582
|
const sets = [];
|
|
17542
17583
|
const values = [];
|
|
17584
|
+
let nextTransport;
|
|
17585
|
+
let nextUrl;
|
|
17586
|
+
if (updates.transport !== undefined) {
|
|
17587
|
+
nextTransport = normalizeServerTransport(updates.transport);
|
|
17588
|
+
}
|
|
17589
|
+
if (updates.url !== undefined) {
|
|
17590
|
+
nextUrl = normalizeServerUrl(updates.url);
|
|
17591
|
+
}
|
|
17543
17592
|
if (updates.name !== undefined) {
|
|
17544
17593
|
const name = normalizeCandidate(updates.name);
|
|
17545
17594
|
if (!name) {
|
|
@@ -17574,11 +17623,11 @@ function updateServer(id, updates) {
|
|
|
17574
17623
|
}
|
|
17575
17624
|
if (updates.transport !== undefined) {
|
|
17576
17625
|
sets.push("transport = ?");
|
|
17577
|
-
values.push(
|
|
17626
|
+
values.push(nextTransport);
|
|
17578
17627
|
}
|
|
17579
17628
|
if (updates.url !== undefined) {
|
|
17580
17629
|
sets.push("url = ?");
|
|
17581
|
-
values.push(
|
|
17630
|
+
values.push(nextUrl ?? null);
|
|
17582
17631
|
}
|
|
17583
17632
|
if (updates.enabled !== undefined) {
|
|
17584
17633
|
sets.push("enabled = ?");
|
|
@@ -25998,14 +26047,11 @@ function buildEnv(extra) {
|
|
|
25998
26047
|
return merged;
|
|
25999
26048
|
}
|
|
26000
26049
|
function requireUrl(entry) {
|
|
26001
|
-
|
|
26050
|
+
const url2 = normalizeServerUrl(entry.url);
|
|
26051
|
+
if (!url2) {
|
|
26002
26052
|
throw new Error(`Server "${entry.id}" is missing a URL for ${entry.transport} transport`);
|
|
26003
26053
|
}
|
|
26004
|
-
|
|
26005
|
-
return new URL(entry.url);
|
|
26006
|
-
} catch {
|
|
26007
|
-
throw new Error(`Server "${entry.id}" has an invalid URL: ${entry.url}`);
|
|
26008
|
-
}
|
|
26054
|
+
return new URL(url2);
|
|
26009
26055
|
}
|
|
26010
26056
|
async function connectToServer(entry, options = {}) {
|
|
26011
26057
|
if (connections.has(entry.id)) {
|
|
@@ -26037,8 +26083,10 @@ async function connectToServer(entry, options = {}) {
|
|
|
26037
26083
|
});
|
|
26038
26084
|
} else if (entry.transport === "sse") {
|
|
26039
26085
|
transport = new SSEClientTransport(requireUrl(entry));
|
|
26040
|
-
} else {
|
|
26086
|
+
} else if (entry.transport === "streamable-http") {
|
|
26041
26087
|
transport = new StreamableHTTPClientTransport(requireUrl(entry));
|
|
26088
|
+
} else {
|
|
26089
|
+
throw new Error(`Unsupported transport type for server "${entry.id}": ${entry.transport}`);
|
|
26042
26090
|
}
|
|
26043
26091
|
await client.connect(transport);
|
|
26044
26092
|
const result = await client.listTools();
|
|
@@ -26586,6 +26634,54 @@ import { execFileSync as execFileSync2 } from "child_process";
|
|
|
26586
26634
|
import { existsSync as existsSync9, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync7 } from "fs";
|
|
26587
26635
|
import { join as join10 } from "path";
|
|
26588
26636
|
import { homedir as homedir8 } from "os";
|
|
26637
|
+
function formatTomlString(value) {
|
|
26638
|
+
return JSON.stringify(value);
|
|
26639
|
+
}
|
|
26640
|
+
function formatTomlKey(key) {
|
|
26641
|
+
return /^[A-Za-z0-9_-]+$/.test(key) ? key : formatTomlString(key);
|
|
26642
|
+
}
|
|
26643
|
+
function formatTomlEnv(env) {
|
|
26644
|
+
return Object.entries(env).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${formatTomlKey(key)} = ${formatTomlString(value)}`).join(`
|
|
26645
|
+
`);
|
|
26646
|
+
}
|
|
26647
|
+
function escapeRegExp(value) {
|
|
26648
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26649
|
+
}
|
|
26650
|
+
function codexServerHeader(id) {
|
|
26651
|
+
return `[mcp_servers.${id}]`;
|
|
26652
|
+
}
|
|
26653
|
+
function codexEnvHeader(id) {
|
|
26654
|
+
return `[mcp_servers.${id}.env]`;
|
|
26655
|
+
}
|
|
26656
|
+
function formatCodexEnvBlock(id, env) {
|
|
26657
|
+
return `
|
|
26658
|
+
${codexEnvHeader(id)}
|
|
26659
|
+
${formatTomlEnv(env)}
|
|
26660
|
+
`;
|
|
26661
|
+
}
|
|
26662
|
+
function formatCodexServerBlock(entry, env) {
|
|
26663
|
+
return `
|
|
26664
|
+
${codexServerHeader(entry.id)}
|
|
26665
|
+
` + `command = ${formatTomlString(entry.command)}
|
|
26666
|
+
` + `args = [${entry.args.map((a) => formatTomlString(a)).join(", ")}]
|
|
26667
|
+
` + (Object.keys(env).length > 0 ? formatCodexEnvBlock(entry.id, env) : "");
|
|
26668
|
+
}
|
|
26669
|
+
function upsertCodexEnvBlock(config2, id, env) {
|
|
26670
|
+
const envBlock = formatCodexEnvBlock(id, env);
|
|
26671
|
+
const envHeaderPattern = escapeRegExp(codexEnvHeader(id));
|
|
26672
|
+
const envBlockPattern = new RegExp(`(?:\\r?\\n)?[ \\t]*${envHeaderPattern}[ \\t]*\\r?\\n[\\s\\S]*?(?=\\r?\\n[ \\t]*\\[|\\s*$)`);
|
|
26673
|
+
if (envBlockPattern.test(config2)) {
|
|
26674
|
+
return config2.replace(envBlockPattern, () => envBlock);
|
|
26675
|
+
}
|
|
26676
|
+
const serverHeaderPattern = escapeRegExp(codexServerHeader(id));
|
|
26677
|
+
const serverBlockPattern = new RegExp(`([ \\t]*${serverHeaderPattern}[ \\t]*\\r?\\n[\\s\\S]*?)(?=\\r?\\n[ \\t]*\\[|\\s*$)`);
|
|
26678
|
+
let inserted = false;
|
|
26679
|
+
const updated = config2.replace(serverBlockPattern, (_match, serverBlock) => {
|
|
26680
|
+
inserted = true;
|
|
26681
|
+
return `${serverBlock}${envBlock}`;
|
|
26682
|
+
});
|
|
26683
|
+
return inserted ? updated : `${config2}${envBlock}`;
|
|
26684
|
+
}
|
|
26589
26685
|
function installToClaude(entry) {
|
|
26590
26686
|
try {
|
|
26591
26687
|
const args = [
|
|
@@ -26613,16 +26709,15 @@ function installToCodex(entry) {
|
|
|
26613
26709
|
if (!existsSync9(configDir)) {
|
|
26614
26710
|
mkdirSync7(configDir, { recursive: true });
|
|
26615
26711
|
}
|
|
26616
|
-
const
|
|
26617
|
-
[mcp_servers.${entry.id}]
|
|
26618
|
-
` + `command = ${JSON.stringify(entry.command)}
|
|
26619
|
-
` + `args = [${entry.args.map((a) => JSON.stringify(a)).join(", ")}]
|
|
26620
|
-
`;
|
|
26712
|
+
const env = assertAgentInstallEnv(entry);
|
|
26621
26713
|
const existing = existsSync9(configPath) ? readFileSync4(configPath, "utf-8") : "";
|
|
26622
|
-
if (existing.includes(
|
|
26714
|
+
if (existing.includes(codexServerHeader(entry.id))) {
|
|
26715
|
+
if (Object.keys(env).length > 0) {
|
|
26716
|
+
writeFileSync3(configPath, upsertCodexEnvBlock(existing, entry.id, env), "utf-8");
|
|
26717
|
+
}
|
|
26623
26718
|
return { agent: "codex", success: true };
|
|
26624
26719
|
}
|
|
26625
|
-
writeFileSync3(configPath, existing +
|
|
26720
|
+
writeFileSync3(configPath, existing + formatCodexServerBlock(entry, env), "utf-8");
|
|
26626
26721
|
return { agent: "codex", success: true };
|
|
26627
26722
|
} catch (err) {
|
|
26628
26723
|
return { agent: "codex", success: false, error: err.message };
|
package/dist/lib/registry.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { CredentialReference, McpServerEntry, AddServerOptions } from "../types.js";
|
|
2
|
+
export declare const VALID_TRANSPORTS: Set<"stdio" | "sse" | "streamable-http">;
|
|
3
|
+
export declare function normalizeServerTransport(value: unknown, fallback?: McpServerEntry["transport"]): McpServerEntry["transport"];
|
|
4
|
+
export declare function normalizeServerUrl(value: unknown): string | null;
|
|
2
5
|
export declare function addServer(opts: AddServerOptions): McpServerEntry;
|
|
3
6
|
export declare function removeServer(id: string): void;
|
|
4
7
|
export declare function listServers(): McpServerEntry[];
|
package/dist/mcp/index.js
CHANGED
|
@@ -30759,6 +30759,40 @@ function normalizeCandidate(value) {
|
|
|
30759
30759
|
const trimmed = value?.trim();
|
|
30760
30760
|
return trimmed ? trimmed : undefined;
|
|
30761
30761
|
}
|
|
30762
|
+
function normalizeServerTransport(value, fallback = "stdio") {
|
|
30763
|
+
if (value === undefined)
|
|
30764
|
+
return fallback;
|
|
30765
|
+
if (typeof value !== "string") {
|
|
30766
|
+
throw new Error("Invalid transport type");
|
|
30767
|
+
}
|
|
30768
|
+
const transport = value.trim();
|
|
30769
|
+
if (!transport) {
|
|
30770
|
+
throw new Error("Invalid transport type");
|
|
30771
|
+
}
|
|
30772
|
+
if (!VALID_TRANSPORTS.has(transport)) {
|
|
30773
|
+
throw new Error("Invalid transport type");
|
|
30774
|
+
}
|
|
30775
|
+
return transport;
|
|
30776
|
+
}
|
|
30777
|
+
function normalizeServerUrl(value) {
|
|
30778
|
+
if (value === null || value === undefined)
|
|
30779
|
+
return null;
|
|
30780
|
+
if (typeof value !== "string") {
|
|
30781
|
+
throw new Error("URL must be a valid HTTP(S) URL");
|
|
30782
|
+
}
|
|
30783
|
+
const trimmed = value.trim();
|
|
30784
|
+
if (!trimmed)
|
|
30785
|
+
return null;
|
|
30786
|
+
try {
|
|
30787
|
+
const parsed = new URL(trimmed);
|
|
30788
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
30789
|
+
throw new Error("unsupported protocol");
|
|
30790
|
+
}
|
|
30791
|
+
} catch {
|
|
30792
|
+
throw new Error("URL must be a valid HTTP(S) URL");
|
|
30793
|
+
}
|
|
30794
|
+
return trimmed;
|
|
30795
|
+
}
|
|
30762
30796
|
function pickNameFromArgs(args) {
|
|
30763
30797
|
if (!args || args.length === 0)
|
|
30764
30798
|
return;
|
|
@@ -30800,9 +30834,11 @@ function addServer(opts) {
|
|
|
30800
30834
|
if (!id) {
|
|
30801
30835
|
throw new Error("Unable to generate a valid server ID");
|
|
30802
30836
|
}
|
|
30837
|
+
const transport = normalizeServerTransport(opts.transport);
|
|
30838
|
+
const url2 = normalizeServerUrl(opts.url);
|
|
30803
30839
|
const row = db2.prepare(`INSERT INTO servers (id, name, description, command, args, env, credential_refs, transport, url, source)
|
|
30804
30840
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
30805
|
-
RETURNING *`).get(id, name, opts.description || null, command, JSON.stringify(opts.args || []), JSON.stringify(normalizeLiteralEnv(opts.env)), JSON.stringify(normalizeCredentialRefs(opts.credentialRefs)),
|
|
30841
|
+
RETURNING *`).get(id, name, opts.description || null, command, JSON.stringify(opts.args || []), JSON.stringify(normalizeLiteralEnv(opts.env)), JSON.stringify(normalizeCredentialRefs(opts.credentialRefs)), transport, url2, opts.source || "local");
|
|
30806
30842
|
return parseRow(row);
|
|
30807
30843
|
}
|
|
30808
30844
|
function removeServer(id) {
|
|
@@ -30823,6 +30859,14 @@ function updateServer(id, updates) {
|
|
|
30823
30859
|
const db2 = getDb();
|
|
30824
30860
|
const sets = [];
|
|
30825
30861
|
const values = [];
|
|
30862
|
+
let nextTransport;
|
|
30863
|
+
let nextUrl;
|
|
30864
|
+
if (updates.transport !== undefined) {
|
|
30865
|
+
nextTransport = normalizeServerTransport(updates.transport);
|
|
30866
|
+
}
|
|
30867
|
+
if (updates.url !== undefined) {
|
|
30868
|
+
nextUrl = normalizeServerUrl(updates.url);
|
|
30869
|
+
}
|
|
30826
30870
|
if (updates.name !== undefined) {
|
|
30827
30871
|
const name = normalizeCandidate(updates.name);
|
|
30828
30872
|
if (!name) {
|
|
@@ -30857,11 +30901,11 @@ function updateServer(id, updates) {
|
|
|
30857
30901
|
}
|
|
30858
30902
|
if (updates.transport !== undefined) {
|
|
30859
30903
|
sets.push("transport = ?");
|
|
30860
|
-
values.push(
|
|
30904
|
+
values.push(nextTransport);
|
|
30861
30905
|
}
|
|
30862
30906
|
if (updates.url !== undefined) {
|
|
30863
30907
|
sets.push("url = ?");
|
|
30864
|
-
values.push(
|
|
30908
|
+
values.push(nextUrl ?? null);
|
|
30865
30909
|
}
|
|
30866
30910
|
if (updates.enabled !== undefined) {
|
|
30867
30911
|
sets.push("enabled = ?");
|
|
@@ -30914,9 +30958,15 @@ function getCachedTools(serverId) {
|
|
|
30914
30958
|
input_schema: safeJsonParse(r.input_schema, {})
|
|
30915
30959
|
}));
|
|
30916
30960
|
}
|
|
30961
|
+
var VALID_TRANSPORTS;
|
|
30917
30962
|
var init_registry = __esm(() => {
|
|
30918
30963
|
init_db();
|
|
30919
30964
|
init_credentials();
|
|
30965
|
+
VALID_TRANSPORTS = new Set([
|
|
30966
|
+
"stdio",
|
|
30967
|
+
"sse",
|
|
30968
|
+
"streamable-http"
|
|
30969
|
+
]);
|
|
30920
30970
|
});
|
|
30921
30971
|
|
|
30922
30972
|
// src/lib/local-command-consent.ts
|
|
@@ -31484,6 +31534,54 @@ import { execFileSync } from "child_process";
|
|
|
31484
31534
|
import { existsSync as existsSync10, readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync7 } from "fs";
|
|
31485
31535
|
import { join as join11 } from "path";
|
|
31486
31536
|
import { homedir as homedir8 } from "os";
|
|
31537
|
+
function formatTomlString(value) {
|
|
31538
|
+
return JSON.stringify(value);
|
|
31539
|
+
}
|
|
31540
|
+
function formatTomlKey(key) {
|
|
31541
|
+
return /^[A-Za-z0-9_-]+$/.test(key) ? key : formatTomlString(key);
|
|
31542
|
+
}
|
|
31543
|
+
function formatTomlEnv(env) {
|
|
31544
|
+
return Object.entries(env).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${formatTomlKey(key)} = ${formatTomlString(value)}`).join(`
|
|
31545
|
+
`);
|
|
31546
|
+
}
|
|
31547
|
+
function escapeRegExp(value) {
|
|
31548
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
31549
|
+
}
|
|
31550
|
+
function codexServerHeader(id) {
|
|
31551
|
+
return `[mcp_servers.${id}]`;
|
|
31552
|
+
}
|
|
31553
|
+
function codexEnvHeader(id) {
|
|
31554
|
+
return `[mcp_servers.${id}.env]`;
|
|
31555
|
+
}
|
|
31556
|
+
function formatCodexEnvBlock(id, env) {
|
|
31557
|
+
return `
|
|
31558
|
+
${codexEnvHeader(id)}
|
|
31559
|
+
${formatTomlEnv(env)}
|
|
31560
|
+
`;
|
|
31561
|
+
}
|
|
31562
|
+
function formatCodexServerBlock(entry, env) {
|
|
31563
|
+
return `
|
|
31564
|
+
${codexServerHeader(entry.id)}
|
|
31565
|
+
` + `command = ${formatTomlString(entry.command)}
|
|
31566
|
+
` + `args = [${entry.args.map((a) => formatTomlString(a)).join(", ")}]
|
|
31567
|
+
` + (Object.keys(env).length > 0 ? formatCodexEnvBlock(entry.id, env) : "");
|
|
31568
|
+
}
|
|
31569
|
+
function upsertCodexEnvBlock(config2, id, env) {
|
|
31570
|
+
const envBlock = formatCodexEnvBlock(id, env);
|
|
31571
|
+
const envHeaderPattern = escapeRegExp(codexEnvHeader(id));
|
|
31572
|
+
const envBlockPattern = new RegExp(`(?:\\r?\\n)?[ \\t]*${envHeaderPattern}[ \\t]*\\r?\\n[\\s\\S]*?(?=\\r?\\n[ \\t]*\\[|\\s*$)`);
|
|
31573
|
+
if (envBlockPattern.test(config2)) {
|
|
31574
|
+
return config2.replace(envBlockPattern, () => envBlock);
|
|
31575
|
+
}
|
|
31576
|
+
const serverHeaderPattern = escapeRegExp(codexServerHeader(id));
|
|
31577
|
+
const serverBlockPattern = new RegExp(`([ \\t]*${serverHeaderPattern}[ \\t]*\\r?\\n[\\s\\S]*?)(?=\\r?\\n[ \\t]*\\[|\\s*$)`);
|
|
31578
|
+
let inserted = false;
|
|
31579
|
+
const updated = config2.replace(serverBlockPattern, (_match, serverBlock) => {
|
|
31580
|
+
inserted = true;
|
|
31581
|
+
return `${serverBlock}${envBlock}`;
|
|
31582
|
+
});
|
|
31583
|
+
return inserted ? updated : `${config2}${envBlock}`;
|
|
31584
|
+
}
|
|
31487
31585
|
function installToClaude(entry) {
|
|
31488
31586
|
try {
|
|
31489
31587
|
const args = [
|
|
@@ -31511,16 +31609,15 @@ function installToCodex(entry) {
|
|
|
31511
31609
|
if (!existsSync10(configDir)) {
|
|
31512
31610
|
mkdirSync7(configDir, { recursive: true });
|
|
31513
31611
|
}
|
|
31514
|
-
const
|
|
31515
|
-
[mcp_servers.${entry.id}]
|
|
31516
|
-
` + `command = ${JSON.stringify(entry.command)}
|
|
31517
|
-
` + `args = [${entry.args.map((a) => JSON.stringify(a)).join(", ")}]
|
|
31518
|
-
`;
|
|
31612
|
+
const env = assertAgentInstallEnv(entry);
|
|
31519
31613
|
const existing = existsSync10(configPath) ? readFileSync5(configPath, "utf-8") : "";
|
|
31520
|
-
if (existing.includes(
|
|
31614
|
+
if (existing.includes(codexServerHeader(entry.id))) {
|
|
31615
|
+
if (Object.keys(env).length > 0) {
|
|
31616
|
+
writeFileSync3(configPath, upsertCodexEnvBlock(existing, entry.id, env), "utf-8");
|
|
31617
|
+
}
|
|
31521
31618
|
return { agent: "codex", success: true };
|
|
31522
31619
|
}
|
|
31523
|
-
writeFileSync3(configPath, existing +
|
|
31620
|
+
writeFileSync3(configPath, existing + formatCodexServerBlock(entry, env), "utf-8");
|
|
31524
31621
|
return { agent: "codex", success: true };
|
|
31525
31622
|
} catch (err) {
|
|
31526
31623
|
return { agent: "codex", success: false, error: err.message };
|
|
@@ -34452,14 +34549,11 @@ function buildEnv(extra) {
|
|
|
34452
34549
|
return merged;
|
|
34453
34550
|
}
|
|
34454
34551
|
function requireUrl(entry) {
|
|
34455
|
-
|
|
34552
|
+
const url2 = normalizeServerUrl(entry.url);
|
|
34553
|
+
if (!url2) {
|
|
34456
34554
|
throw new Error(`Server "${entry.id}" is missing a URL for ${entry.transport} transport`);
|
|
34457
34555
|
}
|
|
34458
|
-
|
|
34459
|
-
return new URL(entry.url);
|
|
34460
|
-
} catch {
|
|
34461
|
-
throw new Error(`Server "${entry.id}" has an invalid URL: ${entry.url}`);
|
|
34462
|
-
}
|
|
34556
|
+
return new URL(url2);
|
|
34463
34557
|
}
|
|
34464
34558
|
async function connectToServer(entry, options = {}) {
|
|
34465
34559
|
if (connections.has(entry.id)) {
|
|
@@ -34491,8 +34585,10 @@ async function connectToServer(entry, options = {}) {
|
|
|
34491
34585
|
});
|
|
34492
34586
|
} else if (entry.transport === "sse") {
|
|
34493
34587
|
transport = new SSEClientTransport(requireUrl(entry));
|
|
34494
|
-
} else {
|
|
34588
|
+
} else if (entry.transport === "streamable-http") {
|
|
34495
34589
|
transport = new StreamableHTTPClientTransport(requireUrl(entry));
|
|
34590
|
+
} else {
|
|
34591
|
+
throw new Error(`Unsupported transport type for server "${entry.id}": ${entry.transport}`);
|
|
34496
34592
|
}
|
|
34497
34593
|
await client.connect(transport);
|
|
34498
34594
|
const result = await client.listTools();
|