MCP
Thinkfree Drive embeds an MCP (Model Context Protocol) server at /mcp. An AI client - the Claude app, Claude Code, or
any other MCP client - connects with OAuth 2.0 or an API Key and then calls Drive features with the permissions of
the connected account: a regular user (USER) account gets the file, folder, and sharing tools, an administrator
(ADMIN) account gets the account and API Key tools.
The server exposes 50 tools - 27 user tools and 23 administrator tools.
| Item | Value |
|---|---|
| Endpoint | /mcp on the tenant subdomain, Streamable HTTP. Stateless: no Mcp-Session-Id session, and tools/list and tools/call work as one-shot calls without initialize. |
| Authentication | One header, Authorization: Bearer replace-with-your-api-key, carrying either an OAuth 2.0 access token (dynamic client registration plus user consent) or the API Key itself (an opaque string issued in the admin area). The server treats a JWT-shaped value as OAuth and anything else as an API Key. |
| Scopes | mcp:read for reads, mcp:write for writes (which includes reads). OAuth takes the scope the user approved on the consent screen; an API Key takes the scope combination chosen when it was issued. |
| Account role | Each tool declares the account role it requires and the check is an exact match - the 27 user tools are USER-only and the 23 administrator tools are ADMIN-only. A SUPER_ADMIN account can call neither: there is no role hierarchy. |
| Tenant | The tenant is resolved from the request host. An administrator tool may only target a userSeq or apiKeySeq in that same tenant. |
Authentication, scope combinations, and API Key lifecycle are documented in Authentication; the same keys authenticate the Document Management API.
Transport
MCP Streamable HTTP carries JSON-RPC 2.0 over HTTP POST, so the server can be called directly with curl. Every request
is a POST to /mcp and carries three headers:
Authorization: Bearer replace-with-your-api-key- an OAuth access token or an API Key. Missing, and the server answers401withWWW-Authenticate.Content-Type: application/jsonAccept: application/json, text/event-stream- both media types are required; omitting either fails with400or406.
The response body is the JSON-RPC response as application/json; there are no SSE data: frames. GET /mcp returns
405.
An MCP client library sends initialize and notifications/initialized first. Over curl you can skip both. If you do
send initialize, it answers 200, returns no Mcp-Session-Id, and reports every listChanged capability as false.
Listing tools
curl -X POST "https://drive.example.com/mcp" \
-H "Authorization: Bearer replace-with-your-api-key" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}'
result.tools[] holds the name, description, and inputSchema of all 50 tools. The list does not depend on the
account role - every tool is listed, and a tool the account may not use is refused when it is called.
Calling a tool
A tools/call result carries the tool's own response envelope, serialized as a JSON string in result.content[0].text:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{"type": "text", "text": "{\"data\":{}}"}
],
"isError": false
}
}
Response envelope
Every tool result is wrapped in an envelope. Success is {"data": {…}}, and an expected failure - validation,
permission, or a business rule - is {"error": "…"} with an optional errorCode.
Success is the absence of an error field. Expected failures are returned in band: the HTTP status is still 200
and isError is still false, so a client that only checks the transport will read a failure as a success.
Fields whose value is null are dropped from the serialized data object. Many write tools return no data at all on
success, just an empty envelope {}. One tool, drive_admin_get_users_status, returns an array rather than an object
as its data.
The message inside error is a human-readable Korean string; errorCode - where one is present - is the stable value
to branch on. It uses the same code vocabulary as the Document Management API, listed in Errors.
{"error": "유저 정보를 찾을 수 없습니다.", "errorCode": "USER_005"}
Checks before a tool runs
The server applies four checks, in this order: role, scope, tenant, then the tool itself.
| Check | Behavior |
|---|---|
| Role | The account role must match the role the tool declares. Calling an administrator tool from a user account is refused, and so is the reverse. |
| Scope | The 30 write tools - 16 user and 14 administrator - are refused when the connection has no mcp:write. For read tools, holding either scope is enough. |
| Tenant | An administrator tool's target userSeq or apiKeySeq must belong to the request host's tenant. A target in another tenant is hidden as if it did not exist: USER_005 or API_KEY_001. |
| Input | required in inputSchema is client guidance, not server enforcement, so each tool validates its own input and reports a missing value in band, as "{parameter}는 필수입니다." |
Further input rules the tools enforce in band:
- Parameters that are only meaningful as a pair - a date range's start and end,
cursorIdwithcursorValue,countryCodewithphoneNumber- must be sent together. An empty string counts as not sent. - Length limits (
userNameis 20 characters) and future-dated values (expireDate) are checked. - A SQL exception is never echoed back. The server returns a generic "check the format and length of your input" message instead.
Shared conventions
Cursor pagination. When a list tool returns hasNext=true, pass its nextCursor, nextCursorValue, and
nextCursorType straight back as cursorId, cursorValue, and cursorType on the next call. Most administrator list
tools use a single cursor (only nextCursor is set); drive_admin_list_pending_delete_users uses a composite cursor.
drive_list_resource_versions is the one offset-based tool - it pages with pageIndex against totalCount.
Reaching a shared resource. For a resource someone shared with you, pass the list item's sharedByUserSeq - or its
userSeq when that is absent - as the tool's sharedByUserSeq, or as targetUserSeq where the parameter names a
destination (copy, move, create). It is not ownerSeq. Omit it for your own resources.
Web links. List, metadata, and file tools return webViewUrl, a browser link that previews a file or opens a
folder. When the format is editable in web office and the caller has canEdit, editUrl is returned as well.
Dates. Request date ranges such as startDate and endDate are yyyy-MM-dd, inclusive, and both ends are
required. An expireDate is yyyy-MM-ddTHH:mm:ss, or yyyy-MM-dd, which is read as 23:59:59 that day. Timestamps in
responses are strings in yyyy-MM-dd HH:mm:ss form, with .SSS on date cursor values.
Permissions and audit. Each tool runs the permission check and the use case of the matching web API, and leaves the same audit and user-log entries the web product does. A password sent to an administrator tool is never written to the server log.
User tools
These 27 tools require a USER account.
| Group | Tool | Scope | Purpose |
|---|---|---|---|
| Search | drive_search_resources | READ | Search by name or list a folder's contents; My Drive by default |
| Search | drive_get_resource_metadata | READ | One resource's metadata plus the caller's six permission flags |
| Lists | drive_list_recent_resources | READ | Recently opened or edited resources, shared ones included |
| Lists | drive_list_starred_resources | READ | Starred resources |
| Lists | drive_list_trash_resources | READ | Deleted resources, with who deleted them and when |
| Lists | drive_list_shared_resources | READ | Resources shared with the caller |
| Files | drive_read_file | READ | File contents as text - 21 plain-text formats, 15 extracted (10 MB, 50,000 characters) |
| Files | drive_download_file | READ | Original bytes as base64, any format (10 MB) |
| Files | drive_upload_file | WRITE | Upload a new file from text or base64 content (512 KB) |
| Files | drive_create_file | WRITE | Create an empty office document (word, excel, ppt, note) |
| Files | drive_copy_file | WRITE | Copy one file; folders are not supported |
| Folders | drive_create_folder | WRITE | Create a folder, auto-numbering a duplicate name |
| Changes | drive_move_resource | WRITE | Move a file or folder, a folder with everything below it |
| Changes | drive_rename_resource | WRITE | Rename a file or folder |
| Starred | drive_star_resource | WRITE | Star a resource |
| Starred | drive_unstar_resource | WRITE | Unstar a resource, by starredSeq |
| Trash | drive_delete_resource | WRITE | Move to trash; restorable |
| Trash | drive_restore_trash_resource | WRITE | Restore from trash to its original location |
| Trash | drive_delete_trash_resource_permanently | WRITE | Delete permanently and return the quota; not recoverable |
| Versions | drive_list_resource_versions | READ | Version history of a file |
| Versions | drive_restore_resource_version | WRITE | Roll back to an earlier version |
| Versions | drive_delete_resource_version | WRITE | Delete one version permanently; owner only |
| Sharing | drive_get_share_permissions | READ | Share type, default permission, and target list |
| Sharing | drive_search_share_users | READ | Find share candidates by name or email |
| Sharing | drive_share_resource | WRITE | Owner-only upsert of share type, default permission, and targets |
| Sharing | drive_update_share_targets | WRITE | Replace the target list, for a delegate with canShare |
| Sharing | drive_unshare_resource | WRITE | Remove sharing entirely; owner only, not recoverable |
Administrator tools
These 23 tools require an ADMIN account, and every name carries the drive_admin_ prefix.
| Group | Tool | Scope | Purpose |
|---|---|---|---|
| Accounts | drive_admin_list_admins | READ | ADMIN accounts, filtered by status, userSeq cursor |
| Accounts | drive_admin_list_users | READ | USER accounts, filtered by status and user id, userSeq cursor |
| Accounts | drive_admin_search_users | READ | Partial name or email match; active USER accounts only, no cursor |
| Accounts | drive_admin_get_user | READ | One account in full - storage, phone, MFA - including deleted states |
| Accounts | drive_admin_get_users_status | READ | Emails in, userSeq and status out; data is an array |
| Accounts | drive_admin_get_user_storage_usage | READ | Quota, total, file, version, and trash bytes |
| Accounts | drive_admin_list_user_logs | READ | LOGIN, LOGOUT, CHANGE_PASSWORD entries, userLogSeq cursor |
| Account management | drive_admin_register_user | WRITE | Register one account; external authentication cannot be ADMIN |
| Account management | drive_admin_update_user | WRITE | Partial update - an omitted field is kept |
| Account management | drive_admin_update_user_password | WRITE | Change the password and reset the failed-login counter |
| Account management | drive_admin_activate_user | WRITE | INACTIVE to ACTIVE |
| Account management | drive_admin_deactivate_user | WRITE | ACTIVE to INACTIVE; not yourself, not the default administrator |
| Account management | drive_admin_bulk_upsert_users | WRITE | Array upsert in one transaction; an update replaces the whole record |
| Deletion | drive_admin_withdraw_user | WRITE | Move to PENDING_DELETE, purged after about 30 days |
| Deletion | drive_admin_list_pending_delete_users | READ | Accounts awaiting deletion, date-range filter, composite cursor |
| Deletion | drive_admin_restore_user | WRITE | PENDING_DELETE to INACTIVE |
| Deletion | drive_admin_delete_user | WRITE | Cascade delete, then DELETED; not recoverable |
| API Key | drive_admin_list_api_keys | READ | The tenant's keys, masked, apiKeySeq cursor |
| API Key | drive_admin_create_api_key | WRITE | Issue for yourself or a USER; the key is shown once |
| API Key | drive_admin_reissue_api_key | WRITE | Replace the key value and return it to ACTIVE; expiry is unchanged |
| API Key | drive_admin_activate_api_key | WRITE | INACTIVE to ACTIVE; idempotent |
| API Key | drive_admin_deactivate_api_key | WRITE | ACTIVE to INACTIVE; idempotent, and it can disable your own key |
| API Key | drive_admin_update_api_key_expire_date | WRITE | Future timestamps only; the recovery path for an expired key |
drive_delete_trash_resource_permanently, drive_delete_resource_version, drive_unshare_resource, and
drive_admin_delete_user cannot be undone. Grant mcp:write to an AI client only when the connected account is meant
to make changes of that kind.