MCP server
Harvv runs a hosted Model Context Protocol server so AI coding agents (GitHub Copilot, Cursor, Claude, Windsurf, Zed, Lovable) can read your behavioral findings and install the pixel without leaving the editor. One endpoint, one bearer token, scoped to your account.
Endpoint
https://harvv.com/mcp
The aliases /mcp/lovable and /mcp/harvv resolve to
the same server. Point any MCP client at the base /mcp URL.
Connect your client
Every client uses the same standard MCP config: an HTTP server URL plus an
Authorization: Bearer header. Only the file or UI you paste it
into changes.
- VS Code / GitHub Copilot, Cursor, Claude Desktop, Windsurf, Zed, Copilot CLI: use the generated config at /install/copilot. It fills in your token and shows the right file per client.
- Lovable: open Connectors, pick Harvv from the catalog, and paste your token. Walkthrough at /install/lovable.
- A custom client or your own agent: see Transport below.
Authentication
- Generate a token at harvv.com/app (or right on /install/copilot). The raw token is shown once.
- Each token is scoped to one Harvv account. Every tool call filters to that account's sites and no one else's.
- Tokens do not expire. They stay valid until you revoke them from your dashboard. A 401 therefore means the token was revoked or is wrong, never that it "aged out". See Troubleshooting.
- Keep the token out of committed config. The VS Code flow uses an input prompt so the editor stores it for you.
Transport (custom clients)
The server speaks JSON-RPC 2.0 over Streamable HTTP (MCP spec 2025-03-26 and later). For a hand-rolled client:
- Method:
POSTtohttps://harvv.com/mcp - Headers:
Content-Type: application/json,Authorization: Bearer YOUR_TOKEN, andAccept: application/json, text/event-stream(the MCP SDK 1.25+ enforces the dual Accept value). - Lifecycle:
initialize, thentools/list, thentools/call.pingis supported.
curl -X POST https://harvv.com/mcp \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"list_my_sites","arguments":{}}}'
Tools
Five tools. The ones that act on a site take an optional site_id
and default to the first site on your account if you omit it. To get a real
site_id, call list_my_sites first.
list_my_sites (no arguments)
Lists every site on your account with id, name,
domain, and pixel_key. This is how you discover the
site_id the other tools accept.
install_pixel
Returns the Harvv install snippet plus framework-specific placement guidance.
site_id(optional): the site UUID or its 16-character pixel key. Omit for the first site.
This tool returns text and instructions only. It does not touch your filesystem. Your coding agent reads the snippet and writes it into the right file; the Harvv server never has access to your project.
check_install
Checks whether the pixel is firing on a public URL.
url(required): the published site URL. Must be http or https; localhost and private ranges are rejected.
Pass the real published URL (custom domain or *.lovable.app),
not the Lovable id-preview--*.lovable.app wrapper, which serves
Lovable chrome instead of your project HTML and will report not-installed.
get_friction_findings
Returns the top behavioral findings plus headline dead-click and rage-click counts.
site_id(optional): which site. Omit for the first site.days(optional): lookback window, 1 to 30, default 7. Out-of-range values are clamped and the response says so.
get_dashboard_url
Returns deep links into the Harvv dashboard for a site (overview, issues, install).
site_id(optional): which site. Omit for the first site.
Example: get_friction_findings
Request:
{"jsonrpc":"2.0","id":4,"method":"tools/call",
"params":{"name":"get_friction_findings","arguments":{"days":7}}}
The result is a content block whose text is JSON:
{
"ok": true,
"site": { "id": "c8d5fc24-...", "name": "Acme", "domain": "acme.com" },
"window": { "days": 7, "requested_days": 7, "clamped": false,
"min_days": 1, "max_days": 30 },
"headline": { "sessions": 1840, "events": 41230,
"dead_clicks": 212, "rage_clicks": 64,
"unit": "count", "window_days": 7 },
"findings": [
{ "id": "8231", "type": "dead_click",
"title": "Dead clicks on pricing CTA",
"element": "button.upgrade-cta", "priority": "high",
"summary": "212 clicks on a button with no handler ...",
"dashboard_url": "https://harvv.com/app/site/c8d5fc24-.../issue/8231" }
]
}
All headline counts are totals over the whole window, not
per-day averages. Findings come sorted high priority first.
Troubleshooting
token_revoked: regenerate at harvv.com/app and reconnect.token_not_found: mistyped, or from another account. Regenerate and reconnect.wrong_scope: not a customer MCP token. Generate one from your dashboard.
error.data.reason (JSON-RPC) and the
WWW-Authenticate response header.
inputSchema looks
like {"properties":{}}, it cached an older catalog from before
the site_id / url / days parameters
shipped. Remove and re-add the Harvv connector (or refresh the connection)
to re-fetch tools/list and pick up the current schemas.
list_my_sites genuinely takes no arguments, so an empty schema
there is correct.
check_install reports not-installed on a Lovable preview.
Use the published URL, not the id-preview--*.lovable.app wrapper
(see check_install above).