Skip to main content
BlendDuck Docs

MCP server

Connect Codex, ChatGPT, Claude, Cursor, or Inspector through OAuth-protected tools.

Documentation owner:
BlendDuck Documentation
Last reviewed:

BlendDuck exposes a remote Streamable HTTP MCP server:

https://blendduck.com/api/mcp

The server uses Better Auth for OAuth discovery, dynamic client registration, PKCE, consent, refresh tokens, and JWT validation. MCP clients never receive a BlendDuck session cookie or social-provider credential.

BlendDuck MCP currently accepts OAuth JWTs, not organization API keys. Leave a client's Bearer token environment variable and header fields empty. Organization API keys remain the headless REST/SDK/Zapier/n8n credential for /api/v1; they are not accepted by /api/mcp.

Connect Codex

Authenticate to BlendDuck with email OTP first. Guest sessions cannot approve an MCP grant. For a local quickstart, replace https://blendduck.com below with the exact APP_URL, such as http://localhost:5001.

In the Codex app:

  1. Open Settings → Plugins → MCP → Add server.
  2. Choose Streamable HTTP and enter https://blendduck.com/api/mcp.
  3. Leave Bearer token environment variable, static headers, and environment headers empty. Save and restart Codex.
  4. Select Authenticate, sign in to BlendDuck, choose the organization on the consent screen, and select Allow access.
  5. Type /mcp, then ask Codex to list the connected channels without making changes.

The Codex app, CLI, and IDE extension share the same local MCP configuration. The equivalent CLI setup is:

codex mcp add blendduck \
  --url https://blendduck.com/api/mcp \
  --oauth-resource https://blendduck.com/api/mcp

codex mcp login blendduck

The default grant is read-only. Request write scope only when the client needs to create, schedule, or publish posts:

codex mcp login blendduck \
  --scopes openid,profile,email,offline_access,blendduck:read,blendduck:write

Connect other clients

All supported clients use the same endpoint and OAuth contract. Copy the checked examples from examples/mcp, or use the native commands below:

claude mcp add --transport http blendduck https://blendduck.com/api/mcp
pnpm dlx @modelcontextprotocol/inspector@2.0.0 https://blendduck.com/api/mcp

Cursor reads the same URL from .cursor/mcp.json. Run cursor agent login once to select the Cursor identity, then authorize BlendDuck when the MCP server is first used. ChatGPT web does not read local Codex configuration. An eligible Developer mode workspace can create a custom app for the public HTTPS endpoint. A validated BlendDuck plugin package bundles the production endpoint, OAuth base read/write scopes, write-tool approval prompts, logo, and organization-bound workflow guidance for optional public distribution. Complete OAuth in the client, then use list_channels before making a draft-only create_post check. No API key or social-provider credential is entered during setup.

The deployed Registry manifest is versioned with the runtime. BlendDuck 3.2.0 is published and active under the domain-owned name com.blendduck/blendduck in the official MCP Registry.

Tools

ToolScopePurpose
list_channelsblendduck:readList connected channels and publishing support
get_provider_contractblendduck:readRead one provider's Zod-derived full post/settings schemas and media constraints
get_channel_healthblendduck:readInspect safe connection state and the next queue slot
validate_postblendduck:readValidate content, media, thread, and settings without writing
list_postsblendduck:readList posts with date, channel, state, and campaign filters
get_postblendduck:readRead one post and its delivery state
create_postblendduck:writeIdempotently draft, queue, schedule, prioritize, or publish a post
update_postblendduck:writeIdempotently update content, media, campaigns, or lifecycle mode
duplicate_postblendduck:writeCreate a fresh draft copy and all channel variants
cancel_postblendduck:writeCancel one target before it reaches a provider
retry_postblendduck:writeRetry one eligible failed provider target
delete_postblendduck:writePermanently delete a mutable post or target
list_campaignsblendduck:readList canonical campaign tags and usage counts
reschedule_postblendduck:writeMove one mutable target to an explicit date-time
bulk_calendar_actionblendduck:writeRun a bounded best-effort calendar command
list_mediablendduck:readList reusable tenant media and authoritative metadata
import_mediablendduck:writeImport a public media URL into tenant-owned storage
get_analyticsblendduck:readCompare normalized metrics with filters, freshness, and content attribution
get_inboxblendduck:readRead a filtered Social Inbox queue and sync health without sending or moderating
list_approvalsblendduck:readList visible approval cycles and allowed actions
manage_approvalblendduck:writeSubmit or decide an approval with server-side authorization

OAuth consent binds the connection to exactly one organization. Tools infer that organization from the access token, never expose tenant selection, and recheck membership on every call. Tool metadata distinguishes read-only, external-write, destructive, and non-idempotent operations so MCP clients can ask for the right approval.

Post, recovery, rescheduling, and bulk commands require a stable requestId. duplicate_post, import_media, and manage_approval are explicitly non-idempotent and should not be automatically repeated after an ambiguous response. allowDuplicate: true is reserved for an intentional repeat inside the configured content-deduplication window.

Optional OpenAPI categories

The 21 task-oriented tools remain the default. Resource-oriented agents may authorize only the stable v1 categories they need:

CategoryOAuth scopeDerived tools
Channelsblendduck:tools:channels3
Postsblendduck:tools:posts5
Mediablendduck:tools:media2 derived + 3 secure upload
Providersblendduck:tools:providers2
Webhooksblendduck:tools:webhooks8

This example adds only the two provider resource tools:

codex mcp login blendduck \
  --scopes openid,profile,email,offline_access,blendduck:read,blendduck:tools:providers

Generated tools use names such as api_list_providers and api_update_post. Their input and structured { data, meta } output schemas come from the reviewed OpenAPI contract; their execution still calls the same audited application services as REST and the dashboard. Category scope does not replace blendduck:read or blendduck:write. Public REST derives the organization from its API key; OAuth MCP derives the same boundary from the organization selected during consent.

Credential management, session-only setup, one-time webhook secrets, and multipart file bytes are excluded. Local media upload uses a separate secure browser session so an agent never needs to embed file bytes or receive storage credentials.

Upload a local file for an agent

Local-file hand-off is opt-in and needs the Media category plus both base scopes:

codex mcp login blendduck \
  --scopes openid,profile,email,offline_access,blendduck:read,blendduck:write,blendduck:tools:media
  1. Call create_media_upload_session and show its browserUrl to the person. Keep the returned session.id for polling.
  2. The same signed-in user opens the 15-minute link and chooses one image or video. BlendDuck uploads, reads back, and inspects the bytes in the original workspace.
  3. Call get_media_upload_session until state is completed.
  4. Call attach_uploaded_media with that session ID, the logical postId, and a stable requestId.

The database stores only a digest of the browser capability, which expires after 15 minutes even when the upload has completed. The separate non-secret session ID remains available for agent polling. Another member, another workspace, an expired link, or a foreign media URL cannot complete the session. Attachment uses the normal media preflight, content-approval edit rules, audit trail, atomic session claim, and idempotent multi-target post update; a session cannot be redirected to a second post.

Checked first calls

After consent, call list_channels; the selected organization is already bound to the connection. To verify write access without an external publish, call create_post with one returned channel, mode: "draft", and a stable requestId. The response shape is:

{
  "mode": "draft",
  "posts": [
    {
      "postId": "<target-id>",
      "aggregateId": "<post-id>",
      "integration": "<channel-id>"
    }
  ]
}

The repository quickstart verifier performs discovery, dynamic client registration, S256 PKCE, signed consent, token exchange, unauthenticated challenge, MCP initialization, tool listing, organization-bound channel reads, an idempotently replayed draft write, and a real local PNG browser hand-off through all three secure Media tools against a fresh local server.

On this page