librechat-search-mcp
This project allows for "all-message memory" by extending LibreChat's Search messages capability to MCP tools for proactive or on-demand use.
Summary
A restricted, LibreChat-specific MCP server based on the generic meilisearch-mcp for searching the message history that LibreChat has indexed, intended to augment the native memory feature/capability while saving costs and context loss when also disabling the optional LibreChat memory.agent. It uses Streamable HTTP hosted in a dedicated container in the LibreChat Docker Compose network (i.e., NOT implemented for non-Docker hosting/deployment setups!), derives the effective user from LibreChat's per-request User-Id header, and applies the user filter server-side. Additional post-search filters are used to help constrain results before returning to the agent. It is intentionally designed to constrain these capabilities to the scopes of users and admins who already have them, and makes conscious note of potential risks where privacy is a concern, while being designed primarily for scenarios in which "no expectation of privacy" is explicitly communicated to users.
Motivation
The LibreChat built-in memory feature is fine, for notepad-style contextual memory, but it does has some costs and side effects:
- smaller models (e.g.,
Gemma-4-12B) interpret the memory as important prompt context in fresh chats, causing strange carry-over from other conversations - memories are fully overwritten, not appended/combined, by the default LibreChat automated memory agent, causing intentionally-created memories to be lost
- the automated memory agent runs on every user message turn, doubling input token costs (yes, you probably use a cheaper model for your memory agent...)
- cache-write costs - my trigger to finally build this project: every time the memory agent adjusts a memory, the entire conversation cache is rewritten (when using OpenAI's caching system), because the memories are inserted amidst the first objects in the thread history.
- I had some GPT-5.6-Terra conversations cost me up to $3 each, and upon inspection of my usage, discovered it was the unnecessarily repeated cache writes which were the biggest contributing factor.
Meanwhile, I also wanted my agents to be more aware of overall history, like how ChatGPT can do. Seeing as how I can simply start typing into the LibreChat Search messages box, I was like, "why can't the agent be given this capability?" Much richer information is available from full messages than from cheap-agent-summarized memories, and with some recursive searching, could connect a lot of dots from a lot of conversations. My personal implemenation is already proving this out; my at-work deployment within my group is yet to be seen...
MCP tools
The server exposes LibreChat-specific versions of read-only tools (and discards the write tools) of the upstream meilisearch-mcp project this is based on.
Tool list:search_messages: proactively search the caller's indexed messages for continuity; optionally narrow by known conversation ID, sender, and result limit. Returns message ID, conversation ID, sender, and text.search_conversations: proactively find the caller's indexed conversations by title; returns conversation ID, title, and tags for follow-up message searches.admin_search_messages: explicitly requested, authorized search of a specified user's messages; returns the target user plus the documented message fields.admin_search_conversations: explicitly requested, authorized search of a specified user's conversations by title; returns the target user plus conversation ID, title, and tags.health-check: read the configured Meilisearch availability status.get-version: read Meilisearch version information.get-stats: read database-wide Meilisearch statistics.get-health-status: read structured health and index status.get-system-info: read Meilisearch system information.get-index-metrics: read metrics for one known index (indexUidrequired).- NOT YET IMPLEMENTED - returns error in default LibreChat setups. The returned
fieldDistributioncould be useful in a future topical graph construction for networked message searches, but in LibreChat's latest version of Meili this feature is experimental and must be enabled/created.
- NOT YET IMPLEMENTED - returns error in default LibreChat setups. The returned
User scoping
Normal searches are request- and caller-scoped by the service and accept no target user or raw filter. Administrative searches require service authorization and normally a target user; if authorization fails, do not retry or probe. The current implementation reports a generic search failure. All tools are read-only and return only the fields documented above.
Request-scoped tool behavior
What wasn't apparent to me from the start was how request-scoped (i.e., using message or conversation IDs in the MCP header) alter the UX. The MCP server is visible for selection overall, but the tools it offers are not - meaning you can't deselect the admin tools for a user-oriented agent (but there is some dynamism in how this server presents tools based on the user scope). Ideally we could configure server connection headers separately from tool use headers. I'm following the various MCP bugs/PRs in LibreChat to better understand what adjustments I can make to improve customizability.
Known issues
This server runs mostly as intended, and the following items are on my radar:Within the current project:
- Logs are too basic for troubleshooting (add request parameters and response metrics; optionally dump errors to json)
- Tool failure errors are non-descriptive (initially intentional for privacy preservation; agent needs more context for self-correction)
conversationId-filtered use ofsearch_messagesintermittently fails? (could be connection/threading/async related; TODO: add convo as filterable field)get-index-metricsrequires experimental feature enablement (TODO: test and explore this)- Documentation and code contain legacy/dev artifacts and inconsistencies
- User ID for targeted admin searches is tedious to acquire (TODO: explore PeoplePicker API to map to handle or name+initial)
Integration/activation effects:
- Tool selection not availalbe (due to request-scoped headers)
- Rapid-fire tool use in a sub-agent generates failure responses (threading and async functions need a closer look)
- Repeated search/discussion of historical topics dilutes those topics in future searches
- Conversation grouping is cumbersome and potentially token-expensive (TODO: add a function or feature to return conversation-grouped stats over message searches)
- Complex search scenarios are costly (TODO: server-side grouping, keyword/topic graph, multi-search union/intersect/exclude ops, dedup, ordering)
Security model
This tool is set up with the baseline assumption that the LibreChat deployment is single-tenant, single-policy, with no implemenation of security-specific models or providers!
Tools have basic user gating, and potentially vast admin scope:
- Normal tools:
search_messagesandsearch_conversationsalways search only the caller's user. The model cannot provideuseror a raw Meilisearch filter. - Admin tools:
admin_search_messagesandadmin_search_conversationsrequire the caller'sUser-Idto exactly match an entry inMEILI_MCP_ADMINS. A targetuseris required unlessMEILI_MCP_ADMIN_SCOPE_ALL_USERS=true. - The MCP service receives a restricted, read-only Meilisearch key in
MEILI_MCP_KEY; never use or pass the Meilisearch master key. - Results are schema-limited. Normal results contain only
messageId,conversationId,sender, andtext; conversation results contain onlyconversationId,title, andtags. Admin results additionally include the selecteduser. - Missing, empty, or malformed identity fails closed. Authorization failures are intentionally generic and secrets are never returned.
Retrieved text is exactly whatever LibreChat indexed. Depending on the indexer and deployment, that may include assistant output, reasoning-like text, or tool traces. This MCP server cannot recover content LibreChat did not index; treat search results as potentially sensitive audit data.
SEE SECURITY.md FOR FURTHER CAUTIONS AND CAVEATS!!!
Stewardship
I already notify my corporate user base of the capability for IT sec-ops and me to view all data/history ("no expectation of privacy") - my assumption is you would do the same if applicable to your deployment, or you would not implement this in a scenario where it could violate any policies. This tool merely makes it easier for me to do what I already can (vs the MongoDB tools or Meili CLI), while also exposing histories from one provider/model/agent to another (in my deployments, this is not a concern - yet - because I haven't implemented any private models for secure content).
LibreChat setup
Copy or merge these example files into the LibreChat Compose project and input your specific keys/IDs/configs:
librechat-search-mcp/librechat.yaml.example: mergemcpSettingsandmcpServersinto the existinglibrechat.yamlfile. Note MCP header parameter mappings like{{LIBRECHAT_USER_ID}}must be configured exactly as given; LibreChat replaces them per request and these are part of the security model and filtering functionality.- Recommended if you agree with my motivations above for your deployment: in
librechat.yaml, disable the memory agent until/unless future LibreChat versions alter how its behavior impacts token costs and cross-conversation topic pollution - Note: recent LibreChat changes have altered memory tool behavior to specific opt-in in the
endpoints.agents.capabilitiessetting - add "memory" there if you want the agent to be able to write memories on demand.
- Recommended if you agree with my motivations above for your deployment: in
librechat-search-mcp/docker-compose.override.yml.example: merge thelibrechat-search-mcpservice into the existing Compose project. It is internal-only: it hasexpose: 8000, noports, and joins the Compose default network.librechat-search-mcp/.env.example: add these keys into your main LibreChat.env, and replace only the marked placeholders. I recommend adding it just below the existingSearchsection.
The MCP URL is http://librechat-search-mcp:8000/mcp. The MCP-visible server name remains chat-search for client comprehension. If LibreChat blocks private MCP destinations, retain the allowedAddresses/allowedDomains entries from librechat.yaml.example. CAUTION: a non-empty domain whitelist may affect other MCP servers, so merge intentionally.
MEILI_HOST_PORT=7700 is the host/Compose bridge variable used by the surrounding LibreChat deployment. The MCP container itself must use the Compose service URL http://meilisearch:${MEILI_HOST_PORT} (the example override constructs that value); LibreChat's existing MEILI_HOST=http://0.0.0.0:7700 is a separate host-facing setting and should not be replaced casually.
Find your (admin) user ID for explicit enablement
MEILI_MCP_ADMINS user IDs can be gleaned from any of the following methods (in order of typical ease of execution):
- in the UI in your browser:
- open the inspector/dev tools (ctrl+shift+i) and select the Network tab;
- from the Chat History conversation list, select a prior conversation (you might need to select an older one not currently in browser cache);
- the first API call recorded in the Networking tab loads the conversation header data in its
Responsesub-tab, which includes:user- this value is your ID (and this field is used in filtering searches within the server, or as thetarget-userparameter for theadmin_tools) - copy this (and ask other admins/grantees you choose to supply the same to you) into the.envfile as theMEILI_MCP_ADMINS[delimit a list with commas only];conversationId- this is the same ID used in parameters for thesearch_MCP tools, and it is noteworthy that this is the same as in the conversation's URL:http://localhost:3080/c/{conversationId};
- noteworthy about this project's functionality - the 3rd API call contains this conversation's messages list, similar in structure to how Meilisearch indexes them; this project uses the following keys:
conversationId- used by this project to exclude search results from the current chat by default, or for targeted filtering of messagessender- "User" or agent display nametext- the content of the message- future research considerations for desired functionality:
endpoint(or to a more targeted extent,model) could be used as a filter in conjunction with aMEILI_MCP_CONSTRAIN_ENDPOINT=truesetting (if private models/agents are separated from public provider ones) to disallow cross-endpoint message search accessparentMessageIdis already integrated as a result filter during tool use via LibreChat's{{LIBRECHAT_BODY_PARENTMESSAGEID}}dynamic variable in the header of MCP transport; I plan to reexamine search indexes for this as a potential method for targeted before/after buffers from search hit messages, ordering results deterministically, and graphing message chainscontentcontains tool call thoughts/reasoning (I don't recall seeing this in the indexed content, probably with good reason - a user searching message history likely expects to see hits where the title or message text match, not file/agentic internals)attachmentscontains tool call results (and potentiall RAG and/or uploaded file content) - similar tocontent, I don't expect this is indexedcreatedAtcould be used as a deterministic temporal ordering or even filtering key (Meili already returns hits in apparent temporal order but this could be influenced by relevance scoring as well) - this may also be reachable (albeit a slightly different value) via Meili index document metadata (timestamp the index was created/updated), but any time a reindex action is performed it could lose all value.
- LibreChat container logs (
docker compose logs api) immediately after you (as an admin user) perform an action from the LibreChat UI (CAUTION: not advisable if you have many concurrent users to conflate log results, as this does NOT display user names) - examining the
userstable in Mongo Express (if you have set this up separately, it's slighly easier to use its web UI) - examining the
userstable in the MongoDB (following is the same for bash or PowerShell; run from the LibreChat directory or where yourdocker-compose.ymlis located):
# open a shell terminal within the MongoDB container - this assumes the default LibreChat service name `mongodb`:
docker compose exec mongodb sh
# open a database shell terminal within the container's shell:
mongosh
# switch to the database used by LibreChat (see all with `show databases`):
use LibreChat
# display target user by `role` attribute == "ADMIN" (LibreChat also stores `email` and `username` which may be present/null depending on registration method):
db.users.find({role: "ADMIN"}).forEach(printjson)
# Alternatively, display the entire users collection (be careful with this if you have many users):
db.users.find().forEach(printjson)
# the hash string in the first key of returned JSONs is the `user` ID - assuming you've found yourself/chosen admins, grab just this hash value from the `ObjectId` construct:
# {
# _id: ObjectId('derp7bfe19e9268da678derp'), #### <- in this dummy example, derp7bfe19e9268da678derp is my user ID to add to MEILI_MCP_ADMINS ####
# name: 'krahnik blis',
# username: 'krahnik',
# email: '[email protected]',
# ...
# quit the mongosh terminal
quit
# exit the mongodb container shell terminal
exit
Generate a read-only permissioned key for the MCP server
Do NOT use the LibreChat MEILI_MASTER_KEY as your MEILI_MCP_KEY!
The repository includes cross-platform helpers to generate and validate the API key in one command.They do this by accessing the meilisearch container (so it must be running), generating a permissioned key,printing the key by default or optionally writing to a local file, and never editing LibreChat's primary .env.The output file method is optional and is refused if it alreadyexists unless --force/-Force is supplied; generated *.local.env files aregit-ignored and receive restrictive permissions where the platform supports them.
Run from the LibreChat directory after you have git cloned this repo into it:
bash:
# ensure the script is executable:
chmod +x librechat-search-mcp/scripts/generate-restricted-key.sh
# run the script in terminal mode:
./librechat-search-mcp/scripts/generate-restricted-key.sh
# OR, run it in file-output mode:
./librechat-search-mcp/scripts/generate-restricted-key.sh --output .librechat-search-mcp.local.env
PowerShell:
# run the script in terminal mode:
powershell.exe -ExecutionPolicy Bypass -File .\librechat-search-mcp\scripts\generate-restricted-key.ps1
# OR, run it in file-output mode:
powershell.exe -ExecutionPolicy Bypass -File .\librechat-search-mcp\scripts\generate-restricted-key.ps1 -Output .librechat-search-mcp.local.env
The output of the script contains validation tests for endpoint permissions and a dummy delete probe to ensure read-only permissions;the read-only permissioned key is printed at the end, or written to the file of your choice.
Example script outputThe script contains checks and messaging I used in debugging, which I've left in place for my own future sanity, and so can you:
[info] Working directory: /path/to/LibreChat
[info] Environment file: .env
[info] Meilisearch container: meilisearch
[info] Messages index: messages
[info] Conversations index: convos
[warning] MEILI_HOST used 0.0.0.0; using loopback for in-container requests.
[info] MEILI_HOST from .env: http://0.0.0.0:7700
[info] API URL used inside chat-meilisearch: http://127.0.0.1:7700
[info] MEILI_MASTER_KEY length: 32
[info] MEILI_MASTER_KEY SHA-256: d3907119a65e489d0202derp0ac65216a44derpb43bd8be71b7dderpb158ac67
[info] Testing Meilisearch connectivity from inside the container.
PASS /health -> HTTP 200
[info] Testing the MEILI_MASTER_KEY read from .env.
PASS .env master key accepted by /version
[info] Key contract payload: {"description":"LibreChat MCP search and read-only diagnostics","actions":["search","stats.get","metrics.get","indexes.get","settings.get","version"],"indexes":["messages","convos"],"expiresAt":null}
[info] Creating restricted key in chat-meilisearch.
[info] Restricted key created successfully.
[info] Generated key length: 64
[info] Validating read-only key contract.
PASS /health -> HTTP 200
PASS /version -> HTTP 200
PASS /stats -> HTTP 200
FAIL /metrics -> HTTP 400
{"message":"Getting metrics requires enabling the `metrics` experimental feature. See https://github.com/meilisearch/product/discussions/625","code":"feature_not_enabled","type":"invalid_request","link":"https://docs.meilisearch.com/errors#feature_not_enabled"}
PASS /indexes -> HTTP 200
PASS /indexes/messages/settings -> HTTP 200
PASS /indexes/convos/settings -> HTTP 200
[info] Testing that document deletion is rejected.
PASS DELETE /indexes/messages/documents/__mcp_read_only_probe__ -> HTTP 403
Restricted key was created, but one or more validation checks failed:
- /metrics returned HTTP 400
The key will still be returned below. Do not deploy it until the failures are understood.
394ederp18e6299f7fddderpbb485b77be7bb1d0906b29ade8derpebaf65de43
^ in this dummy example, 394ederp18e6299f7fddderpbb485b77be7bb1d0906b29ade8derpebaf65de43 is the key to use as MEILI_MCP_KEY in LibreChat's .env file.
Expected FAIL message
Presently, the /metrics endpoint is expected to fail due to this being an experimental feature in the Meilisearch version used by LibreChat;I'm researching potential utility and will update this repo with enablement instructions/scripting, should anything fruitful result.This means the get_index_metrics tool will return the error shown in the example script output above, until/unless you enable the feature yourself.
The following is a manual method to perform what is contained within the generate-restricted-key scripts,in case you have customized your implementation or encounter errors (or see the scripts for all their thorough glory):
Create one dedicated, read-only key for this service. Its exact action contract is:
searchstats.getmetrics.getindexes.getsettings.getversion
Scope the key to the two configured indexes (messages and convos, or your configured names). The global health endpoint is checked separately and does not require a write-capable role. Set expiresAt to null only when a non-expiring operational key is intentional, and store the returned key only in MEILI_MCP_KEY.
Create the key from a terminal in the chat-meilisearch(docker exec)/meilisearch(docker compose exec) container, NOT from the MCP container. The master key below is a placeholder in command history and must not be pasted into prompts, logs, or this repository:
curl -fsS -X POST "http://127.0.0.1:7700/keys" \
-H "Authorization: Bearer $MEILI_MASTER_KEY" \
-H "Content-Type: application/json" \
--data '{"description":"LibreChat MCP search and read-only diagnostics","actions":["search","stats.get","metrics.get","indexes.get","settings.get","version"],"indexes":["messages","convos"],"expiresAt":null}'
Do not add documents.*, indexes.create, indexes.delete, settings.* write actions, keys.*, tasks.cancel, or *. Never set MEILI_MCP_KEY equal to MEILI_MASTER_KEY.
Verify the contract before deploying the key with the following read-only probes. They must all return HTTP 200 (the JSON is intentionally discarded):
auth=(-H "Authorization: Bearer $MEILI_MCP_KEY" -H "Accept: application/json")
for path in /health /version /stats /metrics /indexes /indexes/messages/settings /indexes/convos/settings; do
code=$(curl -sS -o /dev/null -w '%{http_code}' "${auth[@]}" "http://127.0.0.1:7700/$path")
test "$code" = 200 || { printf 'unexpected %s: HTTP %s\n' "$path" "$code" >&2; exit 1; }
done
Then verify that a harmless delete probe is rejected. Use a sentinel document ID that is not present; do not replace this with a real document ID:
code=$(curl -sS -o /dev/null -w '%{http_code}' -X DELETE \
"${auth[@]}" "http://127.0.0.1:7700/indexes/messages/documents/__mcp_read_only_probe__")
case "$code" in 401|403) ;; *) printf 'write permission was not rejected: HTTP %s\n' "$code" >&2; exit 1;; esac
The same key is used by the MCP search and diagnostics paths. If any read-only probe returns 401/403, fix the key's action contract or index scope; do not substitute the master key or broaden permissions until writes are rejected.
Overabundance of keys and their deletion
CAUTION: running the above script/commands multiple times will create multiple orphan keys within Meilisearch. I recommend don't. But if you did,
here be dragons:- Either set an environment variable within the container with your master key, or replace the following instances of
$MEILI_MASTER_KEYwith your real key - From a terminal within the primary Meilisearch container, first list all keys:
curl -sS -H "Authorization: Bearer $MEILI_MASTER_KEY" "http://127.0.0.1:7700/keys" - Locate the keys labeled by this project's creation script, they will have the
description"LibreChat MCP search and read-only diagnostics" - Choose whichever are not the key you intend to keep, and get their
uids - For each key to delete, run (replace
KEY_UIDwith your real value):curl -sS -X DELETE -H "Authorization: Bearer $MEILI_MASTER_KEY" "http://127.0.0.1:7700/keys/KEY_UID"
Full setup command sequence
Run the following commands one-by-one interactively (obvs Windows users can skip the cat/nano crap and use notepad/IDE):
cd LibreChat
# this creates the folder librechat-search-mcp WITHIN the LibreChat Compose scope:
git clone https://github.com/krahnikblis/librechat-search-mcp.git
# assuming the baseline LibreChat Compose services are already running, this creates & tests the restricted API key to set manually into the LibreChat .env MEILI_MCP_KEY:
# see above/README page for details and/or PowerShell equivalent commands
# either write to a local file:
./librechat-search-mcp/scripts/generate-restricted-key.sh --output .librechat-search-mcp.local.env
# OR print to the terminal:
./librechat-search-mcp/scripts/generate-restricted-key.sh
# print the example to copy as template:
cat librechat-search-mcp/.env.example
# copy or merge the example MEILI_MCP_ variables, including the key generated in the prior step into .env:
nano .env
# print the example to copy as template:
cat librechat-search-mcp/docker-compose.override.yml.example
# copy or merge the example configurations from the example into docker-compose.override.yml
nano docker-compose.override.yml
# print the example to copy as template:
cat librechat-search-mcp/librechat.yaml.example
# copy or merge the MCP [and optional agent capabilities and memory agent changes] configurations into librechat.yaml:
nano librechat.yaml
# validate config:
docker compose config
# stop existing services to recreate the LibreChat container with the MCP settings:
docker compose down
# build the image:
docker compose build librechat-search-mcp
# start all Compose services together:
docker compose up -d
# check logs for the new service:
docker compose logs --tail=100 librechat-search-mcp
If all went well, this MCP will be available in your LibreChat UI!
Environment and index contract
dotenv variablesRequired:
MEILI_MCP_KEY=<restricted-search-key>
MEILI_MCP_ADMINS=<admin,list>
Important values in .env:
MEILI_HOST_PORT=7700
MEILI_MCP_PORT=8000
MEILI_MCP_MESSAGES_INDEX=messages
MEILI_MCP_CONVOS_INDEX=convos
MEILI_MCP_DEFAULT_LIMIT=5
MEILI_MCP_MAX_LIMIT=25
MEILI_MCP_ADMIN_SCOPE_ALL_USERS=false
MEILI_MCP_LOG_HOST_DIR=<local/log/path>
Both indexes must contain a filterable user attribute (already existing by LibreChat design).The messages index created by LibreChat does not have a filterable conversationId;this and other parameters for MCP search tools are handled server-side before returning to the caller.
Log mount and persistence
The container writes structured JSON-lines logs to /var/log/librechat-search-mcp.The Compose example bind-mounts that directory to ${MEILI_MCP_LOG_HOST_DIR};its default is ./librechat-search-mcp/logs relative to the parent LibreChatCompose project. Log files are named librechat-search-mcp-YYYY-MM-DD.log, sorecreating the container does not remove existing host-side logs. Keep thishost directory private and back it up or rotate it according to your deploymentpolicy. To use the parent project's conventional log directory instead, setMEILI_MCP_LOG_HOST_DIR=./logs in the local .env; do not commit that populatedfile or generated logs.
Run the read-only contract check from the librechat-search-mcp container:
bash/PowerShell:
# The image's WORKDIR is /app and Compose injects MEILI_HOST plus the
# restricted MEILI_MCP_KEY into the service.
# the script was copied into the container as part of image build
docker compose exec -T -w /app librechat-search-mcp python scripts/check_index_contract.py
The script is copied into the image at /app/scripts/check_index_contract.py.It checks health, index names, primary keys, filterability, and sortableattributes without mutating settings or printing the key. Exit status 0 andJSON "status": "pass" mean the contract passed; a nonzero exit status meansthe reported health, index, settings, or required-filter check failed. It is adiagnostic, not an MCP readiness probe. /health only confirms that the MCPprocess is alive.
Caller prompts and expected behavior
Start a fresh LibreChat conversation after configuration and containers are running(e.g., in UI's MCP sidebar, Agent Builder, and/or the chat box's MCP Servers drop-down)so the model discovers the current tool list.
Tool descriptions are written to encourage agentic use proactively for the standard search tools,while the admin_ variants are given "user-invoked first use" instructions. I'll probably tunethese instructions in future updates based on my experience - I've already seen some interestingproactive usage which seemed unnecessary or was too broad...
NOTE: Small local models may need the tool named explicitly in prompts.
Example test promptsNormal search - explicit instruction:
Use search_conversations with query "deployment" and limit 3. Return only conversationId, title, and tags.
Use search_messages with query "deployment" and limit 3. Return only messageId, conversationId, sender, and text.
Intended proactive use of normal search:
Hey remember that time we went wild designing a giant robotic grackle? I have some ideas about how to combine it with the ornithopter we discussed last week...
The agent should proactively run a search with query resembling "grackle ornithopter", and you should see matching messages from multiple conversations.
Intended search agent design:
This tool alone comes with generic setup and tool descriptions, but the real fun will be in building a dedicated agent and/or an informative SKILL.md for shaping memory-like behavior. Because the results of these tools are full messages, token costs could still be substantial, so a sub-agent built on a cheaper model but given instructions to recursively trace topics across interconnected conversations and then return a detailed symmary/synthesis is probably how I'll deploy this to my team in their default agent.
Targeted admin audit (only from an allowlisted account):
On my to-do list is to research the LibreChat PeoplePicker API and see how/if it's exposed within the Compose network - ideally an admin could name a user by handle or first name, and if PeoplePicker is enabled, the agent could do a lookup for the internal ID (or perhaps bypass the agent and perform lookup targeted filtering/erroring within the server like "2 'Sally's found: did you mean Sally X. or Sally Y.?", without exposing email or full name to the agent)...
Use admin_search_messages for target user "<target-user-id>" with query "deployment" and limit 3.
Intended admin scope (debugging, prompt/conversation optimization, collective attention)
What are our team members saying overall about our company's brand presense in the FIFA World Cup?
Let's review <target-user-id>'s conversation <conversationId> - what initial prompt and context would have elicited the final answer more directly?
Boundary checks:
Try to search another user's messages by supplying a user argument and a raw filter. Do not bypass the tool schema; report whether the request was rejected and do not return cross-user results.
Find messages before and after this hit using createdAt, reconstruct surrounding messages through MongoDB, and sort by timestamp.
The latter is unsupported: this project does not add timestamp ordering, before/after retrieval, MongoDB/API lookup, surrounding-message reconstruction, or arbitrary sorting. Sender and conversation filters are bounded post-filters, so fewer than the requested limit is valid and original Meilisearch hit order is retained.
Verification
TestsLocal checks (from within this project's folder under LibreChat):
python -m pytest tests/test_monitoring.py tests/test_m2_contract.py tests/test_m2_authorization.py tests/test_m1_search.py tests/test_server.py -q
python -m compileall -q src scripts tests
git diff --check
Deployment checks still require a running LibreChat/Meilisearch stack: verify fresh-session tool discovery, the User-Id header, restricted-key permissions, index contract, no host port publication, and concurrent requests from two users. Do not treat local unit tests as proof of live caller behavior.
Deployment and troubleshooting
- See
docs/deployment.mdfor the supported Docker Compose boundary, safe configuration order, service identities, and thecontainer_nametradeoff. - See
docs/troubleshooting.mdfor common Compose, key-generation, networking, MCP discovery, index, and logging failures. - See
SECURITY.mdbefore enabling the service. It covers indexed content, AI-provider exposure, identity and admin scope, logs/retention, restricted keys, trust boundaries, and what this project does not guarantee.
Development
- See
docs/tool-descriptions.mdfor the agent-facing tool contract. - See
ATTRIBUTION.mdfor upstream provenance and licensing. - Development, planning, audit, and internal decision records are intentionally maintained outside the production repository in
workspace/project-context/librechat-search-mcp/development-records/.
I mean, if anyone wants to contribute stuff, open a discussion or issue or whatevs; I could see about adding a Contributing section and learn how PRs work... but really this is just my own hobby thing which I know will have great value to me at work too, and the easiest conduit from hurr to thurr is through publishing on GitHub. I.e., I like to make stuff and solve problems, but I offer no commitment to pay attention to anyone else's issues, and will probably prioritize what is either awesome feature enablement or close any gaps.