Reference · MCP
MCP connector
Endpoint
POST https://app.greenfinch.ai/api/v1/mcp| Plan and scope | Enterprise; a key with the mcp scope, or a per-user connection |
| Transport | Streamable HTTP. Stateless: no session ID, every request is authenticated on its own |
| Protocol versions | 2026-07-28 (newest), 2025-06-18, 2025-03-26 |
| Requests | One JSON-RPC request per POST (batches are refused) |
| Responses | JSON (application/json) |
| Rate limit | 300 requests per minute per key, shared with the REST API |
- Version negotiation.
initializeechoes theprotocolVersionyou ask for when it is supported; otherwise it answers with the newest supported version that is not newer than yours. Clients on the 2026-07-28 revision can callserver/discoverinstead. - Event stream. A
GETto the same URL opens a server-sent-events stream. Greenfinch never pushes messages — every tool answers in its POST response — so the stream only carries keep-alive comments and closes after about 55 minutes. Clients that require it reconnect automatically; scripts can ignore it. - Methods.
initialize,server/discover,ping,tools/list,tools/call,prompts/listandprompts/get. Notifications such asnotifications/initializedare accepted with202and no body. - Caching.
tools/listandprompts/listincludettlMs: 3600000; the tool list only changes when Greenfinch releases. - Prompts.
prompts/listreturns ready-made multi-step plans (for example, building a prospect list for a county) that assistants can offer as shortcuts.
Connect an AI assistant
Claude, ChatGPT and other assistants with connectors
Assistants that support remote MCP connectors add Greenfinch by URL. Enter https://app.greenfinch.ai/api/v1/mcp as the connector URL. Where the assistant supports MCP sign-in, each member connects with their own Greenfinch account and the assistant acts as that member — see per-user connections. Menu names differ between assistants and change often; look for “connectors” or “custom MCP server” in its settings.
Clients configured with a file
Developer tools and agent frameworks that let you set request headers can use an organization key directly. A typical server entry (field names vary slightly by client):
{
"mcpServers": {
"greenfinch": {
"type": "http",
"url": "https://app.greenfinch.ai/api/v1/mcp",
"headers": {
"Authorization": "Bearer ${GREENFINCH_API_KEY}"
}
}
}
}An organization key acts for the whole organization
A key with mcp can reveal contacts, spend credits and change the pipeline for your entire organization. Give it to trusted automation only, and set daily limits for it on the Integrations page. For people, prefer per-user connections.
Call it from code
No MCP library is required. Send a JSON-RPC request with your key; the answer is in the response body.
curl -X POST "https://app.greenfinch.ai/api/v1/mcp" \
-H "Authorization: Bearer $GREENFINCH_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "greenfinch_browse_contacts",
"arguments": {
"employerText": "Lakeside Property Services",
"titleText": "facilities",
"limit": 10
}
}
}'{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{\n \"contacts\": [ … ],\n \"total_matching\": 1\n}"
}
],
"structuredContent": {
"contacts": [
{
"contact_id": "3f2a9c1e-0000-4000-8000-000000000041",
"title": "Director of Facilities",
"role_type": "facilities_operations",
"seniority": "director",
"employer_name": "Lakeside Property Services",
"property_count_in_territory": 6,
"revealed": false,
"email_validated": true,
"has_phone": true
}
],
"total_matching": 1
}
}
}structuredContentis the result the tool returns, as JSON — parse this.content[0].textcarries the same data as text (sometimes after a one-line summary), for assistants that only read text.- Unrevealed contacts are listed without personal details. Reveal one with
greenfinch_reveal_contact.
Official MCP SDKs work too: point a Streamable HTTP client transport at the endpoint and add the Authorization header.
Errors and refusals
A call can fail at three levels, and each looks different:
| Level | Looks like | Examples |
|---|---|---|
| Access | An HTTP error status and the REST error body — no JSON-RPC envelope | 401 bad key, 403 SCOPE_NOT_GRANTED or UPGRADE_REQUIRED, 429 rate limited |
| Protocol | HTTP 200 with a JSON-RPC error | -32700 invalid JSON, -32601 unknown method, -32602 unknown tool or invalid arguments (error.data.issues lists them), -32603 internal error |
| Tool refusal | HTTP 200, a normal result with isError: true | INSUFFICIENT_CREDITS, OUT_OF_TERRITORY, DAILY_CAP_EXCEEDED, NOT_FOUND |
A refusal is a business answer the caller can act on, so it arrives as a successful JSON-RPC response. Its structuredContent always has a machine code and a message, plus any detail; the text content starts with CODE: message so text-only clients see the code too.
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"content": [
{
"type": "text",
"text": "INSUFFICIENT_CREDITS: Insufficient credits\n\n{ \"code\": \"INSUFFICIENT_CREDITS\", … }"
}
],
"isError": true,
"structuredContent": {
"code": "INSUFFICIENT_CREDITS",
"message": "Insufficient credits",
"required": 10,
"available": 4
}
}
}{
"jsonrpc": "2.0",
"id": 8,
"error": {
"code": -32602,
"message": "Unknown tool: \"greenfinch_search_property\". Did you mean: greenfinch_search_properties?"
}
}Refusals that apply to every tool
On a per-user connection, these checks run before any tool, mirroring what the member could do in the app:
| Code | Meaning |
|---|---|
NO_ACTIVE_SEAT | The member has no active seat, so the assistant cannot use Greenfinch at all. |
ROLE_NOT_PERMITTED | The member's role is read-only and the tool writes or spends. |
IDENTITY_UNRESOLVED | The member's account could not be resolved. Retry shortly. |
Organization keys skip these, but tools that must be attributed to a person (for example greenfinch_add_note) refuse keys with ACTING_USER_REQUIRED. Every other code is listed on each tool in the tool reference and explained on Limits and errors.
Tool markers
The tool reference labels every tool so you can tell, before calling it, what it will do.tools/list carries the first of these as the standard readOnlyHint annotation.
| Marker | Meaning |
|---|---|
| Read-only | Reads data only. Safe to call freely. |
| Writes | Changes something in your workspace, or discloses personal data. A read-only member's assistant cannot call it. |
| Costs credits | Can spend credits. Each card says how much and when it is free. |
| Uses a daily limit | Draws down a daily limit: contact reveals, lead exports or agent pipeline changes. |
| Needs a per-user connection | Refuses organization keys; it needs a per-user connection. |
| Needs an extra scope | Needs an extra scope on the connection, such as pipeline:transitions_full. |
Territory and plan always apply
Every tool only sees properties inside your organization's service area (or, on a per-user connection, the member's assigned territory). Asking for something outside it returns OUT_OF_TERRITORY with the county and the reason, never silently empty results.