Docs · MCP

Connect Claude Code to Optic

Optic is an MCP server. Add it to Claude Code with one command and your API key, then ask Claude about your signals, approvals and follow-ups.

Updated 18 October 2026

Before you start

  • Claude Code, installed and signed in. claude --version should print a version.
  • An Optic API key. Keys start with opt_. There's no self-serve signup yet: during early access we create a key for each person, and you'll see it once.
  • Your workspace slugs. One workspace per product, such as acme. The list_workspaces tool tells you which ones your key can use.

Add the server

claude mcp add --transport http optic https://api.opticto.com/mcp \
  --header "Authorization: Bearer opt_..."
  • --transport http: Optic is a remote server over streamable HTTP. Nothing runs on your machine.
  • optic is the name Claude Code shows. If you hold keys for two accounts, add the server twice under different names, for example optic-acme and optic-northlight.
  • By default the server is added for the current project, for you only. Add --scope user to use it in every project.

Sharing the setup with a team

A project-scoped .mcp.json is meant to be committed, so never paste a key into it. Reference an environment variable instead, and give each person their own key:

{
  "mcpServers": {
    "optic": {
      "type": "http",
      "url": "https://api.opticto.com/mcp",
      "headers": { "Authorization": "Bearer ${OPTIC_API_KEY}" }
    }
  }
}

Check the connection

claude mcp list

optic should show as connected. Inside a Claude Code session, /mcp shows the server's status and its tools. Then ask:

List my Optic workspaces.

Claude calls list_workspaces and answers with each workspace and your role in it.

Things to ask

You askClaude calls
What do I owe replies on today in acme?digest
Any new signals above 0.7? Why did the top one score that high?list_signals
What's waiting for my approval?list_approvals
Dismiss that one, it's stock commentary.dismiss_signal

Tools

Every tool except list_workspaces takes a workspace slug. Results come back as JSON; signals include the reasons behind their score.

ToolParametersStatus
list_workspaces
Workspaces you can act in, with your role
noneBuilt
digest
Replies you owe, conversations gone cold, tasks and deal next steps due
workspaceBuilt
list_approvals
Drafts waiting for approval, with the person, company and triggering signal
workspace, limit = 20Built
list_signals
The signal feed, best score first, with the reasons behind each score
workspace, status = "new", min_score = 0.0, limit = 20Built
dismiss_signal
Mark a signal as not worth acting on
workspace, signal_idBuilt
approve
Approve a draft, with edits if needed; the original is kept for the edit-rate metric
workspace, message_id, body?, subject?Built
reject
Reject a draft so it never sends, with an optional reason
workspace, message_id, reason?Built
search
People or companies, filtered by text, tier, lifecycle, persona or status
workspace, kind = "person", q?, tier?, lifecycle?, persona?, status?, company_id?, limit = 25, offset = 0Built
get_record
One person or company with its timeline; a company also lists its people and signals
workspace, kind, record_id, timeline_limit = 50Built
list_plays
Every play with its version, status and mode, and how many people it's running on
workspaceBuilt
play_stats
Enrolled, contacted, replied, meetings, reply rate and edit rate per play, all time
workspace, play?Built
upsert_person / upsert_company
Create or update records, matched by email or domain
to be announcedPlanned
log
Add a note or task
to be announcedPlanned
move_deal
Change a deal's stage or next step
to be announcedPlanned
enroll / unenroll
Run a play on someone by hand
to be announcedPlanned

Permissions

Claude Code asks before it calls an MCP tool unless you've allowed it. The tools that only read are safe to allow. Leave approve and reject off the allow list so every approval and rejection asks you first.

{
  "permissions": {
    "allow": [
      "mcp__optic__list_workspaces",
      "mcp__optic__digest",
      "mcp__optic__list_approvals",
      "mcp__optic__list_signals",
      "mcp__optic__search",
      "mcp__optic__get_record",
      "mcp__optic__list_plays",
      "mcp__optic__play_stats"
    ]
  }
}

The same thing over REST

The REST API uses the same keys and returns the same data.

curl -H "Authorization: Bearer opt_..." https://api.opticto.com/v1/workspaces
Method and pathSame as
GET /v1/workspaceslist_workspaces
GET /v1/workspaces/{workspace}/digestdigest
GET /v1/workspaces/{workspace}/approvals?limit=20list_approvals
POST /v1/workspaces/{workspace}/approvals/{message_id}/approve with {"body"?, "subject"?}approve
POST /v1/workspaces/{workspace}/approvals/{message_id}/reject with {"reason"?}reject
GET /v1/workspaces/{workspace}/people?q=&persona=&tier=, /companies?q=&tier=search
GET /v1/workspaces/{workspace}/people/{id}, /companies/{id}get_record
GET /v1/workspaces/{workspace}/playslist_plays
GET /v1/workspaces/{workspace}/plays/stats?play=play_stats
GET /v1/workspaces/{workspace}/signals?status=new&min_score=0.7list_signals
POST /v1/workspaces/{workspace}/signals/{id}/dismissdismiss_signal
GET /healthNo key needed

Troubleshooting

"not authenticated" or HTTP 401
The header is missing or the key is wrong. It must be exactly Authorization: Bearer opt_....
A workspace isn't found
Check the slug with list_workspaces. Your key may be limited to a different workspace; a limit can narrow access but never widen it.
The server shows as failed in /mcp
Check that the URL ends in /mcp, then remove and re-add it: claude mcp remove optic.
A key leaked
Email hello@opticto.com and we'll revoke it. Revoking one key doesn't affect anyone else's.