@kentcdodds/dropbox
Upload, share, and manage Dropbox files via OAuth — small or large uploads and direct download URLs.
AGENTS.md
254 lines · 7.9 KB · Markdown@kentcdodds/dropbox — agent notes
Human setup and intent live in README.md. This file is for
agents: imports, positive playbooks, and copy-paste execute snippets. Auth is
the saved OAuth integration named dropbox — never paste tokens. Do not
disable live webhooks or jobs. Do not use the Dropbox website UI — use these
MCP package exports.
Auth / integration
| Item | Value |
|---|---|
| Integration name | dropbox |
| Reconnect | https://kody.codes/connect/oauth?provider=dropbox |
Import paths
| Export | Import |
|---|---|
| overview | kody:@kentcdodds/dropbox |
| smoke-test | kody:@kentcdodds/dropbox/smoke-test |
| get-current-account | kody:@kentcdodds/dropbox/get-current-account |
| get-space-usage | kody:@kentcdodds/dropbox/get-space-usage |
| list-folder | kody:@kentcdodds/dropbox/list-folder |
| get-metadata | kody:@kentcdodds/dropbox/get-metadata |
| search | kody:@kentcdodds/dropbox/search |
| download | kody:@kentcdodds/dropbox/download |
| upload | kody:@kentcdodds/dropbox/upload |
| upload-large | kody:@kentcdodds/dropbox/upload-large |
| upload-from-url | kody:@kentcdodds/dropbox/upload-from-url |
| delete | kody:@kentcdodds/dropbox/delete |
| create-shared-link | kody:@kentcdodds/dropbox/create-shared-link |
| ensure-shared-direct-url | kody:@kentcdodds/dropbox/ensure-shared-direct-url |
| paths | kody:@kentcdodds/dropbox/paths |
| request | kody:@kentcdodds/dropbox/request |
Prefer static kody:@kentcdodds/dropbox/... imports from execute. Do not lead
with packages.invoke.
App-folder path primer
- Call
listFolder({ path: '', limit: 100 })first so you see the real root. - Kody-writable files live under
/Apps/Kody/…(constantAPP_FOLDER_ROOT), not/Kody/…. - Use
underAppFolder('notes/a.txt')→/Apps/Kody/notes/a.txt. - A 409 /
path/not_foundon a write often means the path is missing the/Apps/Kodyprefix — helpers suggest the corrected path.
import listFolder from 'kody:@kentcdodds/dropbox/list-folder'
import { underAppFolder } from 'kody:@kentcdodds/dropbox/paths'
export default async function main() {
const root = await listFolder({ path: '', limit: 50 })
return {
rootNames: root.entries.map((e) => e.path_display ?? e.name),
exampleDest: underAppFolder('notes/hello.txt'),
}
}Upload a file (small vs large)
Hard cutoff: 120 KiB binary (UPLOAD_SINGLE_MAX_BYTES = 122880). Base64
in MCP params bloats faster than raw bytes (~200KB+ MCP payloads hurt). Put
bytesBase64 only in params, never megabytes inside the code string.
| Size | Export | Notes |
|---|---|---|
| Tiny text / < 120 KiB binary | ./upload | text or small bytesBase64 in params |
| ≥ 120 KiB binary | ./upload-large | Session: start → append (~48 KiB chunks) → finish (closes) |
| Either | ./upload | Auto-delegates to ./upload-large when over threshold |
Small upload (params)
import upload from 'kody:@kentcdodds/dropbox/upload'
export default async function main() {
return await upload({
path: '/Apps/Kody/notes/hello.txt',
text: 'Hello from Kody',
mode: 'overwrite',
confirm: true,
})
}Large upload (bytesBase64 in params — never in code)
import uploadLarge from 'kody:@kentcdodds/dropbox/upload-large'
export default async function main(params) {
// Pass { path, bytesBase64, mode, confirm } via execute params.
return await uploadLarge({
path: params.path, // e.g. '/Apps/Kody/inbox/report.bin'
bytesBase64: params.bytesBase64,
mode: params.mode ?? 'overwrite',
confirm: true,
})
}mode: 'overwrite' maps to Dropbox commit mode: "overwrite" (string tag).
Finish closes the session — do not call append after finish.
dryRun plan:
import uploadLarge from 'kody:@kentcdodds/dropbox/upload-large'
export default async function main(params) {
return await uploadLarge({
path: params.path ?? '/Apps/Kody/notes/large.bin',
bytesBase64: params.bytesBase64 ?? '',
mode: 'overwrite',
dryRun: true,
})
}Computer agents (local file → Dropbox)
Read the local file on the computer, base64-encode it, then call ./upload or
./upload-large with bytesBase64 in params:
// Pseudocode on the computer agent — not inside Kody Workers:
// const bytesBase64 = Buffer.from(await fs.readFile(localPath)).toString('base64')
import upload from 'kody:@kentcdodds/dropbox/upload'
export default async function main(params) {
return await upload({
path: params.path, // '/Apps/Kody/...'
bytesBase64: params.bytesBase64,
mode: 'overwrite',
confirm: true,
})
}MCP-only / phone (no large base64)
Chat cannot carry large base64. Options:
- Compress / use a smaller WebP (or similar) under ~120 KiB binary, then
./upload. - If you have a public HTTP(S) URL Dropbox can fetch, use
./upload-from-url(files/save_url):
import uploadFromUrl from 'kody:@kentcdodds/dropbox/upload-from-url'
export default async function main(params) {
return await uploadFromUrl({
path: params.path, // '/Apps/Kody/inbox/photo.webp'
url: params.url, // public https://...
confirm: true,
})
}Do not use
files/get_temporary_upload_link— dead end for agents; prefer./upload/./upload-large.- Dropbox website login / UI — use these package exports over MCP instead.
Share → direct download URL (Fable / curl)
After upload, call ./ensure-shared-direct-url for a browser/curl-friendly
content URL on dl.dropboxusercontent.com with raw=1. Reuses an existing link via
list_shared_links when create returns “already exists”.
import ensureSharedDirectUrl from 'kody:@kentcdodds/dropbox/ensure-shared-direct-url'
export default async function main(params) {
return await ensureSharedDirectUrl({
path: params.path, // '/Apps/Kody/notes/guide.pdf'
confirm: true,
})
// => { path, url, directUrl, reused, link }
}dryRun:
import ensureSharedDirectUrl from 'kody:@kentcdodds/dropbox/ensure-shared-direct-url'
export default async function main() {
return await ensureSharedDirectUrl({
path: '/Apps/Kody/notes/guide.pdf',
dryRun: true,
})
}Smoke test (read-only)
import smokeTest from 'kody:@kentcdodds/dropbox/smoke-test'
export default async function main() {
return await smokeTest()
// => { ok: true, hasAccountId, hasDisplayName, accountType } — no PII fields
}dryRun / confirm (writes)
upload, upload-large, upload-from-url, delete, create-shared-link,
ensure-shared-direct-url, and unknown/mutating ./request endpoints require
confirm: true after explicit user approval. Use dryRun: true to preview
without calling Dropbox. Documented read-only ./request endpoints do not need
confirmation.
import deleteDropboxPath from 'kody:@kentcdodds/dropbox/delete'
export default async function main() {
return await deleteDropboxPath({
path: '/Apps/Kody/notes/old.txt',
dryRun: true,
})
}Generic request (known read-only endpoint — no confirm):
import request from 'kody:@kentcdodds/dropbox/request'
export default async function main() {
return await request({
endpoint: 'files/get_metadata',
body: { path: '/Apps/Kody/notes/todo.txt' },
})
}Edge cases
- Paths start with
/; use''for the account root on list/search. - Prefer
/Apps/Kody/...for writes; list root before inventing paths. downloadreturns{ metadata, bytesBase64, byteLength, contentType }.upload: pass exactly one oftextorbytesBase64;modeisadd(default) oroverwrite. Over 120 KiB binary → auto./upload-large.upload-large: always passbytesBase64in params; session chunks ~48 KiB; finish closes the session.list-folder/search: continue with returnedcursorwhilehas_more.- Prefer dedicated helpers over assembling
./requestwhen one exists. - Never paste Dropbox OAuth tokens into chat or logs.