@hasna/configs 0.2.31 → 0.2.32

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/mcp/index.js CHANGED
@@ -11250,7 +11250,7 @@ var init_sync_dir = __esm(() => {
11250
11250
  var require_package = __commonJS((exports, module) => {
11251
11251
  module.exports = {
11252
11252
  name: "@hasna/configs",
11253
- version: "0.2.31",
11253
+ version: "0.2.32",
11254
11254
  description: "AI coding agent configuration manager \u2014 store, version, apply, and share all your AI coding configs. CLI + MCP + REST API + Dashboard.",
11255
11255
  type: "module",
11256
11256
  main: "dist/index.js",
@@ -11333,12 +11333,14 @@ var require_package = __commonJS((exports, module) => {
11333
11333
  });
11334
11334
 
11335
11335
  // src/mcp/index.ts
11336
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
11337
+
11338
+ // src/mcp/server.ts
11336
11339
  init_dist();
11337
11340
  init_configs();
11338
11341
  init_apply();
11339
11342
  init_sync_dir();
11340
11343
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
11341
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
11342
11344
  import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
11343
11345
 
11344
11346
  // src/db/profiles.ts
@@ -11397,7 +11399,7 @@ function resolveProfileForMachine(machine = detectMachineContext(), db) {
11397
11399
  return matches[0]?.profile ?? null;
11398
11400
  }
11399
11401
 
11400
- // src/mcp/index.ts
11402
+ // src/mcp/server.ts
11401
11403
  init_apply();
11402
11404
  init_snapshots();
11403
11405
  init_machine();
@@ -11457,240 +11459,328 @@ function err(msg) {
11457
11459
  return { content: [{ type: "text", text: JSON.stringify({ error: msg }) }], isError: true };
11458
11460
  }
11459
11461
  var _cfgAgents = new Map;
11460
- var server = new Server({ name: "configs", version: require_package().version }, { capabilities: { tools: {} } });
11461
- var LEAN_TOOLS = profileFilter && profileFilter.length > 0 ? ALL_LEAN_TOOLS.filter((t) => profileFilter.includes(t.name)) : ALL_LEAN_TOOLS;
11462
- server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: LEAN_TOOLS }));
11463
- server.setRequestHandler(CallToolRequestSchema, async (req) => {
11464
- const { name, arguments: args = {} } = req.params;
11465
- try {
11466
- switch (name) {
11467
- case "list_configs": {
11468
- const configs = listConfigs({
11469
- category: args["category"] || undefined,
11470
- agent: args["agent"] || undefined,
11471
- kind: args["kind"] || undefined,
11472
- search: args["search"] || undefined
11473
- });
11474
- return ok(configs.map((c) => ({ id: c.id, slug: c.slug, name: c.name, category: c.category, agent: c.agent, kind: c.kind, target_path: c.target_path, version: c.version })));
11475
- }
11476
- case "get_config": {
11477
- const c = getConfig(args["id_or_slug"]);
11478
- return ok(c);
11479
- }
11480
- case "create_config": {
11481
- const c = createConfig({
11482
- name: args["name"],
11483
- content: args["content"],
11484
- category: args["category"],
11485
- agent: args["agent"] || undefined,
11486
- target_path: args["target_path"] || undefined,
11487
- kind: args["kind"] || undefined,
11488
- format: args["format"] || undefined,
11489
- tags: args["tags"] || undefined,
11490
- description: args["description"] || undefined,
11491
- is_template: args["is_template"] || undefined
11492
- });
11493
- return ok({ id: c.id, slug: c.slug, name: c.name });
11494
- }
11495
- case "update_config": {
11496
- const c = updateConfig(args["id_or_slug"], {
11497
- content: args["content"],
11498
- name: args["name"],
11499
- tags: args["tags"],
11500
- description: args["description"],
11501
- category: args["category"],
11502
- agent: args["agent"],
11503
- target_path: args["target_path"]
11504
- });
11505
- return ok({ id: c.id, slug: c.slug, version: c.version });
11506
- }
11507
- case "delete_config": {
11508
- const { deleteConfig: deleteConfig2 } = await Promise.resolve().then(() => (init_configs(), exports_configs));
11509
- deleteConfig2(args["id_or_slug"]);
11510
- return ok({ deleted: true });
11511
- }
11512
- case "apply_config": {
11513
- const config = getConfig(args["id_or_slug"]);
11514
- const result = await applyConfig(config, { dryRun: args["dry_run"] });
11515
- return ok(result);
11516
- }
11517
- case "sync_directory": {
11518
- const dir = args["dir"];
11519
- const direction = args["direction"] || "from_disk";
11520
- const result = direction === "to_disk" ? await syncToDir(dir) : await syncFromDir(dir);
11521
- return ok(result);
11522
- }
11523
- case "list_profiles": {
11524
- return ok(listProfiles());
11525
- }
11526
- case "apply_profile": {
11527
- const machine = detectMachineContext({
11528
- hostname: args["hostname"],
11529
- os: args["os"],
11530
- arch: args["arch"]
11531
- });
11532
- if (!args["auto"] && !args["id_or_slug"])
11533
- return err("id_or_slug is required unless auto=true");
11534
- const profile = args["auto"] ? resolveProfileForMachine(machine) : getProfile(args["id_or_slug"]);
11535
- if (!profile)
11536
- return err("No matching machine-aware profile found");
11537
- const configs = getProfileConfigs(profile.id);
11538
- const vars = resolveProfileVariables(profile, machine);
11539
- const results = await applyConfigs(configs, { dryRun: args["dry_run"], vars });
11540
- return ok({ profile, machine, results });
11541
- }
11542
- case "get_snapshot": {
11543
- const config = getConfig(args["config_id_or_slug"]);
11544
- if (args["version"]) {
11545
- const snap = getSnapshotByVersion(config.id, args["version"]);
11546
- return snap ? ok(snap) : err("Snapshot not found");
11547
- }
11548
- const snaps = listSnapshots(config.id);
11549
- return ok(snaps[0] ?? null);
11550
- }
11551
- case "get_status": {
11552
- const stats = getConfigStats();
11553
- const allConfigs = listConfigs({ kind: "file" });
11554
- const { existsSync: ex, readFileSync: rf } = await import("fs");
11555
- const { expandPath: expandPath2 } = await Promise.resolve().then(() => (init_apply(), exports_apply));
11556
- const { redactContent: redactContent2 } = await Promise.resolve().then(() => (init_redact(), exports_redact));
11557
- let drifted = 0, missing = 0, templates = 0;
11558
- const driftedSlugs = [];
11559
- for (const c of allConfigs) {
11560
- if (c.is_template)
11561
- templates++;
11562
- if (!c.target_path)
11563
- continue;
11564
- const abs = expandPath2(c.target_path);
11565
- if (!ex(abs)) {
11566
- missing++;
11567
- continue;
11568
- }
11569
- const disk = rf(abs, "utf-8");
11570
- const { content: redactedDisk } = redactContent2(disk, c.format);
11571
- if (redactedDisk !== c.content) {
11572
- drifted++;
11573
- driftedSlugs.push(c.slug);
11574
- }
11575
- }
11576
- return ok({
11577
- total: stats["total"] || 0,
11578
- by_category: Object.fromEntries(Object.entries(stats).filter(([k]) => k !== "total")),
11579
- templates,
11580
- drifted,
11581
- drifted_configs: driftedSlugs.slice(0, 5),
11582
- missing,
11583
- db_path: process.env["CONFIGS_DB_PATH"] || "~/.hasna/configs/configs.db"
11584
- });
11585
- }
11586
- case "sync_known": {
11587
- const { syncKnown: syncKnown2 } = await Promise.resolve().then(() => (init_sync(), exports_sync));
11588
- const result = await syncKnown2({
11589
- agent: args["agent"] || undefined,
11590
- category: args["category"] || undefined
11591
- });
11592
- return ok(result);
11593
- }
11594
- case "sync_project": {
11595
- const { syncProject: syncProject2 } = await Promise.resolve().then(() => (init_sync(), exports_sync));
11596
- const dir = args["project_dir"] || process.cwd();
11597
- const result = await syncProject2({ projectDir: dir });
11598
- return ok(result);
11599
- }
11600
- case "render_template": {
11601
- const { renderTemplate: renderTemplate2 } = await Promise.resolve().then(() => (init_template(), exports_template));
11602
- const config = getConfig(args["id_or_slug"]);
11603
- const vars = args["vars"] || {};
11604
- if (args["use_env"]) {
11605
- const { extractTemplateVars: extractTemplateVars2 } = await Promise.resolve().then(() => (init_template(), exports_template));
11606
- for (const v of extractTemplateVars2(config.content)) {
11607
- if (!(v.name in vars) && process.env[v.name]) {
11608
- vars[v.name] = process.env[v.name];
11462
+ function buildServer() {
11463
+ const server = new Server({ name: "configs", version: require_package().version }, { capabilities: { tools: {} } });
11464
+ const LEAN_TOOLS = profileFilter && profileFilter.length > 0 ? ALL_LEAN_TOOLS.filter((t) => profileFilter.includes(t.name)) : ALL_LEAN_TOOLS;
11465
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: LEAN_TOOLS }));
11466
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
11467
+ const { name, arguments: args = {} } = req.params;
11468
+ try {
11469
+ switch (name) {
11470
+ case "list_configs": {
11471
+ const configs = listConfigs({
11472
+ category: args["category"] || undefined,
11473
+ agent: args["agent"] || undefined,
11474
+ kind: args["kind"] || undefined,
11475
+ search: args["search"] || undefined
11476
+ });
11477
+ return ok(configs.map((c) => ({ id: c.id, slug: c.slug, name: c.name, category: c.category, agent: c.agent, kind: c.kind, target_path: c.target_path, version: c.version })));
11478
+ }
11479
+ case "get_config": {
11480
+ const c = getConfig(args["id_or_slug"]);
11481
+ return ok(c);
11482
+ }
11483
+ case "create_config": {
11484
+ const c = createConfig({
11485
+ name: args["name"],
11486
+ content: args["content"],
11487
+ category: args["category"],
11488
+ agent: args["agent"] || undefined,
11489
+ target_path: args["target_path"] || undefined,
11490
+ kind: args["kind"] || undefined,
11491
+ format: args["format"] || undefined,
11492
+ tags: args["tags"] || undefined,
11493
+ description: args["description"] || undefined,
11494
+ is_template: args["is_template"] || undefined
11495
+ });
11496
+ return ok({ id: c.id, slug: c.slug, name: c.name });
11497
+ }
11498
+ case "update_config": {
11499
+ const c = updateConfig(args["id_or_slug"], {
11500
+ content: args["content"],
11501
+ name: args["name"],
11502
+ tags: args["tags"],
11503
+ description: args["description"],
11504
+ category: args["category"],
11505
+ agent: args["agent"],
11506
+ target_path: args["target_path"]
11507
+ });
11508
+ return ok({ id: c.id, slug: c.slug, version: c.version });
11509
+ }
11510
+ case "delete_config": {
11511
+ const { deleteConfig: deleteConfig2 } = await Promise.resolve().then(() => (init_configs(), exports_configs));
11512
+ deleteConfig2(args["id_or_slug"]);
11513
+ return ok({ deleted: true });
11514
+ }
11515
+ case "apply_config": {
11516
+ const config = getConfig(args["id_or_slug"]);
11517
+ const result = await applyConfig(config, { dryRun: args["dry_run"] });
11518
+ return ok(result);
11519
+ }
11520
+ case "sync_directory": {
11521
+ const dir = args["dir"];
11522
+ const direction = args["direction"] || "from_disk";
11523
+ const result = direction === "to_disk" ? await syncToDir(dir) : await syncFromDir(dir);
11524
+ return ok(result);
11525
+ }
11526
+ case "list_profiles": {
11527
+ return ok(listProfiles());
11528
+ }
11529
+ case "apply_profile": {
11530
+ const machine = detectMachineContext({
11531
+ hostname: args["hostname"],
11532
+ os: args["os"],
11533
+ arch: args["arch"]
11534
+ });
11535
+ if (!args["auto"] && !args["id_or_slug"])
11536
+ return err("id_or_slug is required unless auto=true");
11537
+ const profile = args["auto"] ? resolveProfileForMachine(machine) : getProfile(args["id_or_slug"]);
11538
+ if (!profile)
11539
+ return err("No matching machine-aware profile found");
11540
+ const configs = getProfileConfigs(profile.id);
11541
+ const vars = resolveProfileVariables(profile, machine);
11542
+ const results = await applyConfigs(configs, { dryRun: args["dry_run"], vars });
11543
+ return ok({ profile, machine, results });
11544
+ }
11545
+ case "get_snapshot": {
11546
+ const config = getConfig(args["config_id_or_slug"]);
11547
+ if (args["version"]) {
11548
+ const snap = getSnapshotByVersion(config.id, args["version"]);
11549
+ return snap ? ok(snap) : err("Snapshot not found");
11550
+ }
11551
+ const snaps = listSnapshots(config.id);
11552
+ return ok(snaps[0] ?? null);
11553
+ }
11554
+ case "get_status": {
11555
+ const stats = getConfigStats();
11556
+ const allConfigs = listConfigs({ kind: "file" });
11557
+ const { existsSync: ex, readFileSync: rf } = await import("fs");
11558
+ const { expandPath: expandPath2 } = await Promise.resolve().then(() => (init_apply(), exports_apply));
11559
+ const { redactContent: redactContent2 } = await Promise.resolve().then(() => (init_redact(), exports_redact));
11560
+ let drifted = 0, missing = 0, templates = 0;
11561
+ const driftedSlugs = [];
11562
+ for (const c of allConfigs) {
11563
+ if (c.is_template)
11564
+ templates++;
11565
+ if (!c.target_path)
11566
+ continue;
11567
+ const abs = expandPath2(c.target_path);
11568
+ if (!ex(abs)) {
11569
+ missing++;
11570
+ continue;
11571
+ }
11572
+ const disk = rf(abs, "utf-8");
11573
+ const { content: redactedDisk } = redactContent2(disk, c.format);
11574
+ if (redactedDisk !== c.content) {
11575
+ drifted++;
11576
+ driftedSlugs.push(c.slug);
11609
11577
  }
11610
11578
  }
11579
+ return ok({
11580
+ total: stats["total"] || 0,
11581
+ by_category: Object.fromEntries(Object.entries(stats).filter(([k]) => k !== "total")),
11582
+ templates,
11583
+ drifted,
11584
+ drifted_configs: driftedSlugs.slice(0, 5),
11585
+ missing,
11586
+ db_path: process.env["CONFIGS_DB_PATH"] || "~/.hasna/configs/configs.db"
11587
+ });
11611
11588
  }
11612
- const rendered = renderTemplate2(config.content, vars);
11613
- return ok({ rendered, config_id: config.id, slug: config.slug });
11614
- }
11615
- case "scan_secrets": {
11616
- const { scanSecrets: scanSecrets2, redactContent: redactContent2 } = await Promise.resolve().then(() => (init_redact(), exports_redact));
11617
- const configs = args["id_or_slug"] ? [getConfig(args["id_or_slug"])] : listConfigs({ kind: "file" });
11618
- const findings = [];
11619
- for (const c of configs) {
11620
- const fmt = c.format;
11621
- const secrets = scanSecrets2(c.content, fmt);
11622
- if (secrets.length > 0) {
11623
- findings.push({ slug: c.slug, secrets: secrets.length, vars: secrets.map((s) => s.varName) });
11624
- if (args["fix"]) {
11625
- const { content, isTemplate: isTemplate2 } = redactContent2(c.content, fmt);
11626
- updateConfig(c.id, { content, is_template: isTemplate2 });
11589
+ case "sync_known": {
11590
+ const { syncKnown: syncKnown2 } = await Promise.resolve().then(() => (init_sync(), exports_sync));
11591
+ const result = await syncKnown2({
11592
+ agent: args["agent"] || undefined,
11593
+ category: args["category"] || undefined
11594
+ });
11595
+ return ok(result);
11596
+ }
11597
+ case "sync_project": {
11598
+ const { syncProject: syncProject2 } = await Promise.resolve().then(() => (init_sync(), exports_sync));
11599
+ const dir = args["project_dir"] || process.cwd();
11600
+ const result = await syncProject2({ projectDir: dir });
11601
+ return ok(result);
11602
+ }
11603
+ case "render_template": {
11604
+ const { renderTemplate: renderTemplate2 } = await Promise.resolve().then(() => (init_template(), exports_template));
11605
+ const config = getConfig(args["id_or_slug"]);
11606
+ const vars = args["vars"] || {};
11607
+ if (args["use_env"]) {
11608
+ const { extractTemplateVars: extractTemplateVars2 } = await Promise.resolve().then(() => (init_template(), exports_template));
11609
+ for (const v of extractTemplateVars2(config.content)) {
11610
+ if (!(v.name in vars) && process.env[v.name]) {
11611
+ vars[v.name] = process.env[v.name];
11612
+ }
11627
11613
  }
11628
11614
  }
11615
+ const rendered = renderTemplate2(config.content, vars);
11616
+ return ok({ rendered, config_id: config.id, slug: config.slug });
11617
+ }
11618
+ case "scan_secrets": {
11619
+ const { scanSecrets: scanSecrets2, redactContent: redactContent2 } = await Promise.resolve().then(() => (init_redact(), exports_redact));
11620
+ const configs = args["id_or_slug"] ? [getConfig(args["id_or_slug"])] : listConfigs({ kind: "file" });
11621
+ const findings = [];
11622
+ for (const c of configs) {
11623
+ const fmt = c.format;
11624
+ const secrets = scanSecrets2(c.content, fmt);
11625
+ if (secrets.length > 0) {
11626
+ findings.push({ slug: c.slug, secrets: secrets.length, vars: secrets.map((s) => s.varName) });
11627
+ if (args["fix"]) {
11628
+ const { content, isTemplate: isTemplate2 } = redactContent2(c.content, fmt);
11629
+ updateConfig(c.id, { content, is_template: isTemplate2 });
11630
+ }
11631
+ }
11632
+ }
11633
+ return ok({ clean: findings.length === 0, findings, fixed: !!args["fix"] });
11634
+ }
11635
+ case "search_tools": {
11636
+ const query = (args["query"] || "").toLowerCase();
11637
+ const matches = Object.entries(TOOL_DOCS).filter(([k, v]) => k.includes(query) || v.toLowerCase().includes(query)).map(([name2, description]) => ({ name: name2, description }));
11638
+ return ok(matches);
11639
+ }
11640
+ case "describe_tools": {
11641
+ const names = args["names"];
11642
+ if (names) {
11643
+ return ok(Object.fromEntries(names.map((n) => [n, TOOL_DOCS[n] ?? "Unknown tool"])));
11644
+ }
11645
+ return ok(TOOL_DOCS);
11646
+ }
11647
+ case "register_agent": {
11648
+ const n = String(args["name"] ?? "");
11649
+ const existing = [..._cfgAgents.values()].find((x) => x.name === n);
11650
+ if (existing) {
11651
+ existing.last_seen_at = new Date().toISOString();
11652
+ return ok(existing);
11653
+ }
11654
+ const id = Math.random().toString(36).slice(2, 10);
11655
+ const ag = { id, name: n, last_seen_at: new Date().toISOString() };
11656
+ _cfgAgents.set(id, ag);
11657
+ return ok(ag);
11658
+ }
11659
+ case "heartbeat": {
11660
+ const ag = _cfgAgents.get(String(args["agent_id"] ?? ""));
11661
+ if (!ag)
11662
+ return err(`Agent not found: ${args["agent_id"]}`);
11663
+ ag.last_seen_at = new Date().toISOString();
11664
+ return ok({ agent_id: ag.id, name: ag.name, last_seen_at: ag.last_seen_at });
11665
+ }
11666
+ case "set_focus": {
11667
+ const ag = _cfgAgents.get(String(args["agent_id"] ?? ""));
11668
+ if (!ag)
11669
+ return err(`Agent not found: ${args["agent_id"]}`);
11670
+ ag["project_id"] = args["project_id"];
11671
+ return ok({ agent_id: ag.id, project_id: args["project_id"] ?? null });
11672
+ }
11673
+ case "list_agents": {
11674
+ return ok([..._cfgAgents.values()]);
11675
+ }
11676
+ case "send_feedback": {
11677
+ const { getDatabase: getDatabase2 } = await Promise.resolve().then(() => (init_database(), exports_database));
11678
+ const db = getDatabase2();
11679
+ const pkg = require_package();
11680
+ db.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", [args["message"], args["email"] || null, args["category"] || "general", pkg.version]);
11681
+ return ok({ message: "Feedback saved. Thank you!" });
11629
11682
  }
11630
- return ok({ clean: findings.length === 0, findings, fixed: !!args["fix"] });
11631
- }
11632
- case "search_tools": {
11633
- const query = (args["query"] || "").toLowerCase();
11634
- const matches = Object.entries(TOOL_DOCS).filter(([k, v]) => k.includes(query) || v.toLowerCase().includes(query)).map(([name2, description]) => ({ name: name2, description }));
11635
- return ok(matches);
11636
- }
11637
- case "describe_tools": {
11638
- const names = args["names"];
11639
- if (names) {
11640
- return ok(Object.fromEntries(names.map((n) => [n, TOOL_DOCS[n] ?? "Unknown tool"])));
11641
- }
11642
- return ok(TOOL_DOCS);
11643
- }
11644
- case "register_agent": {
11645
- const n = String(args["name"] ?? "");
11646
- const existing = [..._cfgAgents.values()].find((x) => x.name === n);
11647
- if (existing) {
11648
- existing.last_seen_at = new Date().toISOString();
11649
- return ok(existing);
11650
- }
11651
- const id = Math.random().toString(36).slice(2, 10);
11652
- const ag = { id, name: n, last_seen_at: new Date().toISOString() };
11653
- _cfgAgents.set(id, ag);
11654
- return ok(ag);
11655
- }
11656
- case "heartbeat": {
11657
- const ag = _cfgAgents.get(String(args["agent_id"] ?? ""));
11658
- if (!ag)
11659
- return err(`Agent not found: ${args["agent_id"]}`);
11660
- ag.last_seen_at = new Date().toISOString();
11661
- return ok({ agent_id: ag.id, name: ag.name, last_seen_at: ag.last_seen_at });
11662
- }
11663
- case "set_focus": {
11664
- const ag = _cfgAgents.get(String(args["agent_id"] ?? ""));
11665
- if (!ag)
11666
- return err(`Agent not found: ${args["agent_id"]}`);
11667
- ag["project_id"] = args["project_id"];
11668
- return ok({ agent_id: ag.id, project_id: args["project_id"] ?? null });
11669
- }
11670
- case "list_agents": {
11671
- return ok([..._cfgAgents.values()]);
11672
- }
11673
- case "send_feedback": {
11674
- const { getDatabase: getDatabase2 } = await Promise.resolve().then(() => (init_database(), exports_database));
11675
- const db = getDatabase2();
11676
- const pkg = require_package();
11677
- db.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", [args["message"], args["email"] || null, args["category"] || "general", pkg.version]);
11678
- return ok({ message: "Feedback saved. Thank you!" });
11683
+ default:
11684
+ return err(`Unknown tool: ${name}`);
11679
11685
  }
11680
- default:
11681
- return err(`Unknown tool: ${name}`);
11686
+ } catch (e) {
11687
+ return err(e instanceof Error ? e.message : String(e));
11682
11688
  }
11683
- } catch (e) {
11684
- return err(e instanceof Error ? e.message : String(e));
11689
+ });
11690
+ try {
11691
+ registerCloudTools(server, "configs");
11692
+ } catch {}
11693
+ return server;
11694
+ }
11695
+
11696
+ // src/mcp/http.ts
11697
+ import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
11698
+ var MCP_HTTP_PORT = 8807;
11699
+ var MCP_NAME = "configs";
11700
+ function isHttpMode(argv) {
11701
+ return argv.includes("--http") || process.env.MCP_HTTP === "1";
11702
+ }
11703
+ function resolveHttpPort(argv) {
11704
+ const eqArg = argv.find((a) => a.startsWith("--port="));
11705
+ if (eqArg) {
11706
+ const parsed = Number.parseInt(eqArg.slice("--port=".length), 10);
11707
+ if (!Number.isNaN(parsed))
11708
+ return parsed;
11709
+ }
11710
+ const idx = argv.indexOf("--port");
11711
+ if (idx >= 0) {
11712
+ const parsed = Number.parseInt(argv[idx + 1] ?? "", 10);
11713
+ if (!Number.isNaN(parsed))
11714
+ return parsed;
11715
+ }
11716
+ const envPort = process.env.MCP_HTTP_PORT;
11717
+ if (envPort) {
11718
+ const parsed = Number.parseInt(envPort, 10);
11719
+ if (!Number.isNaN(parsed))
11720
+ return parsed;
11721
+ }
11722
+ return MCP_HTTP_PORT;
11723
+ }
11724
+ function healthPayload() {
11725
+ return { status: "ok", name: MCP_NAME };
11726
+ }
11727
+ async function handleMcpRequest(req) {
11728
+ const server = buildServer();
11729
+ const transport = new WebStandardStreamableHTTPServerTransport({
11730
+ sessionIdGenerator: undefined,
11731
+ enableJsonResponse: true
11732
+ });
11733
+ await server.connect(transport);
11734
+ return transport.handleRequest(req);
11735
+ }
11736
+ async function handleMcpHttpRequest(req) {
11737
+ const url = new URL(req.url);
11738
+ if (url.pathname === "/health" && req.method === "GET") {
11739
+ return Response.json(healthPayload());
11685
11740
  }
11686
- });
11687
- if (process.argv.includes("--claude")) {
11688
- const proc = Bun.spawn(["claude", "mcp", "add", "--transport", "stdio", "--scope", "user", "configs", "--", "configs-mcp"], { stdout: "inherit", stderr: "inherit" });
11689
- await proc.exited;
11690
- process.exit(0);
11691
- }
11692
- var transport = new StdioServerTransport;
11693
- try {
11694
- registerCloudTools(server, "configs");
11695
- } catch {}
11696
- await server.connect(transport);
11741
+ if (url.pathname === "/mcp") {
11742
+ return handleMcpRequest(req);
11743
+ }
11744
+ return null;
11745
+ }
11746
+ async function startMcpHttpServer(port) {
11747
+ const httpServer = Bun.serve({
11748
+ hostname: "127.0.0.1",
11749
+ port,
11750
+ async fetch(req) {
11751
+ const handled = await handleMcpHttpRequest(req);
11752
+ if (handled)
11753
+ return handled;
11754
+ return Response.json({ error: "Not found" }, { status: 404 });
11755
+ }
11756
+ });
11757
+ return { port: httpServer.port, stop: () => httpServer.stop() };
11758
+ }
11759
+
11760
+ // src/mcp/index.ts
11761
+ async function main() {
11762
+ const argv = process.argv.slice(2);
11763
+ if (argv.includes("--claude")) {
11764
+ const proc = Bun.spawn(["claude", "mcp", "add", "--transport", "stdio", "--scope", "user", "configs", "--", "configs-mcp"], { stdout: "inherit", stderr: "inherit" });
11765
+ await proc.exited;
11766
+ process.exit(0);
11767
+ }
11768
+ if (isHttpMode(argv)) {
11769
+ const port = resolveHttpPort(argv);
11770
+ const { port: boundPort } = await startMcpHttpServer(port);
11771
+ console.error(`configs-mcp HTTP listening on http://127.0.0.1:${boundPort}/mcp`);
11772
+ return;
11773
+ }
11774
+ const server = buildServer();
11775
+ const transport = new StdioServerTransport;
11776
+ await server.connect(transport);
11777
+ }
11778
+ if (import.meta.main) {
11779
+ main().catch((err2) => {
11780
+ console.error("MCP server error:", err2);
11781
+ process.exit(1);
11782
+ });
11783
+ }
11784
+ export {
11785
+ buildServer
11786
+ };
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env bun
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ export declare function buildServer(): Server;
4
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AA8EnE,wBAAgB,WAAW,IAAI,MAAM,CAkPpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";;;;;;AA8XA,wBAAgE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";;;;;;AA6XA,wBAAgE"}