🔒 fix: Restrict MCP Stdio Transport via API (#11184)
Some checks failed
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Has been cancelled
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Has been cancelled
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Has been cancelled
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Has been cancelled
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Has been cancelled
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Has been cancelled

- Updated MCP server configuration tests to reject stdio transport configurations, ensuring that only remote transports (SSE, HTTP, WebSocket) are allowed via the API.
- Enhanced documentation to clarify that stdio transport is excluded from user input for security, as it allows arbitrary command execution and should only be configured by administrators through YAML files.
This commit is contained in:
Danny Avila 2026-01-03 12:47:11 -05:00 committed by GitHub
parent 4d6ea3b182
commit 211b39f311
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 12 additions and 12 deletions

View file

@ -1553,23 +1553,19 @@ describe('MCP Routes', () => {
);
});
it('should create MCP server with valid stdio config', async () => {
const validConfig = {
it('should reject stdio config for security reasons', async () => {
const stdioConfig = {
type: 'stdio',
command: 'node',
args: ['server.js'],
title: 'Test Stdio Server',
};
mockRegistryInstance.addServer.mockResolvedValue({
serverName: 'test-stdio-server',
config: validConfig,
});
const response = await request(app).post('/api/mcp/servers').send({ config: stdioConfig });
const response = await request(app).post('/api/mcp/servers').send({ config: validConfig });
expect(response.status).toBe(201);
expect(response.body.serverName).toBe('test-stdio-server');
// Stdio transport is not allowed via API - only admins can configure it via YAML
expect(response.status).toBe(400);
expect(response.body.message).toBe('Invalid configuration');
});
it('should return 400 for invalid configuration', async () => {

View file

@ -221,12 +221,16 @@ const omitServerManagedFields = <T extends z.ZodObject<z.ZodRawShape>>(schema: T
});
/**
* MCP Server configuration that comes from UI input only
* MCP Server configuration that comes from UI/API input only.
* Omits server-managed fields like startup, timeout, customUserVars, etc.
* Allows: title, description, url, iconPath, oauth (user credentials)
*
* SECURITY: Stdio transport is intentionally excluded from user input.
* Stdio allows arbitrary command execution and should only be configured
* by administrators via the YAML config file (librechat.yaml).
* Only remote transports (SSE, HTTP, WebSocket) are allowed via the API.
*/
export const MCPServerUserInputSchema = z.union([
omitServerManagedFields(StdioOptionsSchema),
omitServerManagedFields(WebSocketOptionsSchema),
omitServerManagedFields(SSEOptionsSchema),
omitServerManagedFields(StreamableHTTPOptionsSchema),