fix(mcp): resolve {{LIBRECHAT_USER_ID}} in loadTools' MCP tool-loading path (v0.8.7 port) - #33
Merged
Merged
Conversation
…g path PRs #29-#31 fixed user-id propagation into MCP headers across the agent client, openai controller, and responses controller, but loadTools() (api/app/clients/tools/util/handleTools.js) builds the MCP `user` object from `options.req?.user` alone via createSafeUser. When req.user is a plain object deserialized from the passport session (no `id` virtual, no `_id`), that resolves to no usable id — even though loadTools is already given the caller's resolved id via its own `user` param (ToolService.js calls loadTools({ user: req.user.id, ... }), and that same `user` value is already used directly for auth lookups a few lines up). Confirmed live in production: mcp.tool/* spans on cbioportal-mcp still shipped enduser.id="{{LIBRECHAT_USER_ID}}" well after PR #31 deployed. Thread the existing `user` param through as createSafeUser's fallbackId, matching the pattern PR #31 established elsewhere. Adds regression tests exercising the MCP 'all'-tools branch (the one that calls createMCPTools), verifying the fallback fires when req.user has neither id nor _id, and that an explicit req.user.id still takes precedence. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4 tasks
Follow-up to the v0.8.7 rebase: our fork intentionally exposes `conversation_starters` on the list-agents endpoint via commit b044fe8 ("Fix agent conversation starters not returned by list endpoint") so that the landing page can render them without a second per-agent fetch. Upstream added a "mass assignment protection" security test that asserts the exact safe-list of returned fields — that test doesn't know about our extension and fails on any PR against v0.8.7-custom-v1. Rather than undo b044fe8's projection change (which would break the landing UI), extend the test's expected list to reflect what our fork intentionally returns. Distinct from the mcp user-id fix that opened this PR, but folded in so v0.8.7-custom-v1 gets a clean CI baseline.
Second follow-up to the v0.8.7 rebase. This test asserted the pre-fork
behavior ("we only check id") — but our fork intentionally treats _id
as a fallback for id via the createSafeUser + loadTools chain from PRs
#29/#30/#31 and #32 (the fix this PR ports). The whole point of that
chain is that passport-deserialized session user objects carry _id but
not id, and MCP tool calls previously shipped the literal placeholder
{{LIBRECHAT_USER_ID}} instead of the resolved id.
Update the "_id only" assertion to reflect what our fork actually
does. The paired "id takes precedence when both are present" assertion
below is already correct and unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Port of #32 onto `v0.8.7-custom-v1`. Same fix as Foris's PR, adapted to the newer branch's test-file mock structure.
Change
One-line fix in `api/app/clients/tools/util/handleTools.js` line 454:
```diff
```
Same class of bug PRs #29/#30/#31 fixed elsewhere: `loadTools()` builds the MCP-tool `user` object from `options.req?.user` alone. When `req.user` is a plain object deserialized from the passport session (no `id` virtual, no `_id`), the resolver has nothing to work with — even though `loadTools` already receives the caller's resolved id via its own `user` param (see ToolService.js). Passing `user` as the fallback to `createSafeUser` closes the gap.
Test changes vs #32
Foris's version added `jest.mock('
/config'...)` and `jest.mock('/server/services/MCP'...)` blocks. `v0.8.7-custom-v1` already has richer mock scaffolding at the top of the file (`mockGetServerConfig`, `mockCreateMCPTools`, etc.), so:/config')` + `require('/server/services/MCP')` imports.Test intent + coverage are identical.
Test plan
Closes #32.