Skip to content

docs: correct the MCP glob example in the toolApproval policy comment - #14783

Open
sakej wants to merge 1 commit into
danny-avila:mainfrom
sakej:docs/toolapproval-mcp-glob-example
Open

docs: correct the MCP glob example in the toolApproval policy comment#14783
sakej wants to merge 1 commit into
danny-avila:mainfrom
sakej:docs/toolapproval-mcp-glob-example

Conversation

@sakej

@sakej sakej commented Aug 13, 2026

Copy link
Copy Markdown

What

The JSDoc for the per-endpoint tool-approval policy in packages/data-provider/src/config.ts tells you to scope a rule to one MCP server with mcp:server:*. That glob never matches a real MCP tool key, so a rule written from the documented example silently selects nothing.

Why it never matches

MCP tool keys are built as `${rawToolName}${Constants.mcp_delimiter}${serverName}`, and mcp_delimiter is '_mcp_'. A real key looks like create_issue_mcp_github. No colons anywhere.

mapToolApprovalPolicy (packages/api/src/agents/hitl/policy.ts) copies the allow/deny/ask entries verbatim into the SDK's ToolPolicyConfig. No string rewriting happens on the way. In @librechat/agents@3.4.5, createToolPolicyHook's globToRegex escapes regex metacharacters, turns * into .*, and anchors the result, so mcp:server:* compiles to /^mcp:server:.*$/. Test it against a real key:

/^mcp:server:.*$/.test('create_issue_mcp_github') // false

The SDK's own tests exercise the glob only against colon-form names like mcp:github:create_issue, which no LibreChat tool key uses.

The fix

Point the example at a glob that matches the real key format: *_mcp_<serverName> (i.e. `*${Constants.mcp_delimiter}<serverName>`). It compiles to /^.*_mcp_<serverName>$/ and selects every tool from that server. The example also notes that the server segment is the normalizeServerName() form and that a raw tool name may itself contain the delimiter (per splitMCPToolKey's doc comment), so the glob isn't misapplied. One comment line changes; no code paths are touched.

How I confirmed it

  • Read the comment and Constants.mcp_delimiter in config.ts on main.
  • Checked that mapToolApprovalPolicy passes the policy strings through unchanged.
  • Read globToRegex in the pinned @librechat/agents@3.4.5, the version api/package.json resolves in package-lock.json.

@sakej
sakej force-pushed the docs/toolapproval-mcp-glob-example branch from 830ed0c to cc4565a Compare August 13, 2026 10:18

@danny-avila danny-avila left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — the underlying report is correct: mcp:server:* cannot match a LibreChat MCP tool key, so a rule written from the documented example selects nothing. But the replacement example has an off-by-one-underscore that reintroduces the same bug.

Constants.mcp_delimiter is '_mcp_', with a single leading underscore:

/** Delimiter for MCP tools */
mcp_delimiter = '_mcp_',

So a real key is create_issue_mcp_github, not create_issue__mcp_github. The double underscore in the PR body and in the new comment text only appears when the raw tool name itself ends in _.

Running that through the same globToRegex reasoning:

glob regex matches create_issue_mcp_github
mcp:server:* (current) ^mcp:server:.*$ no
*__mcp_github (this PR) ^.*__mcp_github$ no
*_mcp_github ^.*_mcp_github$ yes

Could you change the example to `*${Constants.mcp_delimiter}<serverName>` — i.e. *_mcp_<serverName>, with create_issue_mcp_github as the sample key? Two smaller notes while you're in there:

  • The "The fix" section describes the glob as `*__mcp_` compiling to /^.*__mcp_$/, which is anchored on the delimiter and matches nothing at all. It also doesn't match the actual diff, which writes *__mcp_<serverName>. Worth aligning the description with the change.
  • The server segment in a key is the normalizeServerName() form, not necessarily the raw librechat.yaml name, and raw tool names may themselves contain _mcp_ (see splitMCPToolKey's doc comment). A short parenthetical about the normalized form would make the example harder to misapply.

The rest checks out on my read: mapToolApprovalPolicy in packages/api/src/agents/hitl/policy.ts copies allow/deny/ask into ToolPolicyConfig verbatim, so the SDK really does see raw LibreChat tool keys with no colons.

@sakej
sakej force-pushed the docs/toolapproval-mcp-glob-example branch from cc4565a to 4226041 Compare August 13, 2026 12:09
@sakej

sakej commented Aug 13, 2026

Copy link
Copy Markdown
Author

Thanks for the careful read, and for catching the delimiter. You're right: mcp_delimiter is '_mcp_' with a single underscore, so the real key is create_issue_mcp_github. My double-underscore example reintroduced the same no-match bug. Fixed and force-pushed to the same branch.

The example now uses `*${Constants.mcp_delimiter}<serverName>` (i.e. *_mcp_<serverName>) with create_issue_mcp_github as the sample key, which compiles to /^.*_mcp_<serverName>$/ and matches.

I also handled the two smaller notes:

  • Rewrote the "The fix" section so its description matches the diff (no more /^.*__mcp_$/).
  • Noted in the comment that the server segment is the normalizeServerName() form and that a raw tool name can itself contain the delimiter, per splitMCPToolKey's doc comment.

@sakej
sakej requested a review from danny-avila August 13, 2026 12:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants