Handoff MCP
Provides AI agents with private file storage and controlled sharing capabilities via share links with expiry, open limits, and approval workflows. Supports saving files, listing files, creating share links, managing access, and downloading shared content through REST and MCP interfaces.
Endpoint and access
No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.
https://hand-off.space/mcpWhat you can do with it
- Save a file and generate a share link with expiry and open limits
- Store private files for agent use without human signup
- Approve or deny access to shared files requiring approval
- List and manage file grants and access logs
Source and maintenance
- Maintenance checked
Protocol and capabilities
- Server
- io.github.jueluddinsf/handoff 1.0.1
- MCP protocol
- 2025-06-18
- Tools
- 14 advertised
- Resources
- Not advertised
- Resource templates
- Not advertised
- Prompts
- Not advertised
{
"tools": {
"listChanged": true
}
}Server-provided instructions
Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.
Tools
14 advertised
share_file — Share a file
Share a file in one call and get a download link. Pass name and content_text (or content_base64). Works without an API key: if none is sent, a new account is created and its api_key is returned once; save it to revoke the link or read the access log later. Default link: anyone with the link, expires in 7 days.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"name"
],
"properties": {
"ref": {
"type": "string",
"pattern": "^[a-z0-9._-]+$",
"maxLength": 64,
"minLength": 1,
"description": "Optional attribution label. Lowercase letters, digits, dot, underscore, or hyphen. At most 64 characters."
},
"mime": {
"type": "string",
"pattern": "^[\\w.+-]+\\/[\\w.+-]+$",
"maxLength": 200,
"description": "MIME type. Inferred from the file name when omitted."
},
"name": {
"type": "string",
"pattern": "^[^/\\\\\\x00-\\x1f]+$",
"maxLength": 255,
"minLength": 1,
"description": "File name with an extension. No slashes or control characters."
},
"api_key": {
"type": "string",
"minLength": 1,
"description": "Secret API key from signup. Prefer Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass this only when you cannot set headers. Do not write it into a file you share."
},
"audience": {
"enum": [
"anyone_with_link",
"agent"
],
"type": "string",
"description": "Default anyone_with_link."
},
"max_opens": {
"type": "integer",
"maximum": 2147483647,
"description": "Successful downloads allowed. Omit for no limit.",
"exclusiveMinimum": 0
},
"content_text": {
"type": "string",
"maxLength": 70000000,
"description": "UTF-8 text. Pass exactly one of content_text or content_base64."
},
"audience_value": {
"type": "string",
"maxLength": 320,
"description": "Required when audience is agent."
},
"content_base64": {
"type": "string",
"maxLength": 70000000,
"description": "Standard or url-safe base64. A data:*;base64, prefix is stripped. Example: aGk="
},
"expires_in_hours": {
"type": "number",
"maximum": 87600,
"description": "Hours until the link expires. Default 168 (7 days).",
"exclusiveMinimum": 0
},
"requires_approval": {
"type": "boolean",
"description": "Default false. When true, downloads wait until the owner approves."
}
},
"additionalProperties": false
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"url",
"expires_at",
"max_opens",
"requires_approval",
"file_id",
"grant_id",
"token_prefix",
"next"
],
"properties": {
"url": {
"type": "string"
},
"next": {
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"required": [
"header",
"mcp_url",
"if_no_headers",
"configs",
"first_call"
],
"properties": {
"header": {
"type": "string"
},
"configs": {
"type": "object",
"required": [
"claude_code",
"cursor_json"
],
"properties": {
"claude_code": {
"type": "string"
},
"cursor_json": {
"type": "object",
"required": [
"mcpServers"
],
"properties": {
"mcpServers": {
"type": "object",
"required": [
"handoff"
],
"properties": {
"handoff": {
"type": "object",
"required": [
"url",
"headers"
],
"properties": {
"url": {
"type": "string"
},
"headers": {
"type": "object",
"required": [
"Authorization"
],
"properties": {
"Authorization": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"mcp_url": {
"type": "string"
},
"first_call": {
"type": "string"
},
"if_no_headers": {
"type": "string"
}
},
"additionalProperties": false
}
]
},
"api_key": {
"type": "string"
},
"file_id": {
"type": "string"
},
"grant_id": {
"type": "string"
},
"max_opens": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
]
},
"expires_at": {
"type": "string"
},
"token_prefix": {
"type": "string"
},
"requires_approval": {
"type": "boolean"
}
},
"additionalProperties": false
}{
"title": "Share a file",
"readOnlyHint": false,
"openWorldHint": true,
"idempotentHint": false,
"destructiveHint": false
}signup — Create an account
Create a Handoff account and return an API key once. No Authorization header is required. Save api_key. On later calls send Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass api_key only if you cannot set headers. share_file can create this key for you. The key is a secret. Do not put it in a file you share.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"ref": {
"type": "string",
"pattern": "^[a-z0-9._-]+$",
"maxLength": 64,
"minLength": 1,
"description": "Optional attribution label. Lowercase letters, digits, dot, underscore, or hyphen. At most 64 characters."
},
"agent_id": {
"type": "string",
"pattern": "^[a-zA-Z0-9_-]+$",
"maxLength": 80,
"minLength": 1,
"description": "Optional label, unique across Handoff. Letters, numbers, underscore, and hyphen."
}
},
"additionalProperties": false
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"account_id",
"api_key",
"agent_id",
"caps",
"next"
],
"properties": {
"caps": {
"type": "object",
"required": [
"total_mb",
"files",
"opens_per_day",
"file_mb"
],
"properties": {
"files": {
"type": "number"
},
"file_mb": {
"type": "number"
},
"total_mb": {
"type": "number"
},
"opens_per_day": {
"type": "number"
}
},
"additionalProperties": false
},
"next": {
"type": "object",
"required": [
"header",
"mcp_url",
"if_no_headers",
"configs",
"first_call"
],
"properties": {
"header": {
"type": "string"
},
"configs": {
"type": "object",
"required": [
"claude_code",
"cursor_json"
],
"properties": {
"claude_code": {
"type": "string"
},
"cursor_json": {
"type": "object",
"required": [
"mcpServers"
],
"properties": {
"mcpServers": {
"type": "object",
"required": [
"handoff"
],
"properties": {
"handoff": {
"type": "object",
"required": [
"url",
"headers"
],
"properties": {
"url": {
"type": "string"
},
"headers": {
"type": "object",
"required": [
"Authorization"
],
"properties": {
"Authorization": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"mcp_url": {
"type": "string"
},
"first_call": {
"type": "string"
},
"if_no_headers": {
"type": "string"
}
},
"additionalProperties": false
},
"api_key": {
"type": "string"
},
"agent_id": {
"type": "string"
},
"account_id": {
"type": "string"
}
},
"additionalProperties": false
}{
"title": "Create an account",
"readOnlyHint": false,
"idempotentHint": false,
"destructiveHint": false
}save_file — Save a file
Save a private file for this account. Pass name and content_text or content_base64. Returns the file id and metadata. Does not share the file. Requires your API key.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"name"
],
"properties": {
"mime": {
"type": "string",
"pattern": "^[\\w.+-]+\\/[\\w.+-]+$",
"maxLength": 200,
"description": "MIME type. Inferred from the file name when omitted."
},
"name": {
"type": "string",
"pattern": "^[^/\\\\\\x00-\\x1f]+$",
"maxLength": 255,
"minLength": 1,
"description": "File name with an extension. No slashes or control characters."
},
"api_key": {
"type": "string",
"minLength": 1,
"description": "Secret API key from signup. Prefer Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass this only when you cannot set headers. Do not write it into a file you share."
},
"content_text": {
"type": "string",
"maxLength": 70000000,
"description": "UTF-8 text. Pass exactly one of content_text or content_base64."
},
"content_base64": {
"type": "string",
"maxLength": 70000000,
"description": "Standard or url-safe base64. A data:*;base64, prefix is stripped. Example: aGk="
}
},
"additionalProperties": false
}{
"title": "Save a file",
"readOnlyHint": false,
"idempotentHint": false,
"destructiveHint": false
}list_files — List files
List this account's files, newest first, up to 1000. Use this to find a file_id before sharing. Returns metadata only, never bytes or download URLs. Requires your API key.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"api_key": {
"type": "string",
"minLength": 1,
"description": "Secret API key from signup. Prefer Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass this only when you cannot set headers. Do not write it into a file you share."
}
},
"additionalProperties": false
}{
"title": "List files",
"readOnlyHint": true,
"idempotentHint": true,
"destructiveHint": false
}create_share_link — Create a share link
Create a controlled download link for a file you own. Use this when a person or another agent should fetch the file. The response includes url and token ONCE, plus expires_at and max_opens. Save the url immediately. Later status calls do not return it. When expires_in_hours is omitted, the link expires in 7 days. Download with GET on that url. Requires your API key.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"file_id",
"audience"
],
"properties": {
"api_key": {
"type": "string",
"minLength": 1,
"description": "Secret API key from signup. Prefer Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass this only when you cannot set headers. Do not write it into a file you share."
},
"file_id": {
"type": "string",
"minLength": 1,
"description": "File id returned by save_file or list_files."
},
"audience": {
"enum": [
"anyone_with_link",
"agent"
],
"type": "string",
"description": "anyone_with_link: whoever has the saved url. agent: only the registered agent_id in audience_value."
},
"max_opens": {
"type": "integer",
"maximum": 2147483647,
"description": "Successful downloads allowed. The next one is refused.",
"exclusiveMinimum": 0
},
"audience_value": {
"type": "string",
"maxLength": 320,
"description": "Required for agent: the recipient's registered agent_id. Example: their-agent"
},
"expires_in_hours": {
"type": "number",
"maximum": 87600,
"description": "Hours until the link expires. Default 168 (7 days) when omitted.",
"exclusiveMinimum": 0
},
"requires_approval": {
"type": "boolean",
"default": false,
"description": "When true, downloads wait until the owner approves the grant."
}
},
"additionalProperties": false
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"grant_id",
"url",
"token",
"token_prefix",
"expires_at",
"max_opens"
],
"properties": {
"url": {
"type": "string"
},
"token": {
"type": "string"
},
"grant_id": {
"type": "string"
},
"max_opens": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
]
},
"expires_at": {
"type": "string"
},
"token_prefix": {
"type": "string"
}
},
"additionalProperties": false
}{
"title": "Create a share link",
"readOnlyHint": false,
"idempotentHint": false,
"destructiveHint": false
}get_share_status — Get share status
Read an owned grant: token_prefix (not the secret), audience, approval, expiry, revocation, and open_count. Does not download the file and does not return the share URL. Requires your API key.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"grant_id"
],
"properties": {
"api_key": {
"type": "string",
"minLength": 1,
"description": "Secret API key from signup. Prefer Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass this only when you cannot set headers. Do not write it into a file you share."
},
"grant_id": {
"type": "string",
"minLength": 1,
"description": "grant_id returned when the share was created."
}
},
"additionalProperties": false
}{
"title": "Get share status",
"readOnlyHint": true,
"idempotentHint": true,
"destructiveHint": false
}approve_share — Approve a share
Approve an owned grant that was created with requires_approval. Opens stay blocked until this succeeds. Requires your API key.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"grant_id"
],
"properties": {
"api_key": {
"type": "string",
"minLength": 1,
"description": "Secret API key from signup. Prefer Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass this only when you cannot set headers. Do not write it into a file you share."
},
"grant_id": {
"type": "string",
"minLength": 1,
"description": "grant_id returned when the share was created."
}
},
"additionalProperties": false
}{
"title": "Approve a share",
"readOnlyHint": false,
"idempotentHint": true,
"destructiveHint": false
}deny_share — Deny a share
Deny an owned grant. A denied grant stays blocked. Requires your API key.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"grant_id"
],
"properties": {
"api_key": {
"type": "string",
"minLength": 1,
"description": "Secret API key from signup. Prefer Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass this only when you cannot set headers. Do not write it into a file you share."
},
"grant_id": {
"type": "string",
"minLength": 1,
"description": "grant_id of the share to deny."
}
},
"additionalProperties": false
}{
"title": "Deny a share",
"readOnlyHint": false,
"idempotentHint": true,
"destructiveHint": true
}revoke_share — Revoke a share
Permanently revoke an owned share. Later downloads fail. This cannot be undone and does not delete the file. Requires your API key.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"grant_id"
],
"properties": {
"api_key": {
"type": "string",
"minLength": 1,
"description": "Secret API key from signup. Prefer Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass this only when you cannot set headers. Do not write it into a file you share."
},
"grant_id": {
"type": "string",
"minLength": 1,
"description": "grant_id of the share to revoke."
}
},
"additionalProperties": false
}{
"title": "Revoke a share",
"readOnlyHint": false,
"idempotentHint": true,
"destructiveHint": true
}get_access_log — Get access log
Read the latest 1000 access attempts for an owned grant, including refused downloads. Use this to see whether a share was opened. Requires your API key.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"grant_id"
],
"properties": {
"api_key": {
"type": "string",
"minLength": 1,
"description": "Secret API key from signup. Prefer Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass this only when you cannot set headers. Do not write it into a file you share."
},
"grant_id": {
"type": "string",
"minLength": 1,
"description": "grant_id of the share to audit."
}
},
"additionalProperties": false
}{
"title": "Get access log",
"readOnlyHint": true,
"idempotentHint": true,
"destructiveHint": false
}fetch_shared_file — Fetch a shared file
Download a file from a share url or token. Use this when you were given a Handoff url and need the bytes. Honors expiry, open limits, approval, and agent audience. anyone_with_link needs no key. An agent audience uses your API key. Files up to 1048576 bytes return content_base64, plus content_text when the file is text. Larger files are not inlined: the error includes the byte size and tells you to GET the url. A successful inline return counts as an open. A file over the inline limit does not.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"url_or_token"
],
"properties": {
"api_key": {
"type": "string",
"minLength": 1,
"description": "Secret API key from signup. Prefer Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass this only when you cannot set headers. Do not write it into a file you share."
},
"url_or_token": {
"type": "string",
"minLength": 1,
"description": "Share url returned by create_share_link, or the 64-character token."
}
},
"additionalProperties": false
}{
"title": "Fetch a shared file",
"readOnlyHint": true,
"openWorldHint": true,
"idempotentHint": false,
"destructiveHint": false
}delete_file — Delete a file
Delete a file you own. The bytes are removed and existing share links stop working. Requires your API key.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"file_id"
],
"properties": {
"api_key": {
"type": "string",
"minLength": 1,
"description": "Secret API key from signup. Prefer Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass this only when you cannot set headers. Do not write it into a file you share."
},
"file_id": {
"type": "string",
"minLength": 1,
"description": "File id returned by save_file, list_files, or share_file."
}
},
"additionalProperties": false
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"file_id",
"deleted"
],
"properties": {
"deleted": {
"type": "boolean",
"const": true
},
"file_id": {
"type": "string"
}
},
"additionalProperties": false
}{
"title": "Delete a file",
"readOnlyHint": false,
"idempotentHint": false,
"destructiveHint": true
}list_shares — List shares
List grants you own. Pass file_id to limit the list to one file. Returns grant_id, status, open_count, max_opens, expires_at, and audience. Does not return tokens or download urls. Requires your API key.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"api_key": {
"type": "string",
"minLength": 1,
"description": "Secret API key from signup. Prefer Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass this only when you cannot set headers. Do not write it into a file you share."
},
"file_id": {
"type": "string",
"minLength": 1,
"description": "Optional file id. Omit to list every grant on this account."
}
},
"additionalProperties": false
}{
"title": "List shares",
"readOnlyHint": true,
"idempotentHint": true,
"destructiveHint": false
}update_share — Update share expiry
Set when an owned share expires. expires_in_hours is measured from now. Example: 168 for 7 days. Does not return the token. Requires your API key.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"grant_id",
"expires_in_hours"
],
"properties": {
"api_key": {
"type": "string",
"minLength": 1,
"description": "Secret API key from signup. Prefer Authorization: Bearer <api_key>, the bare key in Authorization, or X-Handoff-Api-Key. Pass this only when you cannot set headers. Do not write it into a file you share."
},
"grant_id": {
"type": "string",
"minLength": 1
},
"expires_in_hours": {
"type": "number",
"maximum": 87600,
"exclusiveMinimum": 0
}
},
"additionalProperties": false
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"grant_id",
"file_id",
"status",
"open_count",
"max_opens",
"expires_at",
"audience"
],
"properties": {
"status": {
"type": "string"
},
"file_id": {
"type": "string"
},
"audience": {
"type": "string"
},
"grant_id": {
"type": "string"
},
"max_opens": {
"type": [
"number",
"null"
]
},
"expires_at": {
"type": [
"string",
"null"
]
},
"open_count": {
"type": "number"
}
},
"additionalProperties": false
}{
"title": "Update share expiry",
"readOnlyHint": false,
"idempotentHint": false,
"destructiveHint": false
}Prompts
Not advertised
Resources
Not advertised
30-day availability
Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.
- Successful checks
- 1 of 1 (100%)
- Average latency
- 731 ms
- 95th percentile latency
- 731 ms
Maintenance history
Public check and source-refresh events. Editorial and ownership records remain private.
- · probe · passed · 731 ms · metadata changed · 14 tool(s)
Connect from your client
Each snippet registers the same endpoint; pick the client you use.
Claude Code
claude mcp add --transport http handoff-mcp-hand-off https://hand-off.space/mcpCodex
codex mcp add handoff-mcp-hand-off --url https://hand-off.space/mcpCursor
{
"mcpServers": {
"handoff-mcp-hand-off": {
"url": "https://hand-off.space/mcp"
}
}
}Cline
{
"mcpServers": {
"handoff-mcp-hand-off": {
"type": "streamableHttp",
"url": "https://hand-off.space/mcp",
"disabled": false
}
}
}VS Code
{
"servers": {
"handoff-mcp-hand-off": {
"type": "http",
"url": "https://hand-off.space/mcp"
}
}
}Gemini CLI
gemini mcp add --transport http handoff-mcp-hand-off https://hand-off.space/mcpClaude Desktop
{
"mcpServers": {
"handoff-mcp-hand-off": {
"url": "https://hand-off.space/mcp"
}
}
}Windsurf
{
"mcpServers": {
"handoff-mcp-hand-off": {
"serverUrl": "https://hand-off.space/mcp"
}
}
}Let your agent find its tools
Find servers like Handoff MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.