mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-22 08:12:00 +02:00
🗝️ feat: User Provided Credentials for MCP Servers (#7980)
* 🗝️ feat: Per-User Credentials for MCP Servers
chore: add aider to gitignore
feat: fill custom variables to MCP server
feat: replace placeholders with custom user MCP variables
feat: handle MCP install/uninstall (uses pluginauths)
feat: add MCP custom variables dialog to MCPSelect
feat: add MCP custom variables dialog to the side panel
feat: do not require to fill MCP credentials for in tools dialog
feat: add translations keys (en+cs) for custom MCP variables
fix: handle LIBRECHAT_USER_ID correctly during MCP var replacement
style: remove unused MCP translation keys
style: fix eslint for MCP custom vars
chore: move aider gitignore to AI section
* feat: Add Plugin Authentication Methods to data-schemas
* refactor: Replace PluginAuth model methods with new utility functions for improved code organization and maintainability
* refactor: Move IPluginAuth interface to types directory for better organization and update pluginAuth schema to use the new import
* refactor: Remove unused getUsersPluginsAuthValuesMap function and streamline PluginService.js; add new getPluginAuthMap function for improved plugin authentication handling
* chore: fix typing for optional tools property with GenericTool[] type
* chore: update librechat-data-provider version to 0.7.88
* refactor: optimize getUserMCPAuthMap function by reducing variable usage and improving server key collection logic
* refactor: streamline MCP tool creation by removing customUserVars parameter and enhancing user-specific authentication handling to avoid closure encapsulation
* refactor: extract processSingleValue function to streamline MCP environment variable processing and enhance readability
* refactor: enhance MCP tool processing logic by simplifying conditions and improving authentication handling for custom user variables
* ci: fix action tests
* chore: fix imports, remove comments
* chore: remove non-english translations
* fix: remove newline at end of translation.json file
---------
Co-authored-by: Aleš Kůtek <kutekales@gmail.com>
This commit is contained in:
parent
8b15bb2ed6
commit
3e4b01de82
36 changed files with 1536 additions and 166 deletions
|
@ -1,6 +1,6 @@
|
|||
const { logger } = require('@librechat/data-schemas');
|
||||
const { encrypt, decrypt } = require('@librechat/api');
|
||||
const { PluginAuth } = require('~/db/models');
|
||||
const { findOnePluginAuth, updatePluginAuth, deletePluginAuth } = require('~/models');
|
||||
|
||||
/**
|
||||
* Asynchronously retrieves and decrypts the authentication value for a user's plugin, based on a specified authentication field.
|
||||
|
@ -25,7 +25,7 @@ const { PluginAuth } = require('~/db/models');
|
|||
*/
|
||||
const getUserPluginAuthValue = async (userId, authField, throwError = true) => {
|
||||
try {
|
||||
const pluginAuth = await PluginAuth.findOne({ userId, authField }).lean();
|
||||
const pluginAuth = await findOnePluginAuth({ userId, authField });
|
||||
if (!pluginAuth) {
|
||||
throw new Error(`No plugin auth ${authField} found for user ${userId}`);
|
||||
}
|
||||
|
@ -79,23 +79,12 @@ const getUserPluginAuthValue = async (userId, authField, throwError = true) => {
|
|||
const updateUserPluginAuth = async (userId, authField, pluginKey, value) => {
|
||||
try {
|
||||
const encryptedValue = await encrypt(value);
|
||||
const pluginAuth = await PluginAuth.findOne({ userId, authField }).lean();
|
||||
if (pluginAuth) {
|
||||
return await PluginAuth.findOneAndUpdate(
|
||||
{ userId, authField },
|
||||
{ $set: { value: encryptedValue } },
|
||||
{ new: true, upsert: true },
|
||||
).lean();
|
||||
} else {
|
||||
const newPluginAuth = await new PluginAuth({
|
||||
userId,
|
||||
authField,
|
||||
value: encryptedValue,
|
||||
pluginKey,
|
||||
});
|
||||
await newPluginAuth.save();
|
||||
return newPluginAuth.toObject();
|
||||
}
|
||||
return await updatePluginAuth({
|
||||
userId,
|
||||
authField,
|
||||
pluginKey,
|
||||
value: encryptedValue,
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error('[updateUserPluginAuth]', err);
|
||||
return err;
|
||||
|
@ -105,26 +94,25 @@ const updateUserPluginAuth = async (userId, authField, pluginKey, value) => {
|
|||
/**
|
||||
* @async
|
||||
* @param {string} userId
|
||||
* @param {string} authField
|
||||
* @param {boolean} [all]
|
||||
* @param {string | null} authField - The specific authField to delete, or null if `all` is true.
|
||||
* @param {boolean} [all=false] - Whether to delete all auths for the user (or for a specific pluginKey if provided).
|
||||
* @param {string} [pluginKey] - Optional. If `all` is true and `pluginKey` is provided, delete all auths for this user and pluginKey.
|
||||
* @returns {Promise<import('mongoose').DeleteResult>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
const deleteUserPluginAuth = async (userId, authField, all = false) => {
|
||||
if (all) {
|
||||
try {
|
||||
const response = await PluginAuth.deleteMany({ userId });
|
||||
return response;
|
||||
} catch (err) {
|
||||
logger.error('[deleteUserPluginAuth]', err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
const deleteUserPluginAuth = async (userId, authField, all = false, pluginKey) => {
|
||||
try {
|
||||
return await PluginAuth.deleteOne({ userId, authField });
|
||||
return await deletePluginAuth({
|
||||
userId,
|
||||
authField,
|
||||
pluginKey,
|
||||
all,
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error('[deleteUserPluginAuth]', err);
|
||||
logger.error(
|
||||
`[deleteUserPluginAuth] Error deleting ${all ? 'all' : 'single'} auth(s) for userId: ${userId}${pluginKey ? ` and pluginKey: ${pluginKey}` : ''}`,
|
||||
err,
|
||||
);
|
||||
return err;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue