Skip to content
Charming Docs
Esc
navigateopen⌘Jpreview
On this page

Connect to any AI agent

Build your app in one agent, then open, read, and update it from another: Claude, ChatGPT, any agent that speaks MCP or HTTP, all against the same app.

What you can do

Build with ChatGPT, then pick the work back up in Claude, Claude Code, or Cursor, without losing anything. Every Charming app is one URL and one dataset, so whichever agent you’re in is working on the real app, not a copy of it.

Your agent can read data, change data, and update the app’s code. Other people can point their own agents at the same app and do the same, within whatever access you’ve given them.

Technical

Charming speaks two open interfaces. It’s an MCP server, so any client that supports MCP connectors, Claude, ChatGPT, Cursor, and others, can add Charming directly; setup steps for each client are at Use Charming with your agent. It’s also a plain HTTP API, so any agent that can make web requests, even just curl, can use your app: give it the app’s id or URL and it has everything it needs.

Copy this prompt for your agent

Connect to my Charming apps. Read
https://charm.ing/docs/capabilities/connect-any-agent.md first. If
you don't have access yet, use the device-pairing flow it describes
and ask me to approve it, then list my apps so I can pick one to
work on.

How an agent performs this job

An agent with Charming MCP tools connected calls list_apps to find the app (or uses an id/URL it’s already been given), get_app to see the app’s current callable operations, get_app_source if it needs the actual code, query_app for a read-only operation, mutate_app for one that writes, and update_app if the code itself needs to change.

An agent that only makes HTTP requests does the same job through the matching routes: GET /app lists apps, GET /app/<id>/describe returns the operation inventory (GET /app/<id>/agent.json is the equivalent public, no-auth descriptor for a remixable or public app), GET /app/<id>/source exports the code, POST /app/<id>/api/<op> calls one operation (the route’s declared method decides whether it’s a read or a write), and PUT /app/<id> ships a code update.

To use the app from a chat assistant, add Charming as a connector in that client first; setup steps are at Use Charming with your agent. Or hand the job to a code agent that can make HTTP requests instead.

The contract

Two credential families decide what a second agent can touch:

  • bld_user_* (account-scoped). Minted by signing in and calling POST /api/token, or by device-pairing (POST /api/pair/start, approve at charm.ing/pair, POST /api/pair/poll). Any agent holding this token can list, read, and mutate every app the account owns, not just the one that first created it. Browser-minted tokens default to a 7-day TTL; paired tokens default to 30 days.
  • bld_app_* (one app). Minted for a specific app at anonymous create. It authorizes mutations and /api/* calls on that one app id only and doesn’t list or touch any other app. If the app has since been claimed by an account, a stale bld_app_* gets a 401 with a recovery block pointing at the device-pairing flow instead of a silent failure.

Over MCP, the client completes OAuth once when it’s added as a connector; after that, tool calls carry the signed-in account’s scope automatically, so the agent never handles a bearer token directly. Over HTTP, the calling agent supplies Authorization: Bearer <bld_user_* or bld_app_*> itself on every request.

Limits, access, and deletion

  • Read-only vs writing. query_app only runs operations the app declares read-only (method: 'GET' or readOnly: true); calling a mutating operation through it returns not_read_only. mutate_app requires run access and refuses to run an operation declared read-only.
  • Viewer role. An agent acting for a read-only viewer (holding app:read but not app:run) can call query_app but gets forbidden_write if the underlying handler tries to write, and is denied mutate_app outright.
  • Scope leaks stay closed. A bld_app_* token can’t list or read the source of any app other than the one it was minted for; those calls 401.
  • Render tokens aren’t for this. The bld_render_* token embedded in a rendered app’s page is scoped to that page calling its own backend, not to an outside agent driving the app. A second agent uses bld_app_* or bld_user_* instead.
  • Deletion. Deleting the app (delete_app / DELETE /app/<id>) removes it for every agent that had access, not just the one that called delete.

Was this page helpful?