file.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. package storage
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/mark3labs/mcp-go/mcp"
  6. "github.com/mark3labs/mcp-go/server"
  7. "fwh-toolbox-server/cmd/mcp/tools/helper"
  8. "fwh-toolbox-server/utils/filestore"
  9. )
  10. // mcpFileStore MCP 专用的文件存储实例
  11. var mcpFileStore *filestore.FileStore
  12. // InitFileStore 初始化 MCP FileStore(由 main.go 调用)
  13. func InitFileStore(fs *filestore.FileStore) {
  14. mcpFileStore = fs
  15. }
  16. // GetFileStore 获取 MCP FileStore 实例
  17. func GetFileStore() *filestore.FileStore {
  18. return mcpFileStore
  19. }
  20. func registerFileTools(s *server.MCPServer) {
  21. s.AddTool(
  22. mcp.NewTool("storage_file_read",
  23. mcp.WithDescription("读取用户上传的文件内容。用户通过前端上传的文件存储在 /uploads/ 路径下。"),
  24. mcp.WithString("path", mcp.Required(), mcp.Description("文件路径,格式为 /uploads/{filename}")),
  25. ),
  26. handleFileRead,
  27. )
  28. s.AddTool(
  29. mcp.NewTool("storage_file_write",
  30. mcp.WithDescription("将文本内容写入文件存储(MinIO)。可用于保存分析结果、生成报告等。文件路径会自动添加 /uploads/ 前缀。"),
  31. mcp.WithString("path", mcp.Required(), mcp.Description("文件路径,格式为 /uploads/{filename}(如 /uploads/report.csv)")),
  32. mcp.WithString("content", mcp.Required(), mcp.Description("要写入的文本内容")),
  33. ),
  34. handleFileWrite,
  35. )
  36. s.AddTool(
  37. mcp.NewTool("storage_file_list",
  38. mcp.WithDescription("列出当前会话中用户上传的所有文件,返回文件名、路径、大小等信息。"),
  39. ),
  40. handleFileList,
  41. )
  42. }
  43. func handleFileRead(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
  44. path, err := req.RequireString("path")
  45. if err != nil {
  46. return helper.ParamError("path"), nil
  47. }
  48. if mcpFileStore == nil {
  49. return helper.ServiceError("文件存储", fmt.Errorf("未初始化")), nil
  50. }
  51. if !mcpFileStore.HasFile(path) {
  52. return helper.EmptyResult(fmt.Sprintf("文件不存在: %s", path)), nil
  53. }
  54. content, err := mcpFileStore.ReadFile(path)
  55. if err != nil {
  56. return helper.ServiceError("读取文件", err), nil
  57. }
  58. return helper.TextResult(content), nil
  59. }
  60. func handleFileList(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
  61. if mcpFileStore == nil {
  62. return helper.ServiceError("文件存储", fmt.Errorf("未初始化")), nil
  63. }
  64. files := mcpFileStore.GetFiles()
  65. if len(files) == 0 {
  66. return helper.EmptyResult("当前没有上传的文件"), nil
  67. }
  68. return helper.JSONResult(files), nil
  69. }
  70. func handleFileWrite(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
  71. path, err := req.RequireString("path")
  72. if err != nil {
  73. return helper.ParamError("path"), nil
  74. }
  75. content, err := req.RequireString("content")
  76. if err != nil {
  77. return helper.ParamError("content"), nil
  78. }
  79. if mcpFileStore == nil {
  80. return helper.ServiceError("文件存储", fmt.Errorf("未初始化")), nil
  81. }
  82. // 写入文件(userId 和 sessionId 使用固定值,MCP 模式下无用户上下文)
  83. record, err := mcpFileStore.WriteFile("mcp-agent", "mcp-session", path, content)
  84. if err != nil {
  85. return helper.ServiceError("写入文件", err), nil
  86. }
  87. return helper.JSONResult(map[string]any{
  88. "message": "文件写入成功",
  89. "path": record.Path,
  90. "fileName": record.FileName,
  91. "size": record.Size,
  92. "key": record.Key,
  93. }), nil
  94. }