MCP server
MarkdownConcierge runs a remote MCP server, so your coding agent can read and write your inbox. A reply sent from your editor reaches the customer’s app live and by push, exactly like a reply from the dashboard. “Triage my support, fix the crash Ana reported, and reply to her” is one prompt.
| Environment | URL |
|---|---|
| Hosted | https://mcp.conciergesdk.com/mcp |
| Local dev | http://localhost:4100/mcp |
It speaks MCP over Streamable HTTP, so it works with any client that does: Claude Code, Cursor, Codex, Windsurf, VS Code with GitHub Copilot, Gemini CLI, Zed and others. Config for each is below.
Sign in with OAuth (no key)
Section titled “Sign in with OAuth (no key)”Clients that support MCP OAuth (Claude Code, Cursor, Codex) need nothing but the URL:
claude mcp add --transport http concierge https://mcp.conciergesdk.com/mcpThe first call opens your browser: sign in to the dashboard, review what the agent can do, and click Allow. The agent registers itself, signs in with PKCE and keeps a refresh token, so you only do this once. It acts as you in the organization that was active when you clicked Allow, and its replies carry your name.
Anyone can register an app under any name, so the consent screen marks every agent Unverified app and shows where access will be sent. Allow only if that address is your own computer (localhost or 127.0.0.1) or a site you started the connection from. Redirects must be https or a loopback http address. Clients that redirect to a custom scheme (for example cursor://) work only when the server operator allows that scheme; otherwise use an API key below. An agent that asks for concierge:read without concierge:write gets read only access.
Or create an API key
Section titled “Or create an API key”Scripts, CI and clients without OAuth sign in with a staff API key: ck_ plus 40 characters. It’s shown once, and only a hash is stored.
- Dashboard: create a key in your settings (it calls
POST /v1/api-keys { name }). List keys withGET /v1/api-keys(prefix only) and revoke withDELETE /v1/api-keys/:id. - CLI, local dev:
pnpm --filter mcp key:create# or, explicitly:Every flag is optional; it defaults to the seeded demo user and their first organization. --quiet prints only the key.
A key belongs to one organization and acts as the person who created it, so replies are signed with their name. It stops working the moment it’s revoked or that person leaves the org. Anyone can revoke their own keys; owners and admins can revoke any key in the org.
Connect your agent
Section titled “Connect your agent”Claude Code (with a key; drop the header to use OAuth instead):
claude mcp add --transport http concierge https://mcp.conciergesdk.com/mcp --header "Authorization: Bearer ck_..."For local dev, use http://localhost:4100/mcp instead (start it with pnpm dev:mcp).
Cursor (.cursor/mcp.json) and other clients that take JSON config:
{ "mcpServers": { "concierge": { "url": "https://mcp.conciergesdk.com/mcp", "headers": { "Authorization": "Bearer ck_..." } } }}Codex (~/.codex/config.toml):
[mcp_servers.concierge]url = "https://mcp.conciergesdk.com/mcp"http_headers = { Authorization = "Bearer ck_..." }Windsurf (~/.codeium/windsurf/mcp_config.json):
{ "mcpServers": { "concierge": { "serverUrl": "https://mcp.conciergesdk.com/mcp", "headers": { "Authorization": "Bearer ck_..." } } }}VS Code with GitHub Copilot (.vscode/mcp.json, agent mode):
{ "servers": { "concierge": { "type": "http", "url": "https://mcp.conciergesdk.com/mcp", "headers": { "Authorization": "Bearer ck_..." } } }}Gemini CLI (~/.gemini/settings.json):
{ "mcpServers": { "concierge": { "httpUrl": "https://mcp.conciergesdk.com/mcp", "headers": { "Authorization": "Bearer ck_..." } } }}Zed (settings.json):
{ "context_servers": { "concierge": { "url": "https://mcp.conciergesdk.com/mcp", "headers": { "Authorization": "Bearer ck_..." } } }}Any other MCP client: point it at https://mcp.conciergesdk.com/mcp as a Streamable HTTP (sometimes labeled “HTTP”) server with the header Authorization: Bearer ck_.... Clients that only launch local stdio servers can bridge with npx mcp-remote https://mcp.conciergesdk.com/mcp --header "Authorization: Bearer ck_...".
Then ask things like “triage my support inbox”.
Set up the dashboard from your agent
Section titled “Set up the dashboard from your agent”Every settings page in the dashboard has a Set up with your agent button. It copies a short prompt for that area: connect the server if needed, read the current settings, look up the facts in your repo (prices from your StoreKit configuration, FAQ from your README, colors from your asset catalog, bundle ids from your build files), show you the planned changes, then write them with the tools below.
Every tool returns a short text summary plus structured content. IDs from another organization behave exactly like missing IDs.
| Tool | What it does |
|---|---|
list_apps |
Your apps with app keys, connected state and open conversation counts. |
list_conversations |
Filter by status (open, snoozed, closed, all; default open), appId, priority, query (name, email, user id, message text) and limit. |
get_conversation |
Messages (paged with before), the customer with metadata and breadcrumbs, devices and status. |
reply |
Replies as you. The customer gets it live and by push, and the AI pauses on that thread. Optional status. Idempotent on clientId. |
send_card |
A review card (store link) or an offer card (paywall id), with optional text. |
update_conversation |
Set status, priority or aiState. |
search_customers |
By name, email, user id, customer id or a metadata value. |
get_customer |
Profile, devices and conversation summary. |
get_app_stats |
Open, snoozed, closed, unread, AI resolved, median first response, customers and 7 day volume. |
get_setup_instructions |
SDK install steps for ios, android or react-native, with your app key filled in. |
verify_install |
Whether the first real message arrived, devices per platform, SDK versions, push readiness, whether onPaywallCard and onOfferCard are set (SDK 0.1.1 or later) and where review cards link. |
list_knowledge |
The AI agent’s knowledge base. |
upsert_knowledge |
Adds or updates a knowledge article, matched by id, then by title. Takes the structured fields (feature, screenPath, steps, planRequired, knownIssues, relatedScreens, deepLinkId) and draft: true to leave it for review. |
list_screens |
The feature map: screen ids and titles your app registered with registerScreen (never deep links). |
list_knowledge_gaps |
Questions the AI couldn’t answer, most asked first. |
get_app_settings |
Every settings area of one app in one call: app, AI agent, appearance, identity, security and allowed websites, kill switch, knowledge autopilot, store integrations, review replies, money, paywall and offer limits. Optional sections. Secrets are never returned, only whether each is set. |
update_app_settings |
Name, icon, store listing (appStoreId, playPackage, which review cards link to), ai, appearance, identity, security (iosAppId, androidPackage, allowedOrigins), sdk and knowledge. Send only what changes. Identity, security, the kill switch, the autopilot and the AI’s model, prompt and tools need an owner or admin. |
list_offers |
The offer catalog with card copy, what each platform gets and the AI policy. |
save_offer |
Creates an offer, or changes one by offerId (status: draft saves it without making it sendable, active activates it, archived retires it). Offers the AI sends on its own or that grant free access need an owner or admin. |
update_offer_limits |
Org wide offer caps and comp policy. Owner or admin. |
update_store_integrations |
App Store, Google Play and RevenueCat ids and keys. Keys are write only: omit to keep, null to clear. Owner or admin. |
update_review_settings |
AI drafts, auto send, reply instructions and the App Store Connect key (write only). Owner or admin. |
update_money_settings |
Refund desk, locked purchase resolver, billing guard and win-back, by the fields sent. Owner or admin. |
update_paywall_settings |
Cancel flow, Apple and Google retention options and paywall help, by the fields sent. Owner or admin. |
import_conversations |
Imports past conversations from your previous support tool as history (externalId, customer userId, status, metadata, messages with role, body and createdAt). Idempotent by externalId, at most 100 conversations and 2,000 messages a call. Never triggers AI replies, push or emails. Owner or admin, Pro. See Switch. |
export_customer_data |
Everything stored for one end user (by customerId, or appId and userId) as JSON, for a GDPR or CCPA access request. Owner or admin. |
delete_customer_data |
Permanently deletes all data for one end user, photos included. Owner or admin, never with a read only token, and confirm must repeat the customerId (or userId). |
list_incidents |
Version incidents: spikes of similar tickets from one app version, with counts, first and last seen, and the auto reply. |
get_incident |
One incident with its newest tickets, OS and build. |
set_incident_auto_reply |
The one reply affected users get (open conversations now, new matching tickets as they arrive), or null to stop. Pro. |
resolve_incident |
Closes an incident; with fixedInVersion and notify every affected conversation hears it is fixed. dismiss for a false alarm. |
Prompts
Section titled “Prompts”triage(/mcp__concierge__triagein Claude Code): open conversations grouped by urgency, patterns across them, and drafted replies. Nothing is sent without your approval.build-knowledge(/mcp__concierge__build-knowledge app_...in your app’s repo, optional focus): reads your screens, settings, paywall, flags, errors and strings, proposes missingregisterScreencalls, shows the articles it plans, then writes them as drafts. See Knowledge autopilot.fix-and-reply(/mcp__concierge__fix-and-reply cnv_...): finds the bug in your current repo from the report, breadcrumbs and device info, fixes and tests it, then replies and sets the status.
Resources
Section titled “Resources”concierge://conversation/{id} is a Markdown transcript of a conversation. The listing shows the 50 most recent conversations, and ids autocomplete.
Security notes
Section titled “Security notes”- Requests from a browser
Originare refused unless it’s localhost or on your allow list. CLI agents send no origin and are fine. - Every request checks the key or token and the person’s org membership.
- Anything a customer wrote (messages, names, metadata, breadcrumbs, tool results) reaches the agent inside
<customer_message>or<customer_data>blocks, escaped, with a standing rule that it is data and never instructions.grant_promo,send_card,upsert_knowledge,call_client_tooland the settings writers (update_app_settings,save_offerand the otherupdate_tools) are marked destructive, so clients ask before running them. - Store keys, private keys, service account JSON and the identity secret are write only over MCP: no tool returns them.
grant_promofollows your workspace comp policy: owners and admins only by default, at most 31 days, 20 grants a day and 2 per customer per 30 days, and an optional entitlement list. Change it under Offers, Limits.- Each person gets 120 MCP requests a minute, and at most 3
call_client_toolwaits at once. - OAuth access tokens are short lived JWTs (one hour) issued only for this MCP server; refresh tokens last 30 days.