Getting started
MCP Server
Qualy runs a remote Model Context Protocol (MCP) server that lets AI agents work with your Qualy data through a curated set of tools. Connect a client such as Claude Desktop, Cursor, or Windsurf — or build your own agent — and it can look up contacts, create payment requests, search your data, and more, all scoped to your tenant.
Beta
The MCP server is new and in beta. The set of tools will grow over time, and tool names or inputs may still change while we iterate.
Endpoint
The server speaks the Streamable HTTP MCP transport at:
https://api.qualyhq.com/v1/mcp
Authenticate with a single header — your Qualy API key as a bearer token:
| Header | Value |
|---|---|
Authorization | Bearer <your-api-key> |
The tenant is encoded in the key, so MCP needs no X-TENANT-ID header. (Authorization: ApiKey <key> is also accepted, and if your client happens to send X-TENANT-ID it's cross-checked against the key.) Every tool call runs with the permissions of the API key's user and is scoped to its tenant.
Connect a client
Most MCP clients connect by adding an entry to their MCP configuration.
Clients with native remote MCP support
Cursor, Windsurf, and similar clients can point at the remote server directly:
{
"mcpServers": {
"qualy": {
"url": "https://api.qualyhq.com/v1/mcp",
"headers": {
"Authorization": "Bearer pk_prod_your-api-key"
}
}
}
}
Claude Desktop and stdio-only clients
Clients that only launch local (stdio) servers can bridge to the remote server with mcp-remote:
{
"mcpServers": {
"qualy": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://api.qualyhq.com/v1/mcp",
"--header",
"Authorization: Bearer pk_prod_your-api-key"
]
}
}
}
After saving the configuration and restarting your client, the Qualy tools appear in its tool list.
Other clients
Any MCP-compatible client connects the same way: point it at https://api.qualyhq.com/v1/mcp and set Authorization: Bearer <your-api-key>. ChatGPT, Claude.ai, Replit, Zed and others each have their own "add MCP server" / connectors screen — follow your client's MCP instructions (for example, Cursor's MCP install links). A hosted one-click Connect Qualy (OAuth) flow is on the roadmap.
Keep your key safe
Your MCP configuration stores the API key in plain text on your machine. Treat it like any other secret — see API key best practices.
Available tools
All tools are scoped to your tenant. Reads are safe to call freely; writes are rate-limited and de-duplicated.
Contacts
| Tool | What it does |
|---|---|
contact_list | List contacts (customers / leads / students), newest first; filter by email. |
contact_get | Get one contact by id or email. |
contact_create | Create a contact. Returns the existing contact if the email is already on file. |
contact_update | Update a contact's name, phone, or email. |
Payment intents
| Tool | What it does |
|---|---|
payment_intent_list | List payment requests; filter by contact or status. |
payment_intent_get | Get one payment intent, including its shareable payment link. |
payment_intent_create | Create a payment request for a contact. |
payment_intent_cancel | Cancel a payment intent. |
Transactions
| Tool | What it does |
|---|---|
transaction_list | List transactions (charges and refunds); filter by contact, payment intent, or status. |
transaction_get | Get one transaction by its id. |
Orders
| Tool | What it does |
|---|---|
order_list | List orders; filter by contact. |
order_get | Get one order by its id. |
Partnerships
| Tool | What it does |
|---|---|
partnership_list | List partnerships (agents / institutions / suppliers). |
partnership_get | Get one partnership by id, code, or name. |
partnership_create | Create a partnership. |
Search
| Tool | What it does |
|---|---|
search | Fuzzy search across contacts or partnerships by name, email, or keyword. |
What's not exposed
For safety, moving money — capturing charges and issuing refunds — is not available through MCP. Those operations still go through the API or the Dashboard. The MCP server is read-heavy with a few safe writes.
Smart references
Wherever a tool takes a contact or partnership, you can pass a natural identifier instead of a Mongo ObjectId — Qualy resolves it to the right record before the tool runs. An agent that only knows a student's email or a partner's name doesn't need to look up an id first. This is the same Smart references resolution the REST API uses, applied to the MCP tools' reference fields.
| Field | Accepts |
|---|---|
contact | a contact id, or the contact's email (case-insensitive) |
partnership | a partnership id, code, exact name, or a unique name prefix |
Examples
Get a contact by email instead of an id — contact_get:
{ "contact": "camila@example.com" }
Raise a payment request straight from the payer's email, with no lookup step — payment_intent_create:
{
"contact": "camila@example.com",
"currency": "AUD",
"items": [{ "name": "Tuition — Semester 1", "amount": 12000 }]
}
Fetch a partner by name (or its code) — partnership_get:
{ "partnership": "Sydney English College" }
The same contact resolution applies to the contact filter on payment_intent_list, transaction_list, and order_list.
When a reference is ambiguous
If a name or prefix matches more than one record, the tool returns an AGENT_TOOL_AMBIGUOUS_REFERENCE error listing the candidate records, so the agent can retry with something more specific (an exact name, the partnership code, or an id). If nothing matches, it returns AGENT_TOOL_REFERENCE_NOT_FOUND.
For automated flows, prefer stable identifiers — email, partnership code, or id — over name prefixes, which can drift into ambiguity as new records are added.
When to use MCP vs the API
The MCP server and the REST API run on the same platform, the same data, and the same API-key auth — they're two front doors to the same back office. Pick by how your integration is driven:
Use the MCP server when an AI assistant is your interface. A person or agent asks in natural language and the model decides which tools to call, in what order, with you approving anything that writes. It exposes a curated, tenant-scoped subset of the platform — ideal for the long tail of ad-hoc questions and tasks ("find this student, draft a plan, chase that invoice") without writing or maintaining integration code.
Use the REST API when you're building a programmatic integration. You get the full endpoint surface, deterministic control over every call, webhooks, idempotency keys, and conveniences like Smart references — sending a contact email, partnership code, or service name where an endpoint expects an ObjectId. (MCP tools accept Smart references too, so this isn't a reason to choose one over the other.)
Many teams use both — an assistant for day-to-day operators, the API for their own product surface. They never conflict: every call, from either door, runs through the same tenant scoping, permissions, and platform controls.
Build your own agent
To drive the server from your own agent, connect with any MCP-compatible client library. With the official TypeScript SDK:
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const transport = new StreamableHTTPClientTransport(
new URL('https://api.qualyhq.com/v1/mcp'),
{
requestInit: {
headers: {
Authorization: 'Bearer pk_prod_your-api-key',
},
},
},
);
const client = new Client({ name: 'my-agent', version: '1.0.0' });
await client.connect(transport);
// Discover the tools…
const { tools } = await client.listTools();
// …and call one.
const result = await client.callTool({
name: 'contact_list',
arguments: { limit: 5 },
});
console.log(result);
Behavior and limits
- Tenant scoping — every call runs against your tenant only; the tenant is taken from your credentials.
- Rate limits — calls are rate-limited per tool. Reads have a generous budget; writes are tighter. Exceeding a limit returns an
AGENT_TOOL_RATE_LIMITEDerror with a retry hint. - Idempotency — write tools (create / update / cancel) are idempotent: repeating the same call with the same input within 24 hours returns the original result instead of creating a duplicate.
- Structured errors — tool errors come back with a
codeandmessageso your agent can react — for example, retry on a rate limit or re-prompt on invalid input.