👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993)

* 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api`

* 🔧 refactor: Update resolveHeaders import paths

* 🔧 refactor: Enhance resolveHeaders to support user and custom variables

- Updated resolveHeaders function to accept user and custom user variables for placeholder replacement.
- Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality.
- Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables.

* 🔧 fix: Update user ID placeholder processing in env.ts

* 🔧 fix: Remove arguments passing this.user rather than req.user

- Updated multiple client and controller files to call resolveHeaders without the user parameter

* 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested

* 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts

* chore: remove legacy ChatGPTClient

* chore: remove LLM initialization code

* chore: initial deprecation removal of `gptPlugins`

* chore: remove cohere-ai dependency from package.json and package-lock.json

* chore: update brace-expansion to version 2.0.2 and add license information

* chore: remove PluginsClient test file

* chore: remove legacy

* ci: remove deprecated sendMessage/getCompletion/chatCompletion tests

---------

Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
This commit is contained in:
Danny Avila 2025-06-23 12:39:27 -04:00 committed by GitHub
parent 01e9b196bc
commit a058963a9f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 542 additions and 2844 deletions

View file

@ -2,7 +2,7 @@ import { logger } from '@librechat/data-schemas';
import { CallToolResultSchema, ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
import type { RequestOptions } from '@modelcontextprotocol/sdk/shared/protocol.js';
import type { OAuthClientInformation } from '@modelcontextprotocol/sdk/shared/auth.js';
import type { JsonSchemaType, MCPOptions, TUser } from 'librechat-data-provider';
import type { JsonSchemaType, TUser } from 'librechat-data-provider';
import type { TokenMethods } from '@librechat/data-schemas';
import type { FlowStateManager } from '~/flow/manager';
import type { MCPOAuthTokens, MCPOAuthFlowMetadata } from './oauth/types';
@ -13,6 +13,7 @@ import { MCPOAuthHandler } from './oauth/handler';
import { MCPTokenStorage } from './oauth/tokens';
import { formatToolContent } from './parsers';
import { MCPConnection } from './connection';
import { processMCPEnv } from '~/utils/env';
export class MCPManager {
private static instance: MCPManager | null = null;
@ -24,11 +25,6 @@ export class MCPManager {
private userLastActivity: Map<string, number> = new Map();
private readonly USER_CONNECTION_IDLE_TIMEOUT = 15 * 60 * 1000; // 15 minutes (TODO: make configurable)
private mcpConfigs: t.MCPServers = {};
private processMCPEnv?: (
obj: MCPOptions,
user?: TUser,
customUserVars?: Record<string, string>,
) => MCPOptions; // Store the processing function
/** Store MCP server instructions */
private serverInstructions: Map<string, string> = new Map();
@ -46,14 +42,11 @@ export class MCPManager {
mcpServers,
flowManager,
tokenMethods,
processMCPEnv,
}: {
mcpServers: t.MCPServers;
flowManager: FlowStateManager<MCPOAuthTokens | null>;
tokenMethods?: TokenMethods;
processMCPEnv?: (obj: MCPOptions) => MCPOptions;
}): Promise<void> {
this.processMCPEnv = processMCPEnv; // Store the function
this.mcpConfigs = mcpServers;
if (!flowManager) {
@ -68,7 +61,7 @@ export class MCPManager {
const connectionResults = await Promise.allSettled(
entries.map(async ([serverName, _config], i) => {
/** Process env for app-level connections */
const config = this.processMCPEnv ? this.processMCPEnv(_config) : _config;
const config = processMCPEnv(_config);
/** Existing tokens for system-level connections */
let tokens: MCPOAuthTokens | null = null;
@ -444,9 +437,7 @@ export class MCPManager {
);
}
if (this.processMCPEnv) {
config = { ...(this.processMCPEnv(config, user, customUserVars) ?? {}) };
}
config = { ...(processMCPEnv(config, user, customUserVars) ?? {}) };
/** If no in-memory tokens, tokens from persistent storage */
let tokens: MCPOAuthTokens | null = null;
if (tokenMethods?.findToken) {