metheus-governance-mcp-cli 0.2.38 → 0.2.40

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.
Files changed (2) hide show
  1. package/cli.mjs +71 -17
  2. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -3563,16 +3563,33 @@ function buildToolAliasMaps(tools) {
3563
3563
  return { aliasToCanonical, canonicalToAlias };
3564
3564
  }
3565
3565
 
3566
- function applyToolAliasesToToolsListResponse(responseObj, canonicalToAlias) {
3566
+ function appendToolAliasesToToolsListResponse(responseObj, canonicalToAlias) {
3567
3567
  const result = safeObject(responseObj.result);
3568
3568
  const tools = ensureArray(result.tools);
3569
- result.tools = tools.map((tool) => {
3569
+ const outputTools = [];
3570
+ const reservedNames = new Set();
3571
+
3572
+ for (const tool of tools) {
3570
3573
  const safeTool = safeObject(tool);
3571
3574
  const currentName = String(safeTool.name || "").trim();
3572
- const aliasName = canonicalToAlias.get(currentName);
3573
- if (!aliasName) return safeTool;
3574
- return { ...safeTool, name: aliasName };
3575
- });
3575
+ if (currentName) {
3576
+ reservedNames.add(currentName);
3577
+ }
3578
+ outputTools.push(safeTool);
3579
+ }
3580
+
3581
+ for (const tool of tools) {
3582
+ const safeTool = safeObject(tool);
3583
+ const canonicalName = String(safeTool.name || "").trim();
3584
+ if (!canonicalName) continue;
3585
+ const aliasName = String(canonicalToAlias.get(canonicalName) || "").trim();
3586
+ if (!aliasName || reservedNames.has(aliasName)) continue;
3587
+ const aliasTool = { ...safeTool, name: aliasName };
3588
+ outputTools.push(aliasTool);
3589
+ reservedNames.add(aliasName);
3590
+ }
3591
+
3592
+ result.tools = outputTools;
3576
3593
  responseObj.result = result;
3577
3594
  return responseObj;
3578
3595
  }
@@ -3603,6 +3620,14 @@ function shouldUseSafeToolAliasesForClient(initParamsRaw) {
3603
3620
  return name.includes("cursor") || name.includes("antigravity");
3604
3621
  }
3605
3622
 
3623
+ function displayToolNameForClient(canonicalName, useSafeToolAliases = false) {
3624
+ const canonical = String(canonicalName || "").trim();
3625
+ if (!canonical) return "";
3626
+ if (!useSafeToolAliases) return canonical;
3627
+ const alias = normalizeSafeToolAliasName(canonical);
3628
+ return alias || canonical;
3629
+ }
3630
+
3606
3631
  function injectWorkspaceDirIntoToolSchemas(tools) {
3607
3632
  const workspaceDirProp = {
3608
3633
  type: "string",
@@ -3633,14 +3658,25 @@ function appendLocalToolToToolsList(responseObj) {
3633
3658
  return responseObj;
3634
3659
  }
3635
3660
 
3636
- function appendProjectHintToInitialize(responseObj, args) {
3661
+ function appendProjectHintToInitialize(responseObj, args, options = {}) {
3662
+ const useSafeToolAliases = Boolean(options.useSafeToolAliases);
3637
3663
  const result = safeObject(responseObj.result);
3664
+ const projectSummaryTool = displayToolNameForClient("project.summary", useSafeToolAliases);
3665
+ const projectDescribeTool = displayToolNameForClient("project.describe", useSafeToolAliases);
3666
+ const projectGetTool = displayToolNameForClient("project.get", useSafeToolAliases);
3667
+ const ctxpackMergeBriefTool = displayToolNameForClient("ctxpack.merge.brief", useSafeToolAliases);
3668
+ const ctxpackMergeExecuteTool = displayToolNameForClient("ctxpack.merge.execute", useSafeToolAliases);
3638
3669
  const hintLines = [
3639
3670
  "High-priority project bootstrap rule:",
3640
- "- MUST call `project.summary` first when the user provides only a Project ID or asks project overview/agenda.",
3641
- "- `project.describe` and `project.get` are aliases of `project.summary`.",
3671
+ ...(useSafeToolAliases
3672
+ ? [
3673
+ "- This session uses safe MCP tool aliases (underscore format). Use `project_summary` / `ctxpack_ensure` / `workitem_list` style names, not dotted names.",
3674
+ ]
3675
+ : []),
3676
+ `- MUST call \`${projectSummaryTool}\` first when the user provides only a Project ID or asks project overview/agenda.`,
3677
+ `- \`${projectDescribeTool}\` and \`${projectGetTool}\` are aliases of \`${projectSummaryTool}\`.`,
3642
3678
  "- After project summary, use workitem/evidence/decision tools as follow-up.",
3643
- "- Before any ctxpack merge, call `ctxpack.merge.brief` first, share recommendation to owner, get explicit owner confirmation, then call `ctxpack.merge.execute`.",
3679
+ `- Before any ctxpack merge, call \`${ctxpackMergeBriefTool}\` first, share recommendation to owner, get explicit owner confirmation, then call \`${ctxpackMergeExecuteTool}\`.`,
3644
3680
  "- IMPORTANT: When calling ANY tool, always include your current working directory / project folder path as the `workspace_dir` argument. This enables ctxpack files to be synced to the correct workspace location.",
3645
3681
  ];
3646
3682
  if (args.projectID) {
@@ -3767,7 +3803,16 @@ function appendAutoCtxpackSyncHint(responseObj, summary) {
3767
3803
  return responseObj;
3768
3804
  }
3769
3805
 
3770
- async function appendWorkitemListHints(responseObj, args, toolArgs, token, workspaceSignalTrusted = true) {
3806
+ async function appendWorkitemListHints(
3807
+ responseObj,
3808
+ args,
3809
+ toolArgs,
3810
+ token,
3811
+ workspaceSignalTrusted = true,
3812
+ options = {},
3813
+ ) {
3814
+ const useSafeToolAliases = Boolean(options.useSafeToolAliases);
3815
+ const projectSummaryTool = displayToolNameForClient("project.summary", useSafeToolAliases);
3771
3816
  const result = safeObject(responseObj.result);
3772
3817
  const content = ensureArray(result.content);
3773
3818
  if (!content.length) return responseObj;
@@ -3777,7 +3822,7 @@ async function appendWorkitemListHints(responseObj, args, toolArgs, token, works
3777
3822
 
3778
3823
  const text = String(first.text || "");
3779
3824
  if (!text) return responseObj;
3780
- if (text.includes("Call `project.summary`")) return responseObj;
3825
+ if (text.includes(`Call \`${projectSummaryTool}\``) || text.includes("Call `project.summary`")) return responseObj;
3781
3826
 
3782
3827
  const parsed = parseGatewayResponseText(text);
3783
3828
  if (!parsed) return responseObj;
@@ -3794,7 +3839,7 @@ async function appendWorkitemListHints(responseObj, args, toolArgs, token, works
3794
3839
  const nextLines = [""];
3795
3840
  if (isEmptyBody) {
3796
3841
  nextLines.push("No work items found for this project.");
3797
- nextLines.push("- Call `project.summary` to confirm project context/agenda and access state first.");
3842
+ nextLines.push(`- Call \`${projectSummaryTool}\` to confirm project context/agenda and access state first.`);
3798
3843
  }
3799
3844
 
3800
3845
  let responseProjectID = "";
@@ -4557,10 +4602,12 @@ async function runProxy(flags) {
4557
4602
  const aliasMaps = buildToolAliasMaps(tools);
4558
4603
  sessionToolAliasToCanonical = aliasMaps.aliasToCanonical;
4559
4604
  sessionToolCanonicalToAlias = aliasMaps.canonicalToAlias;
4560
- patched = applyToolAliasesToToolsListResponse(patched, sessionToolCanonicalToAlias);
4605
+ patched = appendToolAliasesToToolsListResponse(patched, sessionToolCanonicalToAlias);
4561
4606
  }
4562
4607
  } else if (isJsonRpcMethod(requestObj, "initialize")) {
4563
- patched = appendProjectHintToInitialize(patched, args);
4608
+ patched = appendProjectHintToInitialize(patched, args, {
4609
+ useSafeToolAliases: sessionUseSafeToolAliases,
4610
+ });
4564
4611
  // Log initialize params for workspace debugging.
4565
4612
  try {
4566
4613
  const _diagDir = path.join(String(process.env.USERPROFILE || process.env.HOME || "."), ".metheus");
@@ -4577,7 +4624,14 @@ async function runProxy(flags) {
4577
4624
  setImmediate(() => sendRootsListProbe());
4578
4625
  }
4579
4626
  } else if (isJsonRpcMethod(requestObj, "tools/call") && toolName === "workitem.list") {
4580
- patched = await appendWorkitemListHints(patched, args, toolArgs, token, workspaceSignalTrusted);
4627
+ patched = await appendWorkitemListHints(
4628
+ patched,
4629
+ args,
4630
+ toolArgs,
4631
+ token,
4632
+ workspaceSignalTrusted,
4633
+ { useSafeToolAliases: sessionUseSafeToolAliases },
4634
+ );
4581
4635
  } else if (isJsonRpcMethod(requestObj, "tools/call") && toolName === "ctxpack.ensure") {
4582
4636
  patched = appendCtxpackEnsureSyncHints(
4583
4637
  patched,
@@ -5019,7 +5073,7 @@ function resolveSetupContext(flags) {
5019
5073
  const workspaceMeta = loadWorkspaceMeta(process.cwd());
5020
5074
  const projectID = String(flags["project-id"] || workspaceMeta.project_id || "").trim();
5021
5075
  const ctxpackKey = String(flags["ctxpack-key"] || buildCtxpackKeyFromMeta(workspaceMeta) || "").trim();
5022
- const baseURL = String(flags["base-url"] || DEFAULT_SITE_URL).trim().replace(/\/+$/, "");
5076
+ const baseURL = normalizeSiteBaseURL(flags["base-url"] || DEFAULT_SITE_URL);
5023
5077
  const workspaceDirRaw = String(flags["workspace-dir"] || "").trim();
5024
5078
  const workspaceFallbackDirRaw = String(flags["workspace-fallback-dir"] || "").trim();
5025
5079
  const hasWorkspaceDirFlag = Object.prototype.hasOwnProperty.call(flags, "workspace-dir");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.38",
3
+ "version": "0.2.40",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [