Guide
MCP for GTM: expose actions as tools first
Most GTM software is a UI first and an API second, and agents get whatever the API happens to expose. If you and your team already do your thinking in Claude, that order is backwards. The first interface worth building is a set of tools an agent can call, carrying the same rules any UI will enforce later.
This guide covers what MCP is, why a GTM MCP server should come before the screens, how to design tools that are safe to hand to a model, and what that looks like in practice.
What MCP is
The Model Context Protocol is an open protocol Anthropic published in November 2024 for connecting AI applications to outside systems. An MCP server exposes tools: named functions with typed parameters and a description the model reads. A client such as Claude Code or Claude Desktop connects to the server, lists its tools and calls them when a request needs one. Servers run locally over stdio or remotely over HTTP.
For GTM, the server sits in front of your records, signals and outreach queue. You ask in plain language, the model picks a tool, and the answer comes back as structured data instead of a screenshot of a dashboard. The model chooses tools by their names and descriptions, so tool design is product design.
Why tools before a UI
- Your operators are already in Claude. A separate app is one more tab to check.
- A UI built first collects logic agents can’t reach. Validation hidden in a form handler is validation an agent skips.
- Tools are cheap to change. You learn which actions matter before you design screens around them.
- The UI still comes. It calls the same functions, so it adds views, not rules.
This isn’t an argument against a UI. It’s an argument for building the layer underneath first.
Design principles
1. One service layer, every surface
MCP tools, the REST API, webhooks and the eventual UI should all call the same service functions. If a rule exists, it exists once. The test: nothing a UI button does should be impossible from a tool, and the reverse.
2. Name the workspace on every call
If one server covers several products or teams, every tool except the one that lists workspaces should take a workspace slug. The model has to say which product it means, and a wrong guess fails loudly instead of landing in another product’s pipeline.
3. Read tools first, writes behind approval
Ship reads before writes: the daily digest, the signal feed, the approval queue. They are useful on day one and can’t email anyone. When writes arrive, anything that reaches the outside world goes through a person. An agent can draft. A human approves. Then it sends.
4. Return the reasons, not just results
A signal with a score of 0.74 gives the model nothing to explain. A signal with its weight, account fit, persona fit and freshness lets the model say why it ranked first, and lets you disagree with one specific factor.
5. Make writes idempotent
Agents retry. Upsert people by email and companies by domain. Key inbound form submissions on the provider’s submission id. Dismissing a signal twice should leave it dismissed, not raise an error.
6. Scope keys narrowly
Each API key belongs to a user and can be limited to one workspace. A limit can narrow what the user reaches but never widen it. Store only a hash of each key, and give each person their own key so you can revoke one without touching the rest.
7. Let the database be the backstop
Tool code has bugs, so don’t rely on it alone. For each request, verify the key, open a transaction, switch to a role that can’t bypass row-level security (RLS), and set the caller’s user and workspace as transaction-local settings. A tool with a broken filter then still sees only the caller’s rows. The security page shows how Optic does this.
Optic’s tools and their status
Optic runs one MCP server for all products, at /mcp, authenticated with an API key as a bearer token. Every tool except list_workspaces takes a workspace slug.
| Tool | Status | What it does |
|---|---|---|
list_workspaces |
Built | Workspaces you can act in, with your role |
digest |
Built | Replies you owe, conversations gone cold, tasks and deal next steps due |
list_approvals |
Built | Drafts waiting for approval, with the person, company and triggering signal |
list_signals / dismiss_signal |
Built | The signal feed, with the reasons behind each score |
approve / reject |
Building next | approve accepts edits and keeps the original draft for the edit-rate metric |
search |
Building next | People, companies and deals with filters |
get_record |
Planned | One record with its timeline |
upsert_person / upsert_company |
Planned | Create or update records, matched by email or domain |
log |
Planned | Add a note or task |
move_deal |
Planned | Change a deal’s stage or next step |
enroll / unenroll |
Planned | Run a play on someone by hand |
play_stats |
Planned | Play performance for a period |
Prompts and the tools that answer them
This is what it means to run sales from Claude day to day. You ask; Claude picks the call.
| You ask | Claude calls |
|---|---|
| “Which workspaces can I use?” | list_workspaces() |
| “What do I owe replies on today in kumkuat?” | digest(workspace="kumkuat") |
| “Show new signals above 0.7” | list_signals(workspace=..., status="new", min_score=0.7) |
| “What’s waiting for my approval?” | list_approvals(workspace=..., limit=20) |
| “Dismiss that one, it’s stock commentary” | dismiss_signal(workspace=..., signal_id=...) |
| “CCOs at target accounts with no touch in 30 days” | search (building next) |
Because each signal carries its reasons, Claude can explain a ranking instead of reciting it. Here is one result from list_signals, trimmed. Both companies are made up.
{
"type": "m_and_a",
"company": "Halvard Industries",
"title": "Halvard completes acquisition of Tessaline Controls",
"score": 0.74,
"reasons": [
{"factor": "weight", "value": 0.9, "why": "m_and_a weight in the brain"},
{"factor": "account_fit", "value": 1.0, "why": "tier 'target'"},
{"factor": "persona_fit", "value": 1.0, "why": "not about a person"},
{"factor": "freshness", "value": 0.822, "why": "21 days window"}
]
}
The signal-based outbound guide explains where those factors come from.
Connecting Claude Code
Add the server once with your key:
claude mcp add --transport http optic https://api.optic.to/mcp --header "Authorization: Bearer opt_..."
Then ask Claude to list your workspaces to confirm the connection. If you hold keys for more than one account, add the server once per key under different names. The full steps are in Connect Claude Code.
Risks and mitigations
These are the risks that matter for Claude Code outbound, and what holds each one.
| Risk | Mitigation |
|---|---|
| Prompt injection from scraped content. A press release or headline can contain text aimed at a model. | Treat signals as data. Detection is rules, so scraped text can’t change what fires. Nothing sends until a person approves the full draft. |
| An agent approving its own work | Keep write tools such as approve off your Claude Code allowlist, so each call asks you first. |
| A key with too much reach | One key per person, limited to one workspace, stored as a hash, revocable on its own. |
| Retries creating duplicates | Idempotent writes, and one running play per person enforced in Postgres. |
| A tool bug exposing another workspace | RLS per workspace, plus composite foreign keys that stop a row pointing at another workspace’s record. |
| Not knowing what an agent did | An append-only event log of every signal, draft, approval, send and reply. |
Prompt injection deserves one more line. A drafting model reads coverage, so instructions buried in an article could shape a draft. That is one more reason the approval step isn’t optional.
Where Optic fits
Optic GTM is built this way: MCP first, with the REST API and the future web UI on the same service functions. The MCP server is built and live with five tools for reading and triage. approve, reject and search are next on the build plan, alongside drafting and sending. The rest of the tool list and the web UI are planned. More on the product page, and on why sends wait for a person in approval-first outreach.
If you want to run your GTM from Claude this way, you can ask for early access.