FileSync MCP 接入指南

FileSync 实现了完整的 Model Context Protocol (MCP) 服务器, 让 AI Agent 可以安全地管理你的文件:浏览目录、读写文件、上传下载、回收站、创建分享链接。

本文档基于 实战踩坑经验 编写,覆盖从零搭建到高级用法的全部细节。 如果你首次使用,请从头到尾阅读;有经验的可以跳转到 工具参考常见陷阱

核心原则:先调 whoami
任何 Agent 收到 MCP 任务后,第一个动作必须是调用 whoami。 它会返回当前令牌的 scope、空间沙箱、路径沙箱、配额上限——这些决定了你能做什么、不能做什么。 跳过这一步是大多数权限错误的根源。

快速开始

方式一:Web 控制台(推荐)

  1. 登录 FileSync → 左侧栏「访问令牌」→ 点击「新建令牌」
  2. 填写令牌名称,勾选所需 scope:
    • read 文件浏览、读取、下载、回收站查看
    • write 文件创建、上传、改名、移动、删除、恢复
    • share 创建、查看、删除分享链接
  3. (可选)限定空间和目录前缀作为安全沙箱
  4. 点击创建,立即复制令牌(只显示一次!)
  5. 将令牌配置到 MCP 客户端中(见下方 客户端配置
令牌只显示一次! 创建后请立即保存。如果丢失,只能删除重建。

方式二:API 编程创建令牌

如果你想自动化创建令牌(例如 CI/CD 或批量部署),可以通过 REST API:

# 第 1 步:获取 RSA 公钥
curl -s https://你的域名/api/pubkey

# 第 2 步:用公钥加密密码后登录(PKCS1v15 填充!)
# Python 示例:
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding

# ⚠️ 关键:使用 PKCS1v15,不是 OAEP!
public_key.encrypt(password.encode(), padding.PKCS1v15())

# 第 3 步:POST /api/login,获取 session cookie (fs_access_token)
resp = session.post("/api/login", json={
    "username": "admin",
    "password": encrypted_password_base64
})

# 第 4 步:用 session cookie 创建 PAT
# ⚠️ 关键:scopes 必须是数组,不是空格分隔的字符串!
resp = session.post("/api/tokens", json={
    "name": "MyToken",
    "scopes": ["filesync:read", "filesync:write"]  # ← 数组,不是字符串!
})
API 创建令牌的两个常见错误:
① RSA 加密使用 PKCS1v15 填充,不要用 OAEP!
scopes 字段是字符串数组 ["filesync:read"],不是空格分隔字符串!

客户端配置

Claude Desktop

编辑 Claude Desktop 的 MCP 配置文件(%APPDATA%/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "filesync": {
      "type": "streamableHttp",
      "url": "https://你的域名/mcp",
      "headers": {
        "Authorization": "Bearer fsk_你的令牌"
      }
    }
  }
}

Cursor

在 Cursor Settings → MCP → Add new MCP server:

Name: filesync
Type: Streamable HTTP
URL: https://你的域名/mcp
Header: Authorization: Bearer fsk_你的令牌

curl / Python / 其他脚本

直接发 JSON-RPC 请求到 POST /mcp

curl -s -X POST https://你的域名/mcp \
  -H "Authorization: Bearer fsk_你的令牌" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "whoami",
      "arguments": {}
    },
    "id": 1
  }'
# Python 通用调用模板
import requests, json, time

BASE = "https://你的域名"
HEADERS = {
    "Authorization": "Bearer fsk_你的令牌",
    "Content-Type": "application/json"
}

def mcp_call(tool_name, arguments):
    """调用 MCP 工具,返回完整 JSON 响应"""
    payload = {
        "jsonrpc": "2.0",
        "method": "tools/call",
        "params": {"name": tool_name, "arguments": arguments},
        "id": int(time.time() * 1000)
    }
    r = requests.post(f"{BASE}/mcp", json=payload, headers=HEADERS)
    return r.json()

def get_result(response):
    """提取 structuredContent"""
    return response.get("result", {}).get("structuredContent", {})

# 示例
result = get_result(mcp_call("whoami", {}))
print(result["identity"]["username"])  # → "admin"

工具完整参考

whoami 无 scope 要求

Agent 必须首先调用,了解当前令牌的能力边界。

参数类型必填说明
无参数
# 请求
mcp_call("whoami", {})

# 响应 structuredContent
{
  "identity": {
    "username": "admin",
    "role": "admin",
    "scopes": ["filesync:read", "filesync:write", "filesync:share"],
    "token_id": "fsk_xxx",
    "space_sandbox": "",           // 空=不限制
    "path_sandbox": "",            // 空=不限制
    "quota_bytes": 1073741824,     // 配额上限(字节)
    "quota_used": 12345            // 已用配额
  }
}

fs_list filesync:read

列出目录内容。返回子目录列表和文件列表。

参数类型必填说明
pathstring目录路径,空字符串 = 根目录。例: "docs/"
space_idstring空间 ID。普通用户传空字符串使用默认空间,admin 传空=所有空间
recursivebool是否递归列出。默认 false
# 列出根目录
mcp_call("fs_list", {"path": "", "space_id": ""})

# 响应
{
  "dirs":  [{"name": "docs",       "updated": "2026-08-09T12:00:00Z"}],
  "files": [{"name": "notes/todo.txt", "size": 1234, "updated": "...",
              "id": "file_abc123", "hash": "sha256:...", "type": "text"}]
}
注意: 文件列表中的 name完整路径(如 docs/readme.md),不是仅文件名。 id 用于后续操作(如 share_create 需要 file_id)。

fs_stat filesync:read

获取单个文件的元信息(大小、哈希、归属空间)。

参数类型必填说明
file_idstring二选一文件 ID
pathstring二选一文件路径(与 file_id 二选一,推荐用 path)
fs_stat 不需要 space_id。 与 fs_list 不同,fs_stat 直接用 path 查询即可。
mcp_call("fs_stat", {"path": "notes/todo.txt"})

fs_read filesync:read

读取文件内容。文本直接返回,二进制返回 base64(≤1MB 内联)。

参数类型必填说明
pathstring文件路径。不需要 space_id
max_sizeint64最大读取字节,默认 1MB
# 文本文件
mcp_call("fs_read", {"path": "notes/todo.txt"})
# → {"filename": "notes/todo.txt", "content": "...", "size": 200}

# 大文件建议用 fs_download
mcp_call("fs_download", {"path": "video.mp4"})
# → {"filename": "video.mp4", "size": 50000000, "download_url": "...", "expires_in": 1800}

fs_download filesync:read

生成 30 分钟有效的临时下载链接,适合大文件。

参数类型必填说明
pathstring文件路径。不需要 space_id

fs_write filesync:write

创建或覆盖文本文件。

参数类型必填说明
pathstring目标文件路径
contentstring文本内容
space_idstring空间 ID(普通用户传空=默认空间)
overwritebool是否覆盖已存在文件,默认 false(冲突报错)
fs_write 需要 space_id! 这与 fs_read/fs_stat 不同。普通用户传 "",admin 传 "" 会分配到 default-admin 空间。
mcp_call("fs_write", {
    "path": "projects/new-readme.md",
    "content": "# New Project\n\nHello!",
    "space_id": ""
})

fs_upload filesync:write

上传二进制文件。两种方式:Base64 内联或服务端拉取 URL。

参数类型必填说明
pathstring目标路径
content_base64string二选一文件内容 Base64(≤50MB)
source_urlstring二选一源文件 URL,服务端拉取(≤200MB)
space_idstring空间 ID

fs_mkdir filesync:write

创建目录。幂等操作——目录已存在也返回成功。

参数类型必填说明
pathstring目录路径,如 "docs/notes/"
space_idstring空间 ID

fs_rename filesync:write

重命名文件。仅限同目录内改名,跨目录移动请用 fs_move

参数类型必填说明
pathstring原文件路径。不需要 space_id
new_pathstring新文件路径(同目录)
file_idstring文件 ID(与 path 二选一)
fs_rename 不需要 space_id。 只需要 path + new_path。

fs_move filesync:write

批量移动文件(改路径前缀)。把 old_prefix 下所有文件移到 new_prefix

参数类型必填说明
old_prefixstring源目录前缀
new_prefixstring目标目录前缀
space_idstring空间 ID

fs_delete filesync:write

软删除文件(进回收站,30 天保留)。支持按路径或 file_id 批量删除。

参数类型必填说明
pathsstring[]二选一要删除的文件路径列表。不需要 space_id
file_idsstring[]二选一要删除的文件 ID 列表
fs_delete 不需要 space_id,paths 是数组。
路径数组如 ["dir/file1.txt", "dir/subdir"],删除目录会递归删除目录下所有文件。

回收站系列

fs_trash_list filesync:read

参数类型必填说明
space_idstring空间过滤(可选)

fs_trash_restore filesync:write

参数类型必填说明
file_idstring从 fs_trash_list 中获取的 file_id
恢复需要 file_id,不是 path。 先调 fs_trash_list 找到目标文件的 id,再用 fs_trash_restore 恢复。

分享系列

share_create filesync:share

参数类型必填说明
file_idstring条件分享文件时需要。从 fs_list 获取
dir_prefixstring条件分享目录时需要。如 "docs/"
share_typestring"file""dir"
passwordstring访问密码,1-64 字符
expires_inint64有效期秒,0=永久
space_idstring目录分享时指定空间
分享文件需要 file_id,不是 path!
先通过 fs_list 获取文件列表,从返回的 files[].id 中拿到 file_id。
# 第 1 步:获取 file_id
result = get_result(mcp_call("fs_list", {"path": "docs", "space_id": ""}))
file_id = [f["id"] for f in result["files"] if f["name"].endswith("readme.md")][0]

# 第 2 步:创建分享
mcp_call("share_create", {
    "file_id": file_id,
    "share_type": "file",
    "password": "1234",
    "expires_in": 86400    # 24小时
})

share_list filesync:share

列出当前令牌创建的所有分享。无参数。

share_delete filesync:share

参数类型必填说明
share_idstring分享 ID,从 share_list 获取
# 删除分享
result = get_result(mcp_call("share_list", {}))
share_id = result["shares"][0]["id"]
mcp_call("share_delete", {"share_id": share_id})

⚠️ 常见陷阱(实战总结)

陷阱 1:space_id 何时需要?

工具需要 space_id?说明
fs_list✅ 是普通用户传 ""
fs_write✅ 是普通用户传 ""
fs_mkdir✅ 是普通用户传 ""
fs_upload✅ 是普通用户传 ""
fs_move✅ 是普通用户传 ""
fs_stat❌ 否只需 path 或 file_id
fs_read❌ 否只需 path
fs_download❌ 否只需 path
fs_rename❌ 否只需 path + new_path
fs_delete❌ 否只需 paths 数组
fs_trash_list可选可传空
share_create可选目录分享时需要
记住规则: 浏览类(stat/read/download)不需要 space_id;写入类(write/mkdir/upload/move)需要 space_id;list 需要 space_id;delete/rename 不需要 space_id。

陷阱 2:file_id vs path——用哪个?

有些操作接受 file_id,有些需要 path,有些两者都接受。搞错会导致调用失败。

操作推荐用原因
fs_statpath直观,不需要先查 id
fs_readpath唯一选择
fs_downloadpath唯一选择
fs_renamepath最常用
fs_deletepaths[]直接删目录
share_createfile_id文件分享必须用 file_id!
fs_trash_restorefile_id必须用 file_id!
最常见的错误:share_create 传 path 而不是 file_id。
正确的做法:先 fs_list → 取 files[].id → 传给 share_createfile_id 字段。

陷阱 3:MCP 响应格式

MCP JSON-RPC 响应的工具结果在 result.structuredContent 中,不是 result.content

// ✅ 正确
response["result"]["structuredContent"]  // → {"dirs": [...], "files": [...]}

// ❌ 错误
response["result"]["content"]  // 可能是 null

// 完整 JSON-RPC 响应结构
{
  "jsonrpc": "2.0",
  "id": 1733280000000,
  "result": {
    "structuredContent": { /* 工具的实际输出 */ }
    // "content": null  // ← 忽略这个
  }
}

// 错误响应
{
  "jsonrpc": "2.0",
  "id": 1733280000000,
  "result": {
    "isError": true,
    "content": [{"type": "text", "text": "错误描述"}]
  }
}

陷阱 4:登录时 JWT 在 Cookie 中,不在响应体

Web 登录 POST /api/login 成功后,JWT 通过 HttpOnly Cookie (fs_access_token) 设置, 响应体中没有 token 字段

// 登录响应体
{
  "success": true,
  "user_id": 1,
  "username": "admin",
  "role": "admin",
  "expires_in": 86400,
  "token_type": "Bearer"
  // ⚠️ 注意:没有 "token" 字段!
}

// 实际的 token 在 Set-Cookie 响应头中(HttpOnly,JS 不可读)
// Set-Cookie: fs_access_token=eyJhbGc...; HttpOnly; Secure; SameSite=Lax
编程访问时: 使用 requests.Session() 自动管理 Cookie,然后直接用 session 发后续请求。 脚本示例见 API 编程创建令牌

陷阱 5:路径格式

陷阱 6:权限不足

常见错误信息及原因:

错误原因解决
"insufficient_scope"令牌缺少所需 scope重新创建令牌,勾选所需 scope
"space_id outside token sandbox"space_id 超出令牌锁定的空间传令牌允许的空间,或传空字符串
"path outside sandbox"路径不在令牌允许的目录前缀内使用令牌允许的路径前缀
"quota exceeded"超出令牌配额上限删除旧文件或提高配额

附录

REST API 端点

端点方法认证说明
/api/pubkeyGET获取 RSA 公钥(用于加密登录密码)
/api/loginPOSTPKCS1v15 加密密码登录获取 session cookie
/api/tokensPOSTCookie创建 PAT(scopes 必须是数组)
/api/tokensGETCookie列出已创建的 PAT
/api/tokens/{id}DELETECookie删除 PAT
/mcpPOSTBearer PATMCP JSON-RPC 端点

机器可读资源

URL格式用途
/mcp/manifest.jsonJSON工具列表、参数定义、scope 映射。由源码自动生成,始终与实现一致
/mcp/llms.txtPlain textAgent 速查文本。MCP 客户端可自动拉取了解服务器能力
/.well-known/oauth-authorization-serverJSONOAuth 2.0 授权服务器元数据
/.well-known/jwks.jsonJSONJWT 签名公钥(JWKS)

变更记录

日期变更
2026-08-09全面重写:增加完整 curl/Python 示例、16 个工具详细参考、6 大常见陷阱、space_id 对照表、file_id vs path 指南、REST API 端点、MCP 响应格式说明
2026-07-xx初始版本:工具速查表、基本配置方法

FileSync MCP Server · 由 manifest.json 自动生成 · 最后更新 2026-08-09