Agents
MCP server
Complete OAuth remote Model Context Protocol surface: four tools, every operation and type branch, transport, limits, and recovery hints. Same ownership, scopes, quotas, and audit trail as API v1.
Connect
Connect ChatGPT, Claude, or another remote MCP client to your Bidama host. The server URL is the public origin plus /mcp.
| Transport | How | Auth |
|---|---|---|
| Remote HTTP | POST /mcp |
Authorization: Bearer bdmo_at_... |
| OAuth discovery | /.well-known/oauth-protected-resource/mcp |
Authorization code + PKCE |
Remote MCP URL: https://<your-host>/mcp
- HTTP is sessionless: each POST builds a temporary server from that request's OAuth access token. Unsafe cross-origin browser requests are rejected. Authenticated GET returns 405.
- ChatGPT and Claude should be configured with https://<your-host>/mcp, then complete the browser OAuth consent flow.
- Tool permissions are read, write, and delete. offline_access is only an authorization-server scope for refresh tokens.
- JSON-RPC batch arrays are rejected before dispatch so one transport request cannot fan out into unbounded tool calls.
- Each replica accepts at most four concurrent MCP HTTP requests and two per OAuth access token (429 + Retry-After beyond either bound). A POST body must finish within 60 seconds.
Tools
Four tools preserve authorization boundaries. Creation and change stay separate; delete is never mixed into write.
| Tool | Discriminator | Scope | readOnly |
destructive |
idempotent |
Description |
|---|---|---|---|---|---|---|
bidama_read |
operation (7) |
read |
true | false | true | Inspect account, resources, analytics, markdown versions, and jobs. |
bidama_create |
type (8) |
write |
false | false | false | Create any of the eight resource types, including files and artifacts. |
bidama_change |
operation (4) |
write |
false | true | false | Update, restore markdown, redeploy artifacts, or optimize originals. |
bidama_delete |
— | delete |
false | true | true | Soft-delete one owned resource by slug. |
Annotations are client hints, never authorization. bidama_create is openWorld because Notion create can schedule an external fetch; the other tools operate only on this deployment.
bidama_read
Requires read. Select exactly one closed operation branch:
operation |
Input fields | Description |
|---|---|---|
get_account | — | Identity, creation permissions, storage usage/limit, and enabled features. |
list_resources | q?, type?, label?, sort?, archived?, pinned?, limit?, cursor? | Compact rows and next_cursor. Default limit 20; MCP maximum 100. |
get_resource | slug, content? | Type-specific detail plus etag. content is snippet (default), full, or none. |
get_analytics | slug, days?, top? | Hits, visitors, daily counts, ranked buckets. days defaults to 30 (0 = all time, max 365); top defaults to 5 (max 10). |
list_markdown_versions | slug | Version rows with ID, number, source, size, preview, and created time. |
get_markdown_version | slug, version_id, content? | One historical markdown source; content defaults to full. |
get_job | job_id | Job status, safe result projection, error, attempts, completion time, and next poll delay while active. |
- type filters: link, markdown, file, image, collection, notion, bio, artifact. sort: newest, pinned, title, expiring, most_viewed, recently_updated. archived: false (default), true, or all.
- List rows omit owner IDs, internal object keys, and large bodies. Fetch get_resource for full public resource details.
bidama_create
Requires write. type selects one of eight closed branches. Unknown fields are rejected.
type |
Required type fields | Optional type fields |
|---|---|---|
link | target_url | max_views |
markdown | raw_markdown | max_views |
file | file_name, file_content | content_type, max_views |
image | file_name, file_content | content_type |
collection | — | — |
notion | source_url | root_page_id |
bio | — | display_name, headline, bio, theme |
artifact | archive_base64 or files | visibility |
- Common optional fields: slug, title, description, expires_at, password, labels.
- file_content is base64. The server sniffs MIME: image requires image bytes and file requires non-image bytes.
- Artifacts accept exactly one of archive_base64 (ZIP) or files as a native JSON array of {path, content, encoding?} — never a stringified JSON string, and never both modes. Prefer archive_base64 for multi-file packages when arrays are awkward. Decoded content is capped at 8 MiB; direct mode at most 500 files. visibility is public (default), unlisted, or private. max_views is not supported.
- Results return slug, type, url, and etag, plus essentials such as stored filename or artifact deployment_id, origin_url, and entry_path.
bidama_change
Requires write. Annotated destructive because branches can replace originals or retire deployments.
operation |
Input fields | Description |
|---|---|---|
update_resource | slug, if_match?, and at least one of title, description, new_slug, target_url, raw_markdown, expires_at, max_views, password, labels, archived, pinned, original_filename | Partial update of only fields present in the call. Empty expires_at or password clears it. |
restore_markdown_version | slug, version_id, if_match? | Snapshot current markdown and restore the selected version (reversible via history). |
redeploy_artifact | slug, if_match?, archive_base64 or files | Publish a new immutable deployment and retire the previous origin (same 8 MiB content modes as create). |
optimize_original | slug | Enqueue eligible JPEG/HEIC/HEIF original replacement; may irreversibly replace the stored original. Returns job_id for polling. |
- slug always identifies the current resource; new_slug is the replacement value on rename.
- Poll optimize jobs with bidama_read operation get_job. On job_already_active, reuse the earlier job_id rather than enqueueing again.
bidama_delete
Requires delete and accepts slug. Soft-deletes the owned resource so the slug stops resolving publicly. Success returns {slug, deleted: true}. Annotated idempotent: a safe retry may report not_found.
Example calls
Tools take a discriminator (type or operation). Keep the returned etag for later edits. For artifacts, files must be a real JSON array (see the second example), not a string.
bidama_create
{
"type": "markdown",
"title": "Release notes",
"raw_markdown": "# Hello\n\nShipped today."
}
bidama_create
{
"type": "artifact",
"title": "Demo",
"files": [
{"path": "index.html", "content": "<h1>Hi</h1>", "encoding": "text"}
]
}
bidama_change
{
"operation": "update_resource",
"slug": "release-notes",
"if_match": "<etag-from-get_resource>",
"title": "Release notes (final)"
}
bidama_read
{
"operation": "get_job",
"job_id": "<job-id-from-optimize_original>"
}
Conventions
- Omit slug on create to auto-generate one. Slugs are 3–64 characters: a–z, 0–9, - or _.
- get_resource returns an etag; pass it as if_match on bidama_change to avoid overwriting concurrent edits.
- Inline file and artifact payloads are capped at 8 MiB decoded (12 MiB MCP JSON envelope). Use REST uploads for larger content.
- Outputs include typed structuredContent plus a compact JSON text copy for clients that ignore structured output.
- The machine-readable REST contract is also available as MCP resource (text/yaml):
bidama://openapi.yaml
Errors and recovery
Failures keep the REST envelope (status, error_code, message, field/details, Retry-After) and append a short recovery hint for stable codes:
error_code |
Suggested action |
|---|---|
slug_taken | Choose another slug or omit it to auto-generate one. |
etag_mismatch | Re-read the resource and retry with the fresh etag. |
insufficient_scope | Reconnect or re-authorize with the required read, write, or delete scope. |
rate_limited | Wait for Retry-After and retry. |
quota_exceeded | Call get_account and free storage or increase the quota. |
job_already_active | Reuse and poll the job ID from the earlier accepted call. |
validation_failed | Correct the named field; do not retry unchanged input. |
artifact_index_missing | Include a non-empty root index.html or another non-empty HTML entry. |
not_found | Check the slug/ID and ownership; the resource may be deleted or expired. |
Deliberately not exposed
- No list_jobs — agents poll job IDs returned by their own operations.
- QR bytes are not returned as tool content; use the resource QR URL out of band.
- Cookie-API-only bio blocks, collection items, upload requests, and Notion cached-page ops are not MCP tools.
- No generic REST passthrough tool — typed schemas, annotations, and projections stay mandatory.
ChatGPT and Claude
In ChatGPT, Claude, or any remote MCP client, add a custom connector with this server URL and approve the requested scopes in Bidama.
{
"name": "Bidama",
"url": "https://<your-host>/mcp"
}
Revoke previously approved clients from Connected Apps: /connected-apps.