mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
nicely refactored mcp add done
This commit is contained in:
parent
234827dc57
commit
568ec2f7d5
5 changed files with 22 additions and 240 deletions
|
|
@ -1,17 +1,17 @@
|
||||||
import React, { useState, useCallback, useMemo, useEffect } from 'react';
|
|
||||||
import { ChevronLeft } from 'lucide-react';
|
import { ChevronLeft } from 'lucide-react';
|
||||||
import { Constants } from 'librechat-data-provider';
|
import { Constants } from 'librechat-data-provider';
|
||||||
import { useForm, Controller } from 'react-hook-form';
|
import { useForm, Controller } from 'react-hook-form';
|
||||||
|
import React, { useState, useCallback, useMemo, useEffect } from 'react';
|
||||||
import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query';
|
import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query';
|
||||||
import type { TUpdateUserPlugins } from 'librechat-data-provider';
|
import type { TUpdateUserPlugins } from 'librechat-data-provider';
|
||||||
import type { MCP } from 'librechat-data-provider';
|
import type { MCP } from 'librechat-data-provider';
|
||||||
|
import { useCreateMCPMutation } from '~/data-provider';
|
||||||
import { Button, Input, Label } from '~/components/ui';
|
import { Button, Input, Label } from '~/components/ui';
|
||||||
import { useGetStartupConfig } from '~/data-provider';
|
import { useGetStartupConfig } from '~/data-provider';
|
||||||
import { useAddToolMutation } from '~/data-provider/Tools/mutations';
|
|
||||||
import MCPPanelSkeleton from './MCPPanelSkeleton';
|
import MCPPanelSkeleton from './MCPPanelSkeleton';
|
||||||
import { useToastContext } from '~/Providers';
|
import { useToastContext } from '~/Providers';
|
||||||
import { useLocalize } from '~/hooks';
|
|
||||||
import MCPFormPanel from './MCPFormPanel';
|
import MCPFormPanel from './MCPFormPanel';
|
||||||
|
import { useLocalize } from '~/hooks';
|
||||||
|
|
||||||
interface ServerConfigWithVars {
|
interface ServerConfigWithVars {
|
||||||
serverName: string;
|
serverName: string;
|
||||||
|
|
@ -61,7 +61,7 @@ export default function MCPPanel() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const createMCPMutation = useAddToolMutation({
|
const create = useCreateMCPMutation({
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
showToast({
|
showToast({
|
||||||
message: localize('com_ui_update_mcp_success'),
|
message: localize('com_ui_update_mcp_success'),
|
||||||
|
|
@ -119,20 +119,7 @@ export default function MCPPanel() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveMCP = (mcp: MCP) => {
|
const handleSaveMCP = (mcp: MCP) => {
|
||||||
// Transform MCP data to match the expected format
|
create.mutate(mcp);
|
||||||
const mcpData = {
|
|
||||||
name: mcp.metadata.name || '',
|
|
||||||
description: mcp.metadata.description || '',
|
|
||||||
url: mcp.metadata.url || '',
|
|
||||||
icon: mcp.metadata.icon || '',
|
|
||||||
tools: mcp.metadata.tools || [],
|
|
||||||
trust: mcp.metadata.trust ?? false,
|
|
||||||
customHeaders: mcp.metadata.customHeaders || [],
|
|
||||||
requestTimeout: mcp.metadata.requestTimeout,
|
|
||||||
connectionTimeout: mcp.metadata.connectionTimeout,
|
|
||||||
};
|
|
||||||
|
|
||||||
createMCPMutation.mutate(mcpData);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (showMCPForm) {
|
if (showMCPForm) {
|
||||||
|
|
|
||||||
|
|
@ -41,32 +41,14 @@ export const useToolCallMutation = <T extends t.ToolId>(
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface CreateToolData {
|
export const useCreateMCPMutation = (
|
||||||
name: string;
|
options?: t.CreateMCPMutationOptions,
|
||||||
description: string;
|
): UseMutationResult<Record<string, unknown>, Error, t.MCP> => {
|
||||||
metadata?: Record<string, unknown>;
|
|
||||||
// MCP-specific fields
|
|
||||||
url?: string;
|
|
||||||
icon?: string;
|
|
||||||
tools?: string[];
|
|
||||||
trust?: boolean;
|
|
||||||
customHeaders?: Array<{
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
value: string;
|
|
||||||
}>;
|
|
||||||
requestTimeout?: number;
|
|
||||||
connectionTimeout?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useAddToolMutation = (
|
|
||||||
options?: t.MutationOptions<Record<string, unknown>, CreateToolData>,
|
|
||||||
): UseMutationResult<Record<string, unknown>, Error, CreateToolData> => {
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
return useMutation(
|
return useMutation(
|
||||||
(toolData: CreateToolData) => {
|
(mcp: t.MCP) => {
|
||||||
return dataService.createTool(toolData);
|
return dataService.createMCP(mcp);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onMutate: (variables) => options?.onMutate?.(variables),
|
onMutate: (variables) => options?.onMutate?.(variables),
|
||||||
|
|
@ -74,7 +56,7 @@ export const useAddToolMutation = (
|
||||||
onSuccess: (data, variables, context) => {
|
onSuccess: (data, variables, context) => {
|
||||||
// Invalidate tools list to trigger refetch
|
// Invalidate tools list to trigger refetch
|
||||||
queryClient.invalidateQueries([QueryKeys.tools]);
|
queryClient.invalidateQueries([QueryKeys.tools]);
|
||||||
queryClient.invalidateQueries([QueryKeys.mcpTools]);
|
// queryClient.invalidateQueries([QueryKeys.mcpTools]);
|
||||||
return options?.onSuccess?.(data, variables, context);
|
return options?.onSuccess?.(data, variables, context);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,154 +1,8 @@
|
||||||
import { Request, Response } from 'express';
|
import { MCP } from 'librechat-data-provider';
|
||||||
import { logger } from '@librechat/data-schemas';
|
import { Response } from 'express';
|
||||||
|
|
||||||
interface MCPCreateRequest extends Request {
|
// just log the request
|
||||||
body: {
|
export const addTool = (req: { body: MCP }, res: Response) => {
|
||||||
name: string;
|
console.log(JSON.stringify(req.body, null, 2));
|
||||||
description: string;
|
res.send('ok');
|
||||||
url: string;
|
|
||||||
icon?: string;
|
|
||||||
tools?: string[];
|
|
||||||
trust: boolean;
|
|
||||||
customHeaders?: Array<{
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
value: string;
|
|
||||||
}>;
|
|
||||||
requestTimeout?: number;
|
|
||||||
connectionTimeout?: number;
|
|
||||||
};
|
|
||||||
user?: {
|
|
||||||
id: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MCPCreateResponse {
|
|
||||||
mcp_id: string;
|
|
||||||
metadata: {
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
url: string;
|
|
||||||
icon?: string;
|
|
||||||
tools?: string[];
|
|
||||||
trust: boolean;
|
|
||||||
customHeaders?: Array<{
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
value: string;
|
|
||||||
}>;
|
|
||||||
requestTimeout?: number;
|
|
||||||
connectionTimeout?: number;
|
|
||||||
};
|
|
||||||
created_at: string;
|
|
||||||
updated_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MCPCreateError {
|
|
||||||
error: string;
|
|
||||||
message?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a new tool/MCP to the system
|
|
||||||
* @route POST /agents/tools/add
|
|
||||||
* @param {object} req.body - Request body containing tool/MCP data
|
|
||||||
* @param {string} req.body.name - Tool/MCP name
|
|
||||||
* @param {string} req.body.description - Tool/MCP description
|
|
||||||
* @param {string} req.body.url - Tool/MCP server URL
|
|
||||||
* @param {string} [req.body.icon] - Tool/MCP icon (base64)
|
|
||||||
* @param {string[]} [req.body.tools] - Available tools
|
|
||||||
* @param {boolean} req.body.trust - Trust flag
|
|
||||||
* @param {string[]} [req.body.customHeaders] - Custom headers
|
|
||||||
* @param {string} [req.body.requestTimeout] - Request timeout
|
|
||||||
* @param {string} [req.body.connectionTimeout] - Connection timeout
|
|
||||||
* @returns {object} Created tool/MCP object
|
|
||||||
*/
|
|
||||||
export const addTool = async (req: MCPCreateRequest, res: Response) => {
|
|
||||||
try {
|
|
||||||
const {
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
url,
|
|
||||||
icon,
|
|
||||||
tools,
|
|
||||||
trust,
|
|
||||||
customHeaders,
|
|
||||||
requestTimeout,
|
|
||||||
connectionTimeout,
|
|
||||||
} = req.body;
|
|
||||||
|
|
||||||
// Log the raw request body for debugging
|
|
||||||
logger.info('Raw request body: ' + JSON.stringify(req.body, null, 2));
|
|
||||||
|
|
||||||
// Log the incoming tool/MCP request for development
|
|
||||||
const logData = {
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
url,
|
|
||||||
icon: icon ? 'base64_icon_provided' : 'no_icon',
|
|
||||||
tools: tools || [],
|
|
||||||
trust,
|
|
||||||
customHeaders: customHeaders || [],
|
|
||||||
timeouts: {
|
|
||||||
requestTimeout: requestTimeout || 'default',
|
|
||||||
connectionTimeout: connectionTimeout || 'default',
|
|
||||||
},
|
|
||||||
userId: req.user?.id,
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
};
|
|
||||||
|
|
||||||
logger.info('Add Tool/MCP Request: ' + JSON.stringify(logData, null, 2));
|
|
||||||
|
|
||||||
// Validate required fields
|
|
||||||
if (!name || !description || !url) {
|
|
||||||
return res.status(400).json({
|
|
||||||
error: 'Missing required fields: name, description, and url are required',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate URL format
|
|
||||||
try {
|
|
||||||
new URL(url);
|
|
||||||
} catch {
|
|
||||||
return res.status(400).json({
|
|
||||||
error: 'Invalid URL format',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate trust flag
|
|
||||||
if (typeof trust !== 'boolean') {
|
|
||||||
return res.status(400).json({
|
|
||||||
error: 'Trust flag must be a boolean value',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// For now, return a mock successful response
|
|
||||||
// TODO: Implement actual tool/MCP creation logic
|
|
||||||
const mockTool = {
|
|
||||||
mcp_id: `mcp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
||||||
metadata: {
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
url,
|
|
||||||
icon: icon || undefined,
|
|
||||||
tools: tools || [],
|
|
||||||
trust,
|
|
||||||
customHeaders: customHeaders || [],
|
|
||||||
requestTimeout,
|
|
||||||
connectionTimeout,
|
|
||||||
},
|
|
||||||
created_at: new Date().toISOString(),
|
|
||||||
updated_at: new Date().toISOString(),
|
|
||||||
};
|
|
||||||
|
|
||||||
logger.info('Tool/MCP created successfully:', JSON.stringify(mockTool, null, 2));
|
|
||||||
|
|
||||||
res.status(201).json(mockTool);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Error adding tool/MCP:', error);
|
|
||||||
res.status(500).json({
|
|
||||||
error: 'Internal server error while adding tool/MCP',
|
|
||||||
message: error instanceof Error ? error.message : 'Unknown error',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -833,54 +833,11 @@ export const createMemory = (data: {
|
||||||
return request.post(endpoints.memories(), data);
|
return request.post(endpoints.memories(), data);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createTool = (toolData: {
|
export const createMCP = (mcp: ag.MCP): Promise<Record<string, unknown>> => {
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
metadata?: Record<string, unknown>;
|
|
||||||
// MCP-specific fields
|
|
||||||
url?: string;
|
|
||||||
icon?: string;
|
|
||||||
tools?: string[];
|
|
||||||
trust?: boolean;
|
|
||||||
customHeaders?: Array<{
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
value: string;
|
|
||||||
}>;
|
|
||||||
requestTimeout?: number;
|
|
||||||
connectionTimeout?: number;
|
|
||||||
}): Promise<{
|
|
||||||
id?: string;
|
|
||||||
mcp_id?: string;
|
|
||||||
type?: string;
|
|
||||||
function?: {
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
};
|
|
||||||
metadata:
|
|
||||||
| Record<string, unknown>
|
|
||||||
| {
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
url?: string;
|
|
||||||
icon?: string;
|
|
||||||
tools?: string[];
|
|
||||||
trust?: boolean;
|
|
||||||
customHeaders?: Array<{
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
value: string;
|
|
||||||
}>;
|
|
||||||
requestTimeout?: number;
|
|
||||||
connectionTimeout?: number;
|
|
||||||
};
|
|
||||||
created_at: string;
|
|
||||||
updated_at: string;
|
|
||||||
}> => {
|
|
||||||
return request.post(
|
return request.post(
|
||||||
endpoints.agents({
|
endpoints.agents({
|
||||||
path: 'tools/add',
|
path: 'tools/add',
|
||||||
}),
|
}),
|
||||||
toolData,
|
mcp,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import {
|
||||||
AgentCreateParams,
|
AgentCreateParams,
|
||||||
AgentUpdateParams,
|
AgentUpdateParams,
|
||||||
} from './assistants';
|
} from './assistants';
|
||||||
import { Action, ActionMetadata } from './agents';
|
import { Action, ActionMetadata, MCP } from './agents';
|
||||||
|
|
||||||
export type MutationOptions<
|
export type MutationOptions<
|
||||||
Response,
|
Response,
|
||||||
|
|
@ -319,6 +319,8 @@ export type AcceptTermsMutationOptions = MutationOptions<
|
||||||
/* Tools */
|
/* Tools */
|
||||||
export type UpdatePluginAuthOptions = MutationOptions<types.TUser, types.TUpdateUserPlugins>;
|
export type UpdatePluginAuthOptions = MutationOptions<types.TUser, types.TUpdateUserPlugins>;
|
||||||
|
|
||||||
|
export type CreateMCPMutationOptions = MutationOptions<Record<string, unknown>, MCP>;
|
||||||
|
|
||||||
export type ToolParamsMap = {
|
export type ToolParamsMap = {
|
||||||
[Tools.execute_code]: {
|
[Tools.execute_code]: {
|
||||||
lang: string;
|
lang: string;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue