# MCP-MinIO **Repository Path**: framework-learning-notes/MCP-MinIO ## Basic Information - **Project Name**: MCP-MinIO - **Description**: No description available - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-15 - **Last Updated**: 2026-09-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # MCP-MinIO > **简体中文** | [English](README.en.md) ![JDK](https://img.shields.io/badge/JDK-1.8%2B-blue) ![Maven](https://img.shields.io/badge/Maven-3.3%2B-orange) ![MCP](https://img.shields.io/badge/MCP-JSON--RPC%202.0-green) ![Tools](https://img.shields.io/badge/Tools-16-brightgreen) ![License](https://img.shields.io/badge/License-Apache%202.0-red) MinIO / S3 对象存储的 MCP Server。基于 **stdio + JSON-RPC 2.0**,把桶与对象的数据面操作封装为 **16 个** AI 可直接调用的工具,并为每一次调用施加「只读总闸 + 三层白名单 + 大小硬上限」的前置约束。 ## 目录 - [1. 项目简介](#1-项目简介) - [2. 架构设计](#2-架构设计) - [3. 功能模块](#3-功能模块) - [4. 快速开始](#4-快速开始) - [5. 配置说明](#5-配置说明) - [6. 安全设计](#6-安全设计) - [7. 明确不做的事](#7-明确不做的事) - [8. 异常提示规范](#8-异常提示规范) - [9. 自测验收清单](#9-自测验收清单) - [10. FAQ](#10-faq) - [参与贡献](#参与贡献) - [License](#license) ## 1. 项目简介 MCP-MinIO 是一个面向 AI 客户端的对象存储数据面网关:AI 通过自然语言描述意图,客户端把意图转成工具调用,本服务完成参数校验、白名单拦截与 SDK 执行,并返回结构化结果或可自愈的中文错误。 设计目标只有两个: - **让 AI 用得动** —— 入参出参均为结构化 JSON,错误信息附带下一步工具建议,AI 无需人工介入即可纠偏重试; - **让运维放得心** —— 只读总闸、白名单、大小上限、高危确认四道前置约束,越界请求在触达存储前就被拒绝。 ## 2. 架构设计 ### 2.1 请求链路 ``` AI 客户端(CodeBuddy / Claude Desktop) │ stdio / JSON-RPC 2.0 ▼ McpProtocol ──▶ ToolRegistry(工具路由) │ ▼ PathGuard(三层白名单 + 大小校验,前置拦截) │ ▼ MinioRunner(统一执行模板 + 异常翻译) │ ▼ MinioClientManager(单例客户端 + 超时管控 + 优雅关闭) │ ▼ MinIO 集群(S3 协议) ``` ### 2.2 分层设计 | 层 | 组件 | 职责 | | --- | --- | --- | | L7 工具层 | MetaTools / ReadTools / WriteTools / ManageTools | 16 个工具按场景分 4 组;只读模式跳过写与管理工具 | | L6 协议层 | McpProtocol + ToolRegistry + JsonRpcException | JSON-RPC 2.0 解析、工具注册与分发 | | L5 执行层 | MinioRunner | 统一执行模板 + SDK 异常翻译,报错均为中文 + 下一步建议 | | L4 序列化层 | ResultSerializer | 长文本截断、二进制检测、formatSize、ISO8601 时间格式化 | | L3 连接层 | MinioClientManager + Work | MinioClient 线程安全且自带 OkHttp 连接池,全局单例 + close 释放 | | L2 安全层 | PathGuard | Bucket 白名单、Key 前缀白名单、本地路径白名单 + 穿越防护、大小校验 | | L1 配置层 | MinioProperties / YamlConfigLoader | 环境变量 + YAML(jar 内置 / 外部文件)三级取值,启动时一次性载入为不可变对象 | ## 3. 功能模块 共 16 个工具,按元数据、读取、写入、管理四组划分。只读模式(`MINIO_READ_ONLY=true`)下仅注册前 7 个只读工具;`minio_put_file` 仅在配置 `MINIO_LOCAL_UPLOAD_DIR` 后注册。 图例:`*` 表示必填参数。 ### 3.1 元数据模块(4 个,只读) | 工具 | 功能 | 关键参数 | 安全约束 | | --- | --- | --- | --- | | `minio_health` | 连通性体检,返回 endpoint 与延迟 | 无 | — | | `minio_list_buckets` | 列出桶名与创建时间 | 无 | 结果按白名单过滤 | | `minio_list_objects` | 分页列出对象清单,支持前缀过滤与目录折叠 | `bucket`*、`prefix`、`delimiter`、`max_keys`、`continuation_token` | `max_keys` 上限 1000,强制分页 | | `minio_describe_object` | 查看对象大小、ETag、类型、修改时间与二进制判断 | `bucket`*、`key`* | 双层白名单 | ### 3.2 读取模块(3 个,只读) | 工具 | 功能 | 关键参数 | 安全约束 | | --- | --- | --- | --- | | `minio_read_text` | 读取小文本内容,先查类型,二进制拒绝 | `bucket`*、`key`* | 单次上限 64KB,超限引导预签名 | | `minio_read_range` | 按字节段范围读取,适合大文件头部探测 | `bucket`*、`key`*、`offset`*、`length`*、`hex_preview` | 单段上限 1MB | | `minio_get_presigned_url` | 生成临时下载 / 上传链接 | `bucket`*、`key`*、`expiry_seconds`、`method` | 默认 900 秒、上限 1 天;PUT 需显式开启 | ### 3.3 写入模块(4 个,只读模式不注册) | 工具 | 功能 | 关键参数 | 安全约束 | | --- | --- | --- | --- | | `minio_put_text` | 写入文本内容 | `bucket`*、`key`*、`content`*、`content_type`、`overwrite` | 上限 1MB;默认拒绝覆盖已有对象 | | `minio_put_file` | 从本地路径上传文件 | `bucket`*、`key`*、`local_path`*、`content_type` | 路径须在白名单目录内 + 穿越 / 软链防护;上限 100MB | | `minio_copy_object` | 服务端复制对象 | `src_bucket`*、`src_key`*、`dst_bucket`*、`dst_key`* | 源与目标双过白名单 | | `minio_rename_object` | 重命名对象 | `bucket`*、`key`*、`new_key`* | copy + delete 原子封装;`new_key` 过前缀白名单 | ### 3.4 管理模块(5 个,只读模式不注册) | 工具 | 功能 | 关键参数 | 安全约束 | | --- | --- | --- | --- | | `minio_create_bucket` | 创建桶 | `bucket`* | S3 命名规范正则前置校验 + 白名单 | | `minio_delete_object` | 删除单个对象 | `bucket`*、`key`* | 双层白名单;出参区分「对象本就不存在」 | | `minio_delete_by_prefix` | 按前缀批量删除 | `bucket`*、`prefix`*、`limit` | 上限 100 条;空前缀拒绝;返回可审计删除清单 | | `minio_remove_objects` | 按明确 key 列表批量删除 | `bucket`*、`keys`* | 上限 100 条,逐个过白名单 | | `minio_delete_bucket` | 删除桶 | `bucket`*、`confirm`* | `confirm=true` 必传 + SDK 非空校验双保险 | ## 4. 快速开始 ### 4.1 环境要求 | 项 | 要求 | | --- | --- | | 运行环境 | JDK 8 及以上 | | 构建环境 | Maven 3.3.x | | 存储服务 | MinIO 集群(或任意 S3 兼容存储) | ### 4.2 构建打包 ```bash git clone <你的仓库地址> cd MCP-MinIO mvn clean package -DskipTests ``` 产物:`target/MCP-MinIO-1.0.0.jar`(shade 插件打出的 fat jar,可直接 `java -jar` 运行)。 ### 4.3 冒烟运行 ```bash # Linux / macOS MINIO_ENDPOINT=http://127.0.0.1:9000 \ MINIO_ACCESS_KEY=minioadmin \ MINIO_SECRET_KEY=minioadmin \ java -jar target/MCP-MinIO-1.0.0.jar ``` ```powershell # Windows PowerShell $env:MINIO_ENDPOINT = "http://127.0.0.1:9000" $env:MINIO_ACCESS_KEY = "minioadmin" $env:MINIO_SECRET_KEY = "minioadmin" java -jar target/MCP-MinIO-1.0.0.jar ``` 进程挂住等待 stdin 输入即为正常;`Ctrl+C` 触发 ShutdownHook 优雅退出。 ### 4.4 接入 MCP 客户端 在 MCP 配置文件(CodeBuddy 为 `.codebuddy/mcp.json`)中添加: ```json { "mcpServers": { "MCP-MinIO": { "command": "java", "args": ["-jar", "D:/mcp/MCP-MinIO/target/MCP-MinIO-1.0.0.jar"], "env": { "MINIO_ENDPOINT": "http://192.168.10.101:9000", "MINIO_ACCESS_KEY": "你的AccessKey", "MINIO_SECRET_KEY": "你的SecretKey", "MINIO_READ_ONLY": "false", "MINIO_ALLOWED_BUCKETS": "app-data,user-uploads", "MINIO_KEY_PREFIX": "", "MINIO_LOCAL_UPLOAD_DIR": "D:/mcp/uploads", "MINIO_PUBLIC_ENDPOINT": "", "LOG_LEVEL": "INFO" } } } } ``` 接入要点: - jar 路径请使用绝对路径; - 内网部署且需要生成外网可访问链接时,必须配置 `MINIO_PUBLIC_ENDPOINT`; - `MINIO_LOCAL_UPLOAD_DIR` 配置后才启用 `minio_put_file` 工具; - 接入生产存储时建议 `MINIO_READ_ONLY=true`,并将白名单收敛到最小集合。 ### 4.5 对话示例 ``` 你:「MinIO 连得上吗?」 AI:调用 minio_health → 「连接正常,延迟 12ms」 你:「app-data 里有什么?」 AI:调用 minio_list_objects → 「共 128 个对象,前 50 个是……, 还有更多,可用 continuation_token 翻页」 你:「看看 config.json 写的啥」 AI:调用 minio_read_text → 「内容是……」 (若为图片 → 「这是二进制文件,我给你生成下载链接」) 你:「给 report.pdf 一个下载链接」 AI:调用 minio_get_presigned_url → 「15 分钟内有效:https://……」 你:「把 D:/mcp/uploads/a.zip 传上去」 AI:调用 minio_put_file → 「上传成功,大小 24.5MB」 你:「删掉整个 data 桶」 AI:调用 minio_delete_bucket → 「需要 confirm=true 才能删除, 此操作不可恢复,确定吗?」 ``` ## 5. 配置说明 共 22 项。**配置来源与优先级**(同名项逐项覆盖,不是整份替换): | 优先级 | 来源 | 写法 | | --- | --- | --- | | 1(最高) | 环境变量 | MCP 客户端 `env` 中写 `MINIO_ENDPOINT` 等 | | 2 | 外部 YAML | `--config=路径`、`-Dmcp.minio.config=路径`、`MINIO_CONFIG_FILE` 环境变量;或工作目录下的 `application.yml` / `minio.yml`(含 `config/` 子目录,自动发现) | | 3 | jar 内置 YAML | `src/main/resources/application.yml`,出厂默认值 | 三条约定:环境变量留空(`""`)视为「未配置」,继续向下回退;数值 / 布尔解析失败时记一条 `WARN` 并回退默认值;越界值被钳制在合法区间内,保证进程始终可启动。而 `--config` 指定的文件不存在、或 YAML 语法错误,则启动即失败,不静默降级。 **配置项 key 的写法很宽松**,下列四种完全等价(比对时忽略大小写与 `-` `_` `.` 差异): ```yaml minio: max-read-bytes: 2048 # 首选 kebab-case ``` ```yaml max-read-bytes: 2048 # 省掉 minio: 这一层,效果相同 ``` ```yaml MAX_READ_BYTES: 2048 # ENV 风格 ``` ```yaml maxReadBytes: 2048 # camelCase ``` 顶层 `log:` 是独立命名空间,`log.level` 等价于 `LOG_LEVEL`。列表既可写成 `[a, b]`,也可写成 `"a,b"`。 ### 5.1 连接类 | 变量 | 默认值 | 说明 | | --- | --- | --- | | `MINIO_ENDPOINT` | `http://127.0.0.1:9000` | 服务地址,含协议前缀 | | `MINIO_ACCESS_KEY` | 空 | 访问凭证;为空则匿名连接(受保护资源返回 AccessDenied) | | `MINIO_SECRET_KEY` | 空 | 访问凭证;与 AccessKey 必须成对配置 | | `MINIO_REGION` | 空 | 可选,SDK 自动推断 | | `MINIO_PUBLIC_ENDPOINT` | 空 | 预签名 URL 对外 host,内网部署需配置 | | `MINIO_CONNECT_TIMEOUT_MS` | `3000` | 连接超时(100 ~ 60000) | ### 5.2 安全类 | 变量 | 默认值 | 说明 | | --- | --- | --- | | `MINIO_READ_ONLY` | `false` | 只读总闸,`true` 时仅注册 7 个只读工具 | | `MINIO_ALLOWED_BUCKETS` | 空 | Bucket 白名单,逗号 / 空格分隔,空为不限制 | | `MINIO_KEY_PREFIX` | 空 | 对象 Key 前缀白名单,空为不限制 | | `MINIO_LOCAL_UPLOAD_DIR` | 空 | 本地上传目录白名单;为空则不注册 `minio_put_file` | | `MINIO_ALLOW_PRESIGN_PUT` | `false` | 是否允许生成上传型(PUT)预签名 URL | ### 5.3 读写上限类 | 变量 | 默认值 | 说明 | | --- | --- | --- | | `MINIO_MAX_READ_BYTES` | `65536` | `read_text` 单次上限(64KB),最大 10MB | | `MINIO_MAX_RANGE_BYTES` | `1048576` | `read_range` 单段上限(1MB),最大 10MB | | `MINIO_MAX_WRITE_BYTES` | `1048576` | `put_text` 上限(1MB),最大 100MB | | `MINIO_MAX_UPLOAD_BYTES` | `104857600` | `put_file` 上限(100MB),最大 10GB | | `MINIO_MAX_LIST_KEYS` | `1000` | `list_objects` 单页上限(S3 硬上限,最大 1000) | | `MINIO_MAX_DELETE_KEYS` | `100` | 批量删除单次上限,最大 1000 | ### 5.4 超时与其他 | 变量 | 默认值 | 说明 | | --- | --- | --- | | `MINIO_READ_TIMEOUT_MS` | `10000` | 读超时(100 ~ 300000) | | `MINIO_WRITE_TIMEOUT_MS` | `10000` | 写超时(100 ~ 300000) | | `MINIO_PRESIGN_DEFAULT_SECONDS` | `900` | 预签名默认有效期(15 分钟) | | `MINIO_PRESIGN_MAX_SECONDS` | `86400` | 预签名有效期上限(1 天,最大 604800) | | `LOG_LEVEL` | `INFO` | 日志级别 `ERROR` / `WARN` / `INFO`,输出至 stderr | ## 6. 安全设计 共 9 道防线,高危动作一律「先确认、再执行」,越界请求在前置层直接拦截。 | 序号 | 防线 | 实现位置 | | --- | --- | --- | | 1 | 只读总闸:写 / 管理工具不注册,AI 侧不可见 | `Main` | | 2 | Bucket 白名单 | `PathGuard.checkBucket` | | 3 | Key 前缀白名单 | `PathGuard.checkKey` | | 4 | 本地路径白名单 + 穿越防护 + 软链逃逸防护(canonical path 前缀比对) | `PathGuard.checkLocalPath` | | 5 | 大小硬上限:读 64KB / 范围 1MB / 写 1MB / 传 100MB / 批删 100 / 单页 1000 | `PathGuard.checkSize` | | 6 | 危险操作 confirm 机制(`delete_bucket`) | `ManageTools` | | 7 | 预签名管控:有效期上限 + 默认仅 GET + PUT 显式开启 | `ReadTools` | | 8 | 超时硬约束:connect / read / write 三路独立 | `MinioClientManager` | | 9 | AI 友好异常翻译:每条错误附下一步工具建议 | `MinioRunner` | ## 7. 明确不做的事 以下能力经设计评审后刻意不封装,均属控制面高危运维,请使用 `mc` 命令行完成。 | 不做的功能 | 理由 | | --- | --- | | 通用执行器 | SDK 强类型方法无安全白名单空间,开启即后门 | | `setBucketPolicy` / Versioning / Lifecycle | 策略误配影响面覆盖整桶 | | 生命周期规则(expire) | 规则作用在前缀级,AI 配错会批量误删命中对象 | | base64 读取小图 | 1MB 文件转码后 1.33MB 塞入上下文性价比极低,统一走预签名 | | multipart 分片上传 | 分片状态管理复杂,出错难回收 | ## 8. 异常提示规范 所有异常均翻译为「中文原因 + 下一步建议」的结构,AI 可据此自愈重试。 | SDK 异常 | 提示示例 | | --- | --- | | `NoSuchBucket` | 「bucket 不存在:xxx,请先用 minio_list_buckets 确认」 | | `NoSuchKey` | 「对象不存在:xxx,请先用 minio_list_objects 确认路径」 | | `AccessDenied` | 「权限不足:当前 AccessKey 无权操作 xxx,请检查白名单与服务端 IAM 策略」 | | `BucketNotEmpty` | 「bucket 非空无法删除,请先用 minio_delete_by_prefix 清空对象」 | | `InvalidBucketName` | 「桶名不符合 S3 规范(3-63 位小写字母/数字/中划线/点)」 | | `InvalidAccessKeyId` | 「AccessKey 无效:请检查环境变量 MINIO_ACCESS_KEY」 | | `SignatureDoesNotMatch` | 「签名不匹配:MINIO_SECRET_KEY 不正确,请检查」 | | `EntityTooLarge` | 「对象过大:请调大 MINIO_MAX_WRITE_BYTES 或改用 minio_put_file」 | | `IOException(timeout)` | 「操作超时:对象可能过大或网络异常,大文件请改用 minio_get_presigned_url」 | ## 9. 自测验收清单 交付前建议按以下 10 条逐项验证: 1. `java -jar` 启动后挂住不退出,stdout 无协议外输出; 2. `minio_health` 返回延迟正常; 3. `minio_list_objects` 大桶分页正常,`next_token` 可翻页; 4. `minio_read_text` 读二进制被拒绝并引导预签名; 5. `minio_read_range` 读大文件头部正常; 6. `minio_put_file` 白名单外路径被拒绝; 7. `minio_put_text` 默认拒绝覆盖,`overwrite=true` 后成功; 8. `minio_delete_bucket` 无 `confirm` 参数被拒绝; 9. 只读模式下写与管理工具不出现在 `tools/list` 中; 10. `Ctrl+C` / `kill -15` 后进程优雅退出,无连接残留。 如需自动化验证,可运行仓库内的 stdio 协议自测脚本(无需真实 MinIO 服务): ```bash python3 scripts/selftest.py # 需先完成 mvn package;脚本面向 Linux/macOS ``` ## 10. FAQ **Q:能接 AWS S3 / 其他 S3 兼容存储吗?** A:可以。MinIO SDK 兼容 S3 协议,将 `MINIO_ENDPOINT` 指向对应地址即可,但仅在 MinIO 上做过完整验证。 **Q:生成的下载链接外网打不开?** A:配置 `MINIO_PUBLIC_ENDPOINT` 为对外可达的域名地址,SDK 生成的 URL host 会被自动替换。 **Q:为什么读文件有大小限制?** A:读取结果会进入 AI 上下文,超限会挤占对话空间甚至溢出。大文件统一走 `minio_get_presigned_url` 交给人下载。 **Q:上传工具为什么默认不可用?** A:`minio_put_file` 涉及本地文件读取,仅在配置 `MINIO_LOCAL_UPLOAD_DIR` 白名单后才注册,且路径必须落在白名单目录内。 **Q:报错信息是中文的,有英文版吗?** A:工具返回内容当前为中文(面向使用者的自愈式提示),文档本身提供中英双语。 ## 参与贡献 1. Fork 本仓库; 2. 新建 `Feat_xxx` 分支; 3. 提交代码(请保证自测清单全部通过); 4. 新建 Pull Request。 新增工具请先完成设计评审:工具名、入参出参、安全约束、异常翻译,四项齐备后再进入编码。 ## License [Apache License 2.0](LICENSE) > **简体中文** | [English](README.en.md)