Skip to content
Fenn

MCP connector

Drive Fenn from Claude or ChatGPT.

Fenn ships a hosted MCP server with 15 tools. Add it as a custom connector and the whole product is available in conversation — ask “how visible is mydomain.com?” and your agent calls the tools and answers. It is enabled on every plan, including the free one, and read tools have no side effects at all.

What the connector does.

It exposes your visibility data and your fix pipeline as MCP tools, so an agent can read, reason and act without you opening a dashboard. Three things follow from that.

Ask in plain language

You never name a tool. The agent picks between visibility_report, keyword_gaps and the rest based on what you asked.

Reason across your data

Because read tools are free of side effects, an agent can chain a dozen calls to answer one question — engine by engine, prompt by prompt — without asking permission each time.

Act, behind a gate

It can draft the fix as a real diff. It cannot open the PR on its own: gated tools return pending_approval and wait for a person.

Tool surface

15 tools, three bands.

The band tells you what a tool can do to you before you call it. This is the whole permission model — there is nothing else to configure, and no setting that promotes a tool to a lower band.

Read

10 read tools

No side effects. Your agent can call these freely, in a loop, without asking you first.

ToolWhat it doesArgumentsReturns
visibility_reportThe whole picture for a domain: Visibility Score, Share of Voice, Average Position and Sentiment, per engine, over a date range.domain, range?, engines?Scores per engine + trend series
prompt_detailEverything about one tracked prompt: the raw answer each engine gave, who got cited, where you appeared, and how that moved.prompt_id, engines?, range?Per-engine answers, citations, position, sentiment
list_promptsEvery prompt currently tracked for a domain, with its latest result.domain, status?Prompt list with last-run summary
rank_checkClassic rank for a keyword alongside answer-engine presence, so you can see where the two disagree.domain, keyword, locale?Rank, AI Overview presence, citing engines
keyword_gapsPrompts and keywords where competitors are cited and you are not — ranked by how often the question gets asked.domain, competitors?, limit?Gap list with competitor citations
audit_issuesTechnical and content issues that suppress citation: thin answers, missing schema, throat-clearing intros, orphaned pages, slow LCP.domain, severity?, category?Issue list with severity, URL, evidence
backlinksReferring domains and the pages engines actually quote when they answer about you.domain, limit?Referring domains + cited-source overlap
suggest_fixesFor a given issue or gap, the concrete changes that would most likely earn the citation. Read-only — proposes, does not write.issue_id | gap_id, max_suggestions?Ranked suggestions with rationale
get_fix_promptThe exact prompt to hand your own coding agent if you would rather implement the fix yourself, in your own repo, on your own terms.fix_idReady-to-paste prompt + file targets
list_fix_tasksThe state of every fix: drafted, pending approval, PR open, merged, or measured.domain, status?Fix task list with PR links and status
Draft

3 draft tools

Changes what is tracked, or produces a draft artefact. Reversible from the dashboard, and every call is written to the audit log.

ToolWhat it doesArgumentsReturns
track_promptStart tracking a new prompt. Counts against the prompt allowance on your plan.domain, prompt, engines?prompt_id + first scheduled run
track_keywordAdd a keyword to rank tracking.domain, keyword, locale?keyword_id + first scheduled check
draft_fixTurn a suggestion into a real diff against your connected repo. Produces a branch and a patch — it does not push, open, or merge anything.fix_id | issue_id, repo, base_branch?fix_task_id + unified diff preview
Gated

2 gated tools

Never executes on call. Returns status: "pending_approval" plus an approval URL. A human approves in the dashboard before anything leaves the sandbox.

ToolWhat it doesArgumentsReturns
execute_fixOpen the pull request for a drafted fix. Returns pending_approval and stops; a human approves in the dashboard, and only then is the PR opened.fix_task_idstatus: "pending_approval" + approval_url
request_publishPublish a report or a content change to a connected CMS. Same rule: returns pending_approval and waits for a human.target, payload_refstatus: "pending_approval" + approval_url

Gated tools never execute on call.

Calling execute_fix or request_publish does not open a pull request or publish anything. It creates an approval request and returns:

{
  "status": "pending_approval",
  "approval_url": "https://app.fenn.sh/approvals/apr_7c31",
  "expires_in": "72h"
}

A human with a login approves it in the dashboard, and only then does the pull request open. There is no configuration flag that removes this step, for any plan, including agency.

Setup

Copy, paste, done.

Create an API key in your dashboard under Settings → API keys, then add the connector. Keys are scoped to a workspace; on the agency plan you can issue one key per client so each client’s agent sees only their data.

Claude — custom connector
Settings → Connectors → Add custom connector

  Name:  Fenn
  URL:   https://api.fenn.sh/api/aeo-engine/mcp
  Auth:  Bearer <your API key>

Then, in any chat:
  "Using Fenn, how visible is mydomain.com this week?"
ChatGPT — MCP server connector
Settings → Connectors → Create → MCP server

  Name:      Fenn
  Server URL: https://api.fenn.sh/api/aeo-engine/mcp
  Auth:      API key (paste the key from your dashboard)

Enable the connector in the composer, then ask your question
in plain language. No tool names required.
Any other MCP client — JSON config
{
  "mcpServers": {
    "fenn": {
      "type": "http",
      "url": "https://api.fenn.sh/api/aeo-engine/mcp",
      "headers": { "Authorization": "Bearer $FENN_API_KEY" }
    }
  }
}

Full API-key documentation, scopes and rotation policy live in the dashboard at https://app.fenn.sh/docs/api-keys. Never paste a key into a shared chat; issue a second key instead and revoke it when you are done.

Worked example

“How visible is mydomain.com?”

One question, in a normal chat. The agent chooses the tools; you never type a tool name. Here is the full round trip, from the question through to a drafted fix waiting on a human.

Transcript (illustrative figures)
you ▸ How visible is mydomain.com?

agent ▸ visibility_report({ domain: "mydomain.com", range: "7d" })

    Visibility Score      42.4%   (+3.1 pts vs previous 7d)
    Share of Voice        18.1%   (+2.4 pts)
    Average Position       2.8    (was 3.4)
    Sentiment             71% positive / 24% neutral / 5% negative

    Per engine
      ChatGPT              62%    Perplexity      54%
      Claude               47%    AI Overviews    38%
      Gemini               31%    Grok            22%

agent ▸ keyword_gaps({ domain: "mydomain.com", limit: 3 })

    3 prompts where competitors are cited and you are not.
    Top one: "best <category> for small teams" — cited on 5 of 6
    engines, you appear on 0.

agent ▸ Grok is your weakest engine at 22%, and the biggest single
        gap is one prompt cited on five engines where you are absent.
        Want me to run suggest_fixes on it?

you ▸ yes, and draft the fix

agent ▸ suggest_fixes({ gap_id: "gap_8f21" })
        draft_fix({ fix_id: "fix_2c90", repo: "acme/www" })

    Drafted. Branch aeo/answer-first-pricing-page, 2 files changed.
    Diff preview above. Nothing has been pushed.

    To open the pull request, call execute_fix — it will return
    pending_approval and wait for a human to approve at
    https://app.fenn.sh/approvals.

Note where it stops. The agent drafted a real diff and then handed control back. That is the boundary between the fix loop and anything actually changing in your repository.

The MCP server is on the free plan too.

One domain, five prompts, ten keywords, all ten read tools. Enough to point your agent at your own domain and find out what the engines say about you.