| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- /**
- * File Management Tools
- *
- * MCP tools for managing files in the admin system.
- * Note: Only metadata management is supported, binary upload is not available.
- */
- import { getApiClient } from '../services/api-client.js';
- import {
- FileListInputSchema,
- FileGetInputSchema,
- FileDeleteInputSchema
- } from '../schemas/index.js';
- import type {
- FileListInput,
- FileGetInput,
- FileDeleteInput
- } from '../schemas/index.js';
- import { CHARACTER_LIMIT, ResponseFormat } from '../constants.js';
- import type { File, PaginatedResponse } from '../types.js';
- /**
- * Format file data for markdown output
- */
- function formatFileMarkdown(file: File): string {
- const lines = [
- `## File: ${file.fileName} (ID: ${file.id})`,
- '',
- `**File Name**: ${file.fileName}`,
- `**File Size**: ${(file.fileSize / 1024).toFixed(2)} KB`,
- `**MIME Type**: ${file.mimeType}`,
- `**File Path**: ${file.filePath}`,
- file.uploadUser ? `**Uploaded By**: ${file.uploadUser.username} (ID: ${file.uploadUserId})` : `**Uploaded By ID**: ${file.uploadUserId}`,
- `**Created At**: ${new Date(file.createdAt).toLocaleString('zh-CN')}`,
- ''
- ];
- return lines.join('\n');
- }
- /**
- * Format file list for markdown output
- */
- function formatFileListMarkdown(files: File[], total: number, current: number, pageSize: number): string {
- const lines = [
- `# File List`,
- '',
- `Total: ${total} files | Page: ${current} | Page Size: ${pageSize}`,
- ''
- ];
- for (const file of files) {
- lines.push(formatFileMarkdown(file));
- }
- return lines.join('\n');
- }
- /**
- * List files tool
- */
- export const fileListTool = async (args: FileListInput) => {
- const apiClient = getApiClient();
- try {
- const { page, pageSize, keyword, sortBy, sortOrder, filters, response_format } = args;
- const params: Record<string, unknown> = {
- page: page || 1,
- pageSize: pageSize || 20
- };
- if (keyword) params.keyword = keyword;
- if (sortBy) params.sortBy = sortBy;
- if (sortOrder) params.sortOrder = sortOrder;
- if (filters) params.filters = filters;
- const response = await apiClient.get<PaginatedResponse<File>>('/api/v1/files', params);
- const files = response.data || [];
- const total = response.pagination?.total || 0;
- const structuredOutput = {
- total,
- count: files.length,
- current: page || 1,
- pageSize: pageSize || 20,
- files: files.map((f: File) => ({
- id: f.id,
- fileName: f.fileName,
- fileSize: f.fileSize,
- mimeType: f.mimeType,
- filePath: f.filePath,
- uploadUserId: f.uploadUserId,
- uploadUserName: f.uploadUser?.username,
- createdAt: f.createdAt
- })),
- hasMore: total > (page || 1) * (pageSize || 20)
- };
- let textContent: string;
- if (response_format === ResponseFormat.JSON) {
- textContent = JSON.stringify(structuredOutput, null, 2);
- } else {
- let markdown = formatFileListMarkdown(files, total, page || 1, pageSize || 20);
- // Check character limit
- if (markdown.length > CHARACTER_LIMIT) {
- const halfLength = Math.floor(files.length / 2);
- const truncatedFiles = files.slice(0, halfLength);
- markdown = formatFileListMarkdown(truncatedFiles, total, page || 1, pageSize || 20);
- markdown += `\n---\n⚠️ **Response truncated**: Showing ${halfLength} of ${files.length} results. Use pagination to see more.\n`;
- }
- textContent = markdown;
- }
- return {
- content: [{ type: 'text', text: textContent }],
- structuredContent: structuredOutput
- };
- } catch (error) {
- return {
- content: [{
- type: 'text',
- text: `Error: ${error instanceof Error ? error.message : 'Failed to list files'}`
- }]
- };
- }
- };
- /**
- * Get single file tool
- */
- export const fileGetTool = async (args: FileGetInput) => {
- const apiClient = getApiClient();
- try {
- const { id } = args;
- const response = await apiClient.get<File>(`/api/v1/files/${id}`);
- const file = response;
- const structuredOutput = {
- id: file.id,
- fileName: file.fileName,
- fileSize: file.fileSize,
- mimeType: file.mimeType,
- filePath: file.filePath,
- uploadUserId: file.uploadUserId,
- uploadUserName: file.uploadUser?.username,
- createdAt: file.createdAt,
- updatedAt: file.updatedAt
- };
- const markdown = formatFileMarkdown(file);
- return {
- content: [{ type: 'text', text: markdown }],
- structuredContent: structuredOutput
- };
- } catch (error) {
- return {
- content: [{
- type: 'text',
- text: `Error: ${error instanceof Error ? error.message : 'Failed to get file'}`
- }]
- };
- }
- };
- /**
- * Delete file tool
- */
- export const fileDeleteTool = async (args: FileDeleteInput) => {
- const apiClient = getApiClient();
- try {
- const { id } = args;
- await apiClient.delete<{ success: boolean }>(`/api/v1/files/${id}`);
- const markdown = `✅ **File Deleted Successfully**\n\nFile ID ${id} has been deleted.`;
- const structuredOutput = {
- success: true,
- deletedFileId: id
- };
- return {
- content: [{ type: 'text', text: markdown }],
- structuredContent: structuredOutput
- };
- } catch (error) {
- return {
- content: [{
- type: 'text',
- text: `Error: ${error instanceof Error ? error.message : 'Failed to delete file'}`
- }]
- };
- }
- };
- // Export tool registration configs
- export const fileTools = {
- fileList: {
- name: 'admin_list_files',
- schema: FileListInputSchema,
- handler: fileListTool
- },
- fileGet: {
- name: 'admin_get_file',
- schema: FileGetInputSchema,
- handler: fileGetTool
- },
- fileDelete: {
- name: 'admin_delete_file',
- schema: FileDeleteInputSchema,
- handler: fileDeleteTool
- }
- };
|