Ontraport MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Ontraport MCP Servershow me contacts with tag 'VIP'"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Ontraport MCP Server
A stateless Node.js service that implements the Model Context Protocol (MCP) to expose Ontraport CRM functionality as structured tools consumable by any MCP-compatible AI agent.
The server is a translation layer. It receives tool calls from AI agents, authenticates them against Ontraport API credentials, translates them into the appropriate Ontraport REST API calls, cleans the responses, and returns structured results. It contains no business logic of its own.
Table of Contents
Related MCP server: Attio MCP Server
Architecture
┌─────────────────┐ ┌──────────────────────────┐ ┌──────────────────┐
│ │ │ Ontraport MCP Server │ │ │
│ AI Agent │──────▶│ │──────▶│ Ontraport API │
│ (any MCP │ POST │ 1. Validate auth │ HTTP │ │
│ compatible) │ /v1 │ 2. Route JSON-RPC │ │ api.ontraport │
│ │◀──────│ 3. Translate to REST │◀──────│ .com/1/... │
│ │ │ 4. Clean response │ │ │
└─────────────────┘ └──────────────────────────┘ └──────────────────┘Key properties:
Built on the official MCP SDK — Uses
@modelcontextprotocol/sdkwithStreamableHTTPServerTransportfor protocol-compliant transport and session management.Stateless — No database, no persistent session storage, no caching. All state lives in Ontraport. In-memory sessions track only the MCP transport lifecycle.
Full MCP endpoint —
POST /v1for requests,GET /v1for SSE notification streams,DELETE /v1for session termination. PlusGET /v1/healthfor monitoring.Per-session isolation — Each agent connection gets its own
Server+Transportpair scoped to its credentials. No cross-session state leakage.Dynamic manifest — The tool list is generated fresh on every
tools/listcall by querying the Ontraport account's object metadata.Credential passthrough — The server forwards
Api-KeyandApi-Appidheaders directly to the Ontraport API. It never stores, caches, or logs credentials.
Getting Started
Prerequisites
Node.js 18+ (uses native
fetch)
Install & Run
npm install
npm startThe server starts on port 3000 by default. Set the PORT environment variable to change it.
Health Check
curl http://localhost:3000/v1/health
# {"status":"ok"}This endpoint requires no authentication and is intended for uptime monitoring.
Quick Test — Initialize
curl -X POST http://localhost:3000/v1 \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Api-Key: YOUR_API_KEY" \
-H "Api-Appid: YOUR_APP_ID" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","clientInfo":{"name":"test","version":"1.0"},"capabilities":{}}}'Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"serverInfo": { "name": "ontraport-mcp-server", "version": "1.0.0" },
"capabilities": { "tools": {} }
}
}Authentication
Every request to POST /v1 must include two HTTP headers:
Header | Type | Required | Description |
| string | Yes | The Ontraport account's API key, scoped to the desired permissions. |
| string | Yes | The Ontraport account's unique App ID. |
If either header is missing, the server responds with HTTP 401 before making any downstream calls.
The server passes these credentials directly to the Ontraport API on every call. Permission scoping is enforced by Ontraport's existing API key scope system — if a key lacks a required scope, the Ontraport API returns an error and the MCP server surfaces it cleanly.
How It Works
Request Lifecycle
Every request follows the same path:
Agent sends JSON-RPC request to POST /v1
↓
Express validates Api-Key + Api-Appid headers (401 if missing)
↓
Looks up or creates a session (Server + StreamableHTTPServerTransport pair)
↓
SDK handles JSON-RPC framing, protocol negotiation, and method routing:
• initialize → returns server info + capabilities (handled by SDK)
• tools/list → our handler builds dynamic manifest via /objects/meta
• tools/call → our handler dispatches to tool implementation
↓
Tool handler:
1. Validates input parameters
2. Constructs Ontraport API request
3. Executes via OntraportClient with provided credentials
4. Cleans response (strips noise fields)
5. Returns structured resultThe SDK's StreamableHTTPServerTransport handles the full MCP Streamable HTTP spec including session management (Mcp-Session-Id header), SSE streaming for server notifications (GET /v1), and session termination (DELETE /v1).
Dynamic Manifest Generation
Not all Ontraport accounts have the same objects. Customers can create custom objects, each with its own API endpoints and unique object type ID. Because of this, the tool manifest cannot be static.
When an agent calls tools/list, the server:
Calls
GET /objects/metaon the Ontraport API using the agent's credentialsIdentifies custom objects (anything not in the built-in object type ID list)
Generates 4 tool definitions per custom object (
get_,create_,update_,search_)Merges the 48 static tools with the dynamically generated custom object tools
Enforces the 100-tool manifest cap (see Manifest Size Guard)
Returns the complete tool list
The manifest is never cached. Every tools/list call triggers a fresh /objects/meta request so the manifest always reflects the current state of the account.
If the /objects/meta call fails (bad credentials, Ontraport outage), the server returns an MCP error — it never returns a partial manifest.
Tool Execution
When an agent calls tools/call, the server:
Looks up the tool name in the static handler registry
If not found, checks if the name matches a custom object pattern (
get_X,create_X,update_X,search_X)For custom object tools, calls
/objects/metato resolve the object's type ID dynamically — this meanstools/callworks independently of any priortools/listcallExecutes the handler, which translates the tool parameters into the appropriate Ontraport REST API call
Cleans the response and returns it in the MCP content format
This design is fully stateless — there is no global mutable state, no dependency between tools/list and tools/call, and concurrent requests from different accounts are safe.
Response Cleaning
Before returning Ontraport API responses to agents, the server strips fields that add noise without value:
system_sourcesource_locationimport_idbindexip_addy(deprecated)ip_addy_displaycontact_cat(deprecated)updateSequence(deprecated)updateCampaign(deprecated)account_id(the agent already knows which account it's connected to)
Cleaning is applied recursively to nested objects and arrays.
Project Structure
src/
├── index.js # Express app: auth, session management, HTTP routing
├── errors.js # Structured error builders (400–500 taxonomy)
├── mcp/
│ └── server.js # MCP Server factory: creates per-session Server instances
│ # with tools/list and tools/call handlers registered
├── manifest/
│ ├── static-tools.js # All 42 static tool definitions (single source of truth)
│ ├── custom-object-tools.js # Generates 4 tools per custom object
│ ├── builder.js # Merges static + dynamic tools, enforces 100-tool cap
│ └── builder-constants.js # Built-in object type IDs (shared constant)
├── ontraport/
│ ├── client.js # HTTP client for the Ontraport REST API
│ └── response-cleaner.js # Strips noise fields from API responses
└── tools/
├── registry.js # Tool name → handler dispatch (static + dynamic resolution)
├── contacts.js # 7 contact tools
├── tags.js # 6 tag tools
├── sequences.js # 4 sequence/campaign tools
├── tasks.js # 5 task tools
├── notes.js # 2 note tools
├── messages.js # 2 message tools
├── purchases.js # 5 purchase/order read tools
├── transactions.js # 13 transaction write tools
├── products.js # 2 product tools
├── custom-objects.js # Generic CRUD handlers for custom objects
└── metadata.js # 2 metadata/discovery tools
test/
├── health.test.js # Health endpoint
├── auth.test.js # Authentication validation (SDK transport)
├── mcp-server.test.js # MCP Server factory
├── error-handling.test.js # Error taxonomy
├── response-cleaner.test.js # Response cleaning
├── manifest.test.js # Manifest generation, cap, truncation
└── tools/
├── contacts.test.js
├── tags.test.js
├── sequences.test.js
├── tasks.test.js
├── notes.test.js
├── messages.test.js
├── purchases.test.js
├── transactions.test.js
├── products.test.js
├── custom-objects.test.js
└── metadata.test.jsDesign Principles
Single source of truth — All tool definitions (names, descriptions, input schemas) live in
static-tools.js. The manifest, input validation, and handler dispatch all derive from this one file.One pattern — Every tool handler follows the same shape: validate inputs, construct the Ontraport API call, execute it, return the result. Error handling is handled by the client and transport layers.
No abstraction without repetition — Each tool module is a flat set of exported async functions. No base classes, no middleware chains, no framework beyond Express and the MCP SDK.
Tool Reference
Contacts (7 tools)
Tool | Description | API Endpoint |
| Retrieve a single contact by ID or email. |
|
| Search contacts by conditions, tags, or free text. Paginated (max 50). |
|
| Create a new contact. Allows duplicate emails. |
|
| Find by email and update, or create if not found. Safest for agent use. |
|
| Update fields on an existing contact by ID. |
|
| Permanently delete a contact. Cannot be undone. |
|
| Get total matching contacts without returning records. |
|
Tags (6 tools)
Tool | Description | API Endpoint |
| Apply tags by name. Auto-creates tags that don't exist. |
|
| Remove tags by name. Silently ignores nonexistent tags. |
|
| Apply tags by ID. |
|
| Remove tags by ID. |
|
| Get contacts with a specific tag (by name or ID). |
|
| List all tags in the account. |
|
Sequences & Campaigns (4 tools)
Tool | Description | API Endpoint |
| Enroll contacts in sequences or campaigns. |
|
| Remove contacts from sequences or campaigns. |
|
| Pause all automation for a contact. |
|
| Resume paused automation. |
|
Tasks (5 tools)
Tool | Description | API Endpoint |
| Create and assign a task from a message template. |
|
| Mark tasks as completed with optional outcome. |
|
| Cancel tasks (status 2, no longer actionable). |
|
| Update assignee, due date, or status. |
|
| Retrieve tasks with optional filtering. |
|
Notes (2 tools)
Tool | Description | API Endpoint |
| Create a note attached to a contact record. |
|
| Retrieve notes, optionally filtered by contact. |
|
Messages (2 tools)
Tool | Description | API Endpoint |
| List available email, SMS, and task messages. |
|
| Get a single message with full content. |
|
Purchases & Orders (5 tools)
Tool | Description | API Endpoint |
| Retrieve purchase records. |
|
| Retrieve purchase lifecycle logs. |
|
| Retrieve transaction/invoice records. |
|
| Retrieve order records (subscriptions, payment plans). |
|
| Retrieve active subscription records. |
|
Transactions Write (13 tools)
These tools modify financial records. Agents should confirm with the user before executing.
Tool | Description | API Endpoint |
| Charge a contact's card on file. Requires offer with products and a saved card ID. Does NOT accept new card details. |
|
| Record a transaction without charging (offline sales, cash, check). |
|
| Retrieve order details for a transaction (subscription schedule, next charge date). |
|
| Update an order's next charge date, amount, or other fields. |
|
| Cancel active subscriptions by deleting their order records. Stops all future charges. |
|
| Delete a single order record (subscription or payment plan schedule). |
|
| Escalate overdue transactions to collections status. |
|
| Refund through original payment gateway. Cannot be undone. |
|
| Void an unsettled transaction. |
|
| Write off unpaid transactions (bad debt). |
|
| Mark as manually paid (check, cash, wire, etc.). |
|
| Retry a declined/failed transaction. |
|
| Resend invoice email. |
|
Products (2 tools)
Tool | Description | API Endpoint |
| List all products in the account. |
|
| Get a single product by ID. |
|
Custom Objects (4 tools per object)
These tools are dynamically generated for each custom object discovered in the account via /objects/meta. The tool names include the object's name, and the object_type_id is automatically injected.
Pattern | Description | API Endpoint |
| Retrieve a record by ID. |
|
| Create a new record. |
|
| Update fields on an existing record. |
|
| Search by conditions, text, or tag. Paginated. |
|
Metadata & Discovery (2 tools)
Tool | Description | API Endpoint |
| Get field definitions for any object type. |
|
| Get record count for any object with optional filtering. |
|
Input Reference
Condition Parameter
The condition parameter is used across all search and list tools. It is a JSON-encoded string containing an array of criteria objects.
Single condition:
[{"field":{"field":"lastname"},"op":"=","value":{"value":"Smith"}}]Supported operators:
Operator | Description |
| Equal to. Works on text, numeric, and timestamp fields. |
| Greater than. Numeric and timestamp fields. |
| Less than. Numeric and timestamp fields. |
| Greater than or equal to. |
| Less than or equal to. |
| Value is in a list. Value format: |
| For list-type fields. Checks if an option is assigned. |
| For list-type fields. Checks if an option is not assigned. |
Compound conditions:
Insert "AND" or "OR" strings between criteria objects:
[{"field":{"field":"lastname"},"op":"=","value":{"value":"Smith"}}, "AND", {"field":{"field":"city"},"op":"=","value":{"value":"Austin"}}]Pagination
All list/search tools support pagination:
Parameter | Type | Default | Description |
| integer | 0 | Zero-based offset. |
| integer | 50 | Number of records to return. Maximum 50. |
| string | — | Field name to sort by. |
| string | — |
|
Timestamps
All date/time fields use Unix timestamps (seconds since January 1, 1970 00:00:00 UTC). Agents must convert human-readable dates to Unix timestamps before passing them to any tool.
List Selection Fields
Custom fields of the list selection type require option IDs wrapped with the */* delimiter:
"f1500": "*/*1*/*2*/*"Use get_object_meta to discover option IDs for list fields.
Error Handling
The server translates Ontraport API errors into structured responses that give agents enough information to decide whether to retry, fix inputs, or report to the user.
HTTP Code | Category | Agent Guidance |
200 | Success | Parse the |
400 | Bad Request | Do not retry. Fix malformed input parameters. |
401 | Unauthorized | Invalid or missing credentials. Do not retry without new credentials. |
403 | Forbidden | API key lacks the required scope. Report to the user. |
404 | Not Found | Object ID doesn't exist. Verify IDs before retrying. |
422 | Unprocessable | Field validation failed (e.g., invalid email format). Fix and retry. |
429 | Rate Limited | Back off and retry. Check |
500 | Server Error | Retry with exponential backoff (max 3 attempts). |
Error response format:
{
"code": 400,
"error": "bad_request",
"message": "id is required for update_contact."
}Manifest Size Guard
If an account has many custom objects, the manifest can exceed what fits in an LLM's context window. The server enforces a maximum of 100 tools:
All 48 static tools are always included
Custom objects are sorted by most recently modified
Custom object tools are included in groups of 4 (one complete object at a time) until the limit is reached
If truncated, a
_manifest_notetool is added telling the agent that additional objects exist and can be discovered viaget_object_meta
Rate Limiting
The server does not add its own rate limiting. It inherits Ontraport's limit of 180 API requests per minute per account transparently. When the limit is exceeded, the server returns HTTP 429 with the Retry-After header from Ontraport so the agent can back off appropriately.
Security
Credential passthrough —
Api-KeyandApi-Appidare forwarded to Ontraport on each call and never stored.Session credential binding — Sessions are bound to credentials via SHA-256 hash. Returning requests must present the same
Api-Key/Api-Appidthat created the session. Prevents session hijacking across accounts.Auth on all endpoints —
Api-KeyandApi-Appidheaders are validated on every request — POST, GET (SSE), and DELETE — not just session creation.Per-session isolation — Each agent connection gets its own
Serverinstance scoped to its credentials. No shared mutable state between sessions.Session TTL — Abandoned sessions are automatically cleaned up after 30 minutes of inactivity. A background sweep runs every 5 minutes to prevent memory leaks.
No logging of credentials — Error handlers log only
err.message, never full error objects that could contain credentials in stack traces.No persistence — The server has no database, no file storage. In-memory sessions track only the MCP transport lifecycle.
Scope enforcement — Permissions are enforced by Ontraport's existing API key scope system. If a key lacks a scope, the API call fails and the server surfaces the error.
Testing
npm testThe test suite includes 106 tests across 17 suites:
Suite | Coverage |
| Health endpoint returns 200, no auth required |
| Missing headers → 401, valid auth + SDK initialize → 200 |
| Server factory creates isolated per-credential instances |
| All error types, toJSON format, fromHttpStatus mapping |
| Strips all 10 noise fields, recursive cleaning, null handling |
| Static tools, custom objects, built-in ID exclusion, 100-tool cap, truncation at object boundaries, no internal field leaks, failure propagation |
| All 7 contact tools — correct endpoints, params, validation |
| All 6 tag tools — correct payloads, objectID injection |
| All 4 sequence tools — sub_type defaults, correct methods |
| All 5 task tools — correct body structure |
| Both note tools — objectID=12 injection |
| All 2 message tools — correct endpoints |
| All 5 purchase/order tools — correct endpoints |
| All 13 transaction write tools — correct methods and paths |
| Both product tools — correct endpoints |
| All 4 custom object operations — objectID injection, validation |
| Both metadata tools — parameter passthrough |
Configuration
Environment Variable | Default | Description |
|
| The port the server listens on. |
What Is Excluded from v1
The following are intentionally excluded and may be considered for future versions:
Feature | Reason |
Campaign Builder | High complexity, risk of account misconfiguration |
Forms | Low demand for agent use cases |
Webhooks | Push-based pattern, separate architecture |
Bulk Operations | Safety review needed for agentic blast radius |
Calendar Events | Keeping manifest focused on CRM and commerce |
Inbox / Conversations | Requires messaging infrastructure context |
Credit Card Management | Security-sensitive, needs confirmation flows |
processManual (new transactions) | Financial risk, complex offer/product construction |
Object Type ID Reference
Object | Type ID |
Contact | 0 |
Task | 1 |
Group | 3 |
Sequence | 5 |
Rule | 6 |
Message | 7 |
Note | 12 |
Tag | 14 |
Product | 16 |
Purchase | 17 |
Purchase History Log | 30 |
Open Order | 44 |
Transaction | 46 |
Order | 52 |
Tag Subscriber | 138 |
Campaign/Automation | 140 |
Custom objects have IDs assigned dynamically and are discovered via /objects/meta.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/landonray/Mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server