Skip to content

MCP

Spotlight exposes its admin surface as a Model Context Protocol server, so AI agents (Claude Desktop, Claude Code, Cursor, ChatGPT with MCP, anything else that speaks MCP) can list, create, update, publish, and archive tours without bespoke per-host glue.

Two ways to use it:

  • Remotehttps://mcp.spotlight.help/mcp. OAuth (Dynamic Client Registration) for auth. Works from any device the user is signed into their MCP host on; no install. This is the recommended path.
  • Local stdiospotlight-mcp console script bundled with the backend Python package. Useful for dev / when an MCP host doesn't support remote OAuth connectors yet.
  1. Open Claude Desktop → Settings → Connectors → Add custom connector.
  2. Server URL: https://mcp.spotlight.help/mcp. Hit Connect.
  3. A browser tab opens to dashboard.spotlight.help/oauth/authorize. Sign in with Clerk if you're not already.
  4. The consent screen asks which tenant + project this integration is allowed to operate on. Pick them and click Allow.
  5. The browser bounces back to Claude Desktop's local callback ("Couldn't connect" briefly may show — that's just Claude Desktop intercepting the redirect). Claude Desktop swaps to Connected with the tool list visible.

Behind the scenes Spotlight mints a real sk_live_* API key for the chosen project and hands it back as the OAuth access token. The token IS the API key, so:

  • Revoking the integration = revoke the API key in Projects → <project> → API Keys. The MCP host loses access on its next call.
  • Audit log shows the same key prefix the integration uses, so you can trace which connector did what.

Connected-app keys are named mcp:<clerk-user-id>:<client-id>. If you see one of those on the API Keys page, it came from an OAuth-registered MCP host, not from manual minting.

Connecting via local stdio

bash
cd backend
uv pip install -e "."

The mcp package ships as a core dependency now — no opt-in extra needed. (Earlier drafts of this page documented [mcp]; ignore that, the install fails with "extra mcp not provided".)

Then in your MCP host config (~/Library/Application Support/Claude/claude_desktop_config.json for Claude Desktop, similar for others):

json
{
  "mcpServers": {
    "spotlight": {
      "command": "spotlight-mcp",
      "env": {
        "SPOTLIGHT_BASE_URL": "https://api.spotlight.help",
        "SPOTLIGHT_API_KEY": "sk_live_..."
      }
    }
  }
}

SPOTLIGHT_API_KEY is a project-scoped key minted manually from Projects → <project> → API Keys. No OAuth flow — the agent uses the key directly.

Tools

Tours — scope tours:read / tours:write

ToolArgsReturns
list_toursArray of tour summaries
get_tourtour_idFull tour incl. steps + triggers
create_tourtitle, description?, steps?, trigger?New tour, draft status
update_tourtour_id, optional title/description/steps/triggerUpdated tour
publish_tourtour_idTour, now published
archive_tourtour_idTour, now archived

Content (banners, modals, hotspots, spotlights, tooltips, checklists) — scope content:read / content:write

ToolArgsReturns
list_contentcontent_type? (filter)Array of content summaries
get_contentcontent_idFull content body
create_contentcontent_type, name, bodyNew content item, draft status
update_contentcontent_id, patchUpdated content
publish_contentcontent_idContent, now published
archive_contentcontent_idContent, now archived

content_type is one of banner, modal, hotspot, spotlight, tooltip, checklist. The wire format is unified under POST /v1/admin/content with the type as a discriminator field, which is why a single set of tools covers all six.

Themes — scope themes:read / themes:write

ToolArgsReturns
list_themesArray of themes
get_themetheme_idFull theme tokens
create_themename, tokens?New theme
update_themetheme_id, patchUpdated theme
set_default_themetheme_idThe new default
delete_themetheme_id{deleted: true}

tokens on create_theme is a CSS-custom-property map, e.g. {"--spot-bg": "#15151d", "--spot-primary": "#ff6a4d"}. Omit it to seed with the default Indigo palette and tweak via update_theme. delete_theme refuses to delete the current default (set another theme as default first) and shared built-in themes (read-only).

Pinpoint help inbox — scope pinpoint:read / pinpoint:write

ToolArgsReturns
list_help_requestsstatus_filter?, project_id?Inbox with unread count
get_help_requestrequest_idThread + replies
reply_help_requestrequest_id, body, attachments?Updated thread
set_help_request_statusrequest_id, new_status (open / awaiting_user / resolved)Updated thread

Projects — scope projects:read

ToolArgsReturns
list_projectsProjects visible to this token

Tool descriptions are written for agent consumption. When unsure of a payload shape, agents are told to call get_* on an existing record of the same kind to see a real example.

Scopes

OAuth-issued tokens carry an explicit scope list — picked at consent time on the dashboard's authorize page. Scope names follow <resource>:<action>:

ScopeWhat it grants
tours:readlist_tours, get_tour
tours:writecreate / update / publish / archive / copy
content:readlist_content, get_content (banners, modals, hotspots, spotlights, tooltips, checklists)
content:writecreate / update / publish / archive
themes:readlist_themes, get_theme
themes:writecreate / update / set-default
pinpoint:readhelp-inbox list + read
pinpoint:writereply + set-status
projects:readlist_projects (discovery)
admin:writeReserved for high-trust administrative actions. Implicit superset of every other scope.

Mutating tools return a missing_scope error naming the required scope, so an agent can ask the user to re-authorise with the right one. Dashboard-minted (non-OAuth) keys carry no explicit scope list and behave as full-access — preserving the historic "one key, full power" behaviour for server-side use.

Errors

Each tool returns either the API's response payload (success) or a structured error:

json
{
  "error": "spotlight_api_error",
  "status_code": 422,
  "request_id": "req_abc123",
  "detail": "{...full body...}"
}

request_id is what to grep CloudWatch with when something unexpected happens.

Spotlight