关于 Handoff: Send Files to Users & Agents
Handoff 是面向 AI Agent 的托管文件分享 MCP 服务和 REST API,可将文件交给用户或其他 Agent,并通过链接控制访问。链接支持有效期、打开次数、审批、指定 Agent、撤销和访问日志。
主要功能
- 01创建文件分享链接
- 02设置有效期和打开次数
- 03限制指定 Agent 访问
- 04审批后开放文件
- 05撤销链接并查看访问日志
- 06保存、列出和删除文件
适用场景
- 01向用户交付报告或文件
- 02在两个 Agent 间传递文件
- 03审批后再向接收方开放文件
- 04撤销链接并检查访问记录
MCP 相关
远程 MCP 服务通过 Streamable HTTP 暴露文件保存、分享、审批、状态查询、撤销和访问日志等工具。首次调用可免密分享文件并创建账户;后续管理操作使用 API 密钥。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://hand-off.space/mcpclaude mcp add --transport http jueluddinsf-handoff https://hand-off.space/mcp{"mcpServers":{"jueluddinsf-handoff":{"type":"http","url":"https://hand-off.space/mcp"}}}在 Cursor 中打开{"servers":{"jueluddinsf-handoff":{"type":"http","url":"https://hand-off.space/mcp"}}}在 VS Code 中打开{"mcpServers":{"jueluddinsf-handoff":{"type":"http","url":"https://hand-off.space/mcp"}}}{"mcpServers":{"jueluddinsf-handoff":{"serverUrl":"https://hand-off.space/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
https://hand-off.space/mcp需要授权工具
详细介绍
Handoff:面向 AI Agent 的文件共享
通过受控共享链接,将文件从 AI Agent 发送给用户或其他 Agent:可设置过期时间、最大打开次数、人工审批、仅限 Agent 访问,并支持撤销和访问日志。远程 MCP 服务 + REST API,无需人工注册。
Handoff 为 Agent 提供了一种安全的方式,可将文件交给其他人,无论对方是人还是其他 Agent。一次调用(通过 MCP 调用 share_file,或调用 POST /v1/share)即可返回下载链接,无需 API 密钥。 如需更多控制,Agent 可以先私下保存文件,再根据需要创建共享链接并设置规则:过期时间、最大打开次数、可选的人工审批步骤,以及指定的接收 Agent。Agent 可以随时查看状态、撤销链接并读取访问日志。
- 远程 MCP 服务:
https://hand-off.space/mcp(Streamable HTTP) - REST API:
https://hand-off.space/v1(OpenAPI、llms.txt) - 身份验证: 首次调用无需身份验证。无需密钥调用
share_file/POST /v1/share会创建账户,并仅返回一次api_key。后续调用需发送Authorization: Bearer <api_key>(如果客户端无法设置请求头,也可将api_key作为工具参数传入)。你也可以单独通过signup/POST /v1/signup获取密钥。无需邮箱、银行卡或人工账户。 - 14 个 MCP 工具:
share_file、signup、save_file、list_files、create_share_link、get_share_status、approve_share、deny_share、revoke_share、get_access_log、fetch_shared_file、delete_file、list_shares、update_share。initialize和tools/list无需密钥。 - 注册表名称:
io.github.jueluddinsf/handoff
此代码仓库包含文档和目录列表元数据。该服务托管在云端,因此无需安装任何内容。
适用于 Agent 需要……
- 向用户发送报告。 Agent 保存
report.pdf,然后发送一个 24 小时后过期且最多打开 3 次的链接。 - 将文件交给另一个 Agent。 只有指定的接收 Agent 出示自己的密钥后,才能打开链接。
- 等待人工审批后再发布文件。 链接会保持锁定状态(
pending_approval),直到所有者批准。 - 撤回已发送的内容。 撤销链接,并查看所有成功和被拒绝的打开记录。
Agent 常问的问题
- Agent 如何向用户发送文件(PDF、CSV、报告、图片)? 调用带有
name和content_text(或content_base64)的share_file,或调用POST /v1/share,然后将返回的url发给用户。用户可在浏览器中打开链接。下载无需账户。 - 如何获取临时下载链接或设置链接过期时间?
share_file生成的链接默认在 7 天后过期。可在share_file或create_share_link中设置expires_in_hours和max_opens。之后访问链接会返回410 expired或429 limit。 - 如何在两个 Agent 之间传输文件? 将
audience设为"agent",并填写接收方的agent_id。只有该 Agent 的密钥才能通过fetch_shared_file或普通的GET打开文件。 - 文件发布前能否由人工审批? 可以。将
requires_approval: true设为启用。调用approve_share之前,文件无法打开。 - 能否撤销链接或查看是谁打开了链接? 可以。使用
revoke_share和get_access_log。被拒绝的打开请求也会记录在日志中。 - 这是公共文件托管服务或粘贴板吗? 不是。文件默认是私有的,每个链接都是由你控制的明确授权。
指南
- AI Agent 如何向用户发送文件:将 PDF、CSV 或报告作为链接发送
- 面向 AI Agent 的临时下载链接:支持过期、限制打开次数和撤销的链接
- 通过 MCP 在 Agent 之间传输文件:只有指定的 Agent 才能打开链接
- Agent 发布文件前的人工审批:链接会保持锁定,直到你批准
快速开始:一次调用
REST,原始字节。 响应是 URL;如果此次调用创建了账户,则会在第二行返回 api_key: hf_…:
curl -s --data-binary @report.pdf "https://hand-off.space/v1/share?name=report.pdf&format=url"
# https://hand-off.space/g/…
# api_key: hf_…
REST,JSON:
curl -s -X POST https://hand-off.space/v1/share -H 'content-type: application/json' \
-d '{"name":"notes.md","content_text":"# Notes","expires_in_hours":24,"max_opens":3}'
# → {"url":"https://hand-off.space/g/…","expires_at":"…","max_opens":3,"requires_approval":false,
# "file_id":"…","grant_id":"…","token_prefix":"…","next":{…},"api_key":"hf_…"}
MCP。 无需身份验证,连接到 https://hand-off.space/mcp,然后调用:
{"name": "share_file", "arguments": {"name": "notes.md", "content_text": "# Notes"}}
结果包含 url、expires_at(默认 7 天)、grant_id、file_id,以及新账户的一次性 api_key。将 url 提供给接收者,对方可以通过普通的 GET 下载。请保存 api_key:撤销链接、查看状态或读取访问日志时都需要它。后续调用时,请通过 Authorization: Bearer <api_key>(或 api_key 参数)发送它,这样新文件就会保存在同一账户中。
share_file 和 POST /v1/share 还接受 expires_in_hours、max_opens、audience(anyone_with_link 或 agent)、audience_value、requires_approval、mime 和可选的 ref 标签。对于原始字节,请将这些参数作为查询参数传递。
更多控制:REST(3 次调用)
如果你想只存储一次文件,并为其创建多个具有不同规则的链接,请使用此方式。
BASE=https://hand-off.space
# 1. Sign up. The key is shown once, so store it.
curl -s -X POST $BASE/v1/signup -H 'content-type: application/json' -d '{"agent_id":"my-agent"}'
# → {"account_id":"…","api_key":"hf_…","agent_id":"my-agent","caps":{…},"next":…}
export HANDOFF_API_KEY=hf_...
# 2. Save a file privately (content_text, or content_base64 for binary)
curl -s -X POST $BASE/v1/files -H "authorization: Bearer $HANDOFF_API_KEY" -H 'content-type: application/json' \
-d '{"name":"report.md","mime":"text/markdown","content_text":"# Q3 report"}'
# → {"id":"FILE_ID","name":"report.md",…}
# 3. Create a share link
curl -s -X POST $BASE/v1/files/FILE_ID/grants -H "authorization: Bearer $HANDOFF_API_KEY" -H 'content-type: application/json' \
-d '{"audience":"anyone_with_link","expires_in_hours":24,"max_opens":3}'
# → {"grant_id":"…","url":"https://hand-off.space/g/…","token":"…","token_prefix":"…"}
更多控制:MCP(3 次工具调用)
- 将客户端连接到
https://hand-off.space/mcp(配置见下文)。 - 使用
signupMCP 工具获取密钥(无需密钥),或调用POST /v1/signup。将密钥放入客户端的Authorization: Bearer …标头并重新连接,或在每次调用时传递api_key。 - 调用
save_file→create_share_link,然后将返回的url交给接收者。
工具
| 工具 | 功能 |
|---|---|
share_file | 一次调用。 提供 name 加上 content_text 或 content_base64。可选参数:mime、expires_in_hours(默认 168)、max_opens、audience、audience_value、requires_approval、ref。返回 url、expires_at、grant_id、file_id;如果未发送密钥,还会一次性返回 api_key。无需密钥。 |
signup | 创建账户并一次性返回 API 密钥。无需密钥。可选参数:agent_id。 |
save_file | 私密保存文件:name、content_text 或 content_base64,以及可选的 mime。返回文件 ID。不会创建链接。 |
list_files | 按从新到旧的顺序列出你的文件。 |
create_share_link | 提供 file_id、audience(anyone_with_link 或 agent),以及可选的 audience_value(接收者的 agent_id)、expires_in_hours(默认 168,即 7 天)、max_opens、requires_approval。返回 grant_id、url(仅显示一次)、expires_at 和 max_opens。 |
get_share_status | 查看链接的审批、过期、撤销和 open_count 状态,不会消耗可打开次数。 |
approve_share | 批准使用 requires_approval 创建的链接。此操作成功前,链接无法打开。 |
deny_share | 拒绝等待审批的链接。该链接将继续被阻止。 |
revoke_share | 永久撤销链接。文件会保留。 |
get_access_log | 获取链接最近最多 1,000 次打开和拒绝记录。 |
fetch_shared_file | 从 Handoff 分享链接 url 或令牌下载文件(遵循过期时间、打开次数限制、审批状态和 Agent 受众限制)。不超过 1 MB 的文件会以内联的 content_base64 返回(文本文件还会返回 content_text);较大的文件会返回错误,提示你对该 URL 执行 GET。 |
delete_file | 删除你拥有的文件。文件字节会被移除,现有分享链接也会停止工作。 |
list_shares | 列出你拥有的链接,可选按一个 file_id 筛选:grant_id、状态、open_count、max_opens、expires_at、受众。不返回令牌或 URL。 |
update_share | 设置链接的过期时间:grant_id、从现在起计算的 expires_in_hours(例如,168 表示 7 天)。 |
除 share_file、signup 和 fetch_shared_file(针对 anyone_with_link 分享)之外,所有工具都需要你的 API 密钥。未提供密钥时,share_file 会创建一个新账户。
客户端配置
你可以完全不带标头进行连接并调用 share_file,然后保存其返回的 api_key。如需添加密钥,请在下方配置中将 YOUR_HANDOFF_API_KEY 替换为你的密钥,或使用所示的环境变量形式。
Claude Code
claude mcp add --transport http handoff https://hand-off.space/mcp \
--header "Authorization: Bearer YOUR_HANDOFF_API_KEY"
你也可以提交项目级 .mcp.json,本仓库中的文件就是如此。Claude Code 会从环境变量中展开 ${HANDOFF_API_KEY}:
{ "mcpServers": { "handoff": { "type": "http", "url": "https://hand-off.space/mcp",
"headers": { "Authorization": "Bearer ${HANDOFF_API_KEY}" } } } }
Claude Desktop
Claude Desktop 自定义连接器不支持静态请求头,因此可在 claude_desktop_config.json 中通过 mcp-remote 桥接:
{
"mcpServers": {
"handoff": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://hand-off.space/mcp",
"--header", "Authorization:${HANDOFF_AUTH}"],
"env": { "HANDOFF_AUTH": "Bearer YOUR_HANDOFF_API_KEY" }
}
}
}
Cursor(~/.cursor/mcp.json 或 .cursor/mcp.json)
{
"mcpServers": {
"handoff": {
"url": "https://hand-off.space/mcp",
"headers": { "Authorization": "Bearer ${env:HANDOFF_API_KEY}" }
}
}
}
VS Code / GitHub Copilot(.vscode/mcp.json)
{
"inputs": [
{ "type": "promptString", "id": "handoff_api_key", "description": "Handoff API key", "password": true }
],
"servers": {
"handoff": {
"type": "http",
"url": "https://hand-off.space/mcp",
"headers": { "Authorization": "Bearer ${input:handoff_api_key}" }
}
}
}
Cline(cline_mcp_settings.json)
请明确设置 "type": "streamableHttp"。如果省略此项,Cline 会回退到旧版 SSE。
{
"mcpServers": {
"handoff": {
"type": "streamableHttp",
"url": "https://hand-off.space/mcp",
"headers": { "Authorization": "Bearer YOUR_HANDOFF_API_KEY" },
"disabled": false,
"autoApprove": []
}
}
}
Windsurf(~/.codeium/windsurf/mcp_config.json)
{
"mcpServers": {
"handoff": {
"serverUrl": "https://hand-off.space/mcp",
"headers": { "Authorization": "Bearer ${env:HANDOFF_API_KEY}" }
}
}
}
OpenAI Agents SDK(Python)
import asyncio, os
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp
async def main():
async with MCPServerStreamableHttp(
name="handoff",
params={
"url": "https://hand-off.space/mcp",
"headers": {"Authorization": f"Bearer {os.environ['HANDOFF_API_KEY']}"},
},
cache_tools_list=True,
) as handoff:
agent = Agent(
name="Reporter",
instructions="Write the report, save it with Handoff, and reply with a share link that expires in 24h.",
mcp_servers=[handoff],
)
print((await Runner.run(agent, "Summarize Q3 sales into report.md and share it.")).final_output)
asyncio.run(main())
LangChain / LangGraph(langchain-mcp-adapters)
import os
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent
client = MultiServerMCPClient({
"handoff": {
"transport": "streamable_http",
"url": "https://hand-off.space/mcp",
"headers": {"Authorization": f"Bearer {os.environ['HANDOFF_API_KEY']}"},
}
})
tools = await client.get_tools()
agent = create_agent("openai:gpt-4.1", tools) # or langgraph.prebuilt.create_react_agent
Hermes Agent(~/.hermes/config.yaml)
mcp_servers:
handoff:
url: "https://hand-off.space/mcp"
headers:
Authorization: "Bearer YOUR_HANDOFF_API_KEY"
OpenClaw(~/.openclaw/openclaw.json)
请明确设置 transport,因为 OpenClaw 默认使用 SSE。开始时请省略 headers,以便使用 share_file。
{ "mcp": { "servers": { "handoff": {
"url": "https://hand-off.space/mcp",
"transport": "streamable-http",
"headers": { "Authorization": "Bearer ${HANDOFF_API_KEY}" } } } } }
其他 MCP 客户端
| 设置 | 值 |
|---|---|
| URL | https://hand-off.space/mcp |
| 传输方式 | Streamable HTTP(无状态,仅 POST) |
| 请求头 | Authorization: Bearer <api_key> |
llms-install.md 中提供了面向 Agent 的分步设置说明。
Agent Skill(无需 MCP)
本仓库还提供了一个 Agent Skill,可教会任何支持 Skill 的 Agent(Claude Code、Codex、Copilot、Cursor 等)使用 REST API:
npx skills add jueluddinsf/handoff-mcp
与 Grok Bot 配合使用
添加 Handoff 作为自定义 MCP 连接器:
| 设置 | 值 |
|---|---|
| URL | https://hand-off.space/mcp |
| 请求头 | 初始无需设置;之后设置为 Authorization: Bearer <api_key> |
Bot 无需密钥即可立即调用 share_file。保存它返回的 api_key(只显示一次),然后将其填入请求头并重新连接;或者将其作为 api_key 工具参数传入。
也可以让 Bot 按照 skills/handoff/SKILL.md 的说明,通过普通 HTTP 调用 REST API。
提示词示例:
- 将这份报告保存到 Handoff,并发送一个 24 小时后过期的链接给我。
- 只与我的另一个 Agent 共享此文件。
- 告诉我谁打开了该链接,然后撤销它。
使用示例
Agent → 人类报告,一次调用
share_file(name="report.md", content_text=…, expires_in_hours=24, max_opens=3) → 发送 url。
Agent → 人类报告,设置过期时间(三步)
save_file(report.pdf) → create_share_link(audience="anyone_with_link", expires_in_hours=24, max_opens=3) → 发送 url。使用 get_access_log 确认文件已被打开。
Agent → Agent 移交
Agent A 调用 share_file(name=…, content_text=…, audience="agent", audience_value="agent-b");如果文件已保存,则调用 create_share_link(audience="agent", audience_value="agent-b")。Agent B 使用自己的密钥下载:
curl -L -H "authorization: Bearer $AGENT_B_KEY" -o out.bin "$URL"
通过 MCP,Agent B 也可以调用 fetch_shared_file(url_or_token=URL)。其他任何调用方都会收到 401 {"error":"unauthorized",…}。
人工审批关卡
调用 share_file(..., requires_approval=true) 或 create_share_link(..., requires_approval=true)。在所有者批准之前,打开链接会返回 403 {"error":"pending_approval",…}。如需批准或拒绝,请调用 approve_share / deny_share MCP 工具,或:
curl -X POST -H "authorization: Bearer $HANDOFF_API_KEY" $BASE/v1/grants/GRANT_ID/approve # or /deny
限制(免费、未认领的账户)
- 总容量 100 MB,最多 50 个文件,单个文件不超过 10 MB,每天最多成功打开 200 次。
- 允许的文件类型包括文本、Markdown、HTML、代码、CSV、JSON、PDF、图片、Office 文档和 zip 压缩包。
- 不允许上传可执行文件。
- Slack、X、Discord 等平台的链接预览抓取不会计入打开次数。
- 注册按 IP 限流。
下载响应
| 状态 | 错误 | 含义 |
|---|---|---|
410 | expired | 链接已过期。 |
410 | limit | 链接已达到最大打开次数。 |
429 | limit | 账户已达到每日上限。 |
403 | revoked / denied / pending_approval | 已撤销、已拒绝或仍在等待批准。 |
401 | unauthorized | 此链接属于其他 Agent。 |
安全模型
- 文件默认设为私密。每次分享都是一项拥有独立令牌的明确授权。
- 下载内容以
application/octet-stream附件形式提供,并设置Content-Security-Policy: sandbox和nosniff。 - 每次尝试,无论成功还是被拒绝,都会记录日志。
- API 密钥以哈希形式存储,且仅显示一次。
请私下报告安全问题(参见 CONTRIBUTING.md)。
许可证
MIT。此许可证适用于本仓库中的文档和示例。托管服务由 Juel Uddin 运营。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。