- How do I connect Antfly to n8n?
- How do I give an n8n AI Agent grounded retrieval over my own documents?
- How do I use the MCP Client Tool node with Antfly Cloud?
- Why does my n8n agent's Antfly query fail with
invalid query request?
The Result
An n8n AI Agent answers chat messages from your Antfly table. n8n keeps owning the parts around the answer (the trigger, the ticket it opens, the CRM row it updates) and Antfly supplies what the agent knows, as one more tool on the canvas.
There is no application code in this setup. Nothing normalizes a malformed tool call or retries a bad query shape, so the discipline the retrieval needs lives in the agent's system message, written out in full; step 3 gives you that message.
Before You Start
An Antfly Cloud instance with an indexed table (the examples use docs with an embeddings index docs_vectors and a text field text) and an n8n workspace. Step 1 confirms the instance answers over MCP before n8n is involved.
Build It
1. Create a Read-Only Instance Key
In the Antfly Cloud console, create an API key on the instance n8n should read, with key type read only. Copy it when it is shown; it is displayed once. Cloud keys carry an antflydb_ prefix.
The key type decides what the agent can do. A read-only key makes the instance filter its own tool list: the agent is offered the read tools (query, get_document, describe_table, list_indexes, describe_indexes, sample_documents, describe_query_request, describe_mcp_capabilities, and list_tables on an unscoped key) and never sees batch, create_table, or drop_index. The agent cannot write to your data: the tools to do it are never sent to it, and the instance re-checks the key's permissions before dispatching any call it does receive.
Your MCP endpoint is your instance id dropped into the hosted path. Confirm the pair works before opening n8n:
curl -X POST https://platform.antfly.io/cloud/v1/inst_abc123/mcp/v1 \
-H "Authorization: Bearer antflydb_your_key_here" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {"name": "n8n-setup-check", "version": "1.0"}
}
}'
A good response carries an Mcp-Session-Id header and the server's capabilities. A 401 means the key is missing or malformed. A 403 means the key belongs to a different instance than the one in the URL, or the request carried an Origin header: hosted MCP is for backends like n8n, never for browser code.
2. Add the MCP Client Tool Node
The workflow is three nodes and a trigger:
When chat message received -> AI Agent
|-- Chat Model
`-- MCP Client Tool
Add When chat message received and connect it to an AI Agent. Connect any chat model to the agent; retrieval does not depend on which one. Attach an MCP Client Tool to the agent's Tool input:
- MCP URL: your instance endpoint from step 1, ending in
/mcp/v1. - Authentication: Bearer Auth, with a credential holding the token only. n8n adds the
Authorization: Bearerheader itself. - Tools to Include: Selected, exposing only
queryandget_document.
Run the MCP node on its own before touching the agent. It should list the two tools. A connection problem is far easier to read here, where one node fails alone, than out of an agent execution trace later.
3. Give the Agent the Query Vocabulary
Paste this into the AI Agent's System Message. It pins the exact tool-call shape so the model has nothing to improvise:
You are a documentation support agent. Answer only from evidence returned by the
Antfly MCP `query` tool. Begin with a direct answer and cite a documentation title
beside each major claim.
For every substantive question, start with exactly one `query` call against table
`docs`. The tool input must have exactly two outer properties: `tableName` and
`queryRequest`. `queryRequest` must be a JSON object, never a quoted string, and
never combined with shorthand arguments. Do not put `table` inside `queryRequest`.
For broad questions (definitions, overviews, architecture, "when do I use") send
one expanded semantic query:
{
"tableName": "docs",
"queryRequest": {
"semantic_search": "EXPANDED CONCEPTUAL QUESTION",
"indexes": ["docs_vectors"],
"hierarchy": {},
"limit": 5
}
}
For exact terms (API paths, error strings, flags, field names, commands) combine
full-text and semantic search and fuse them:
{
"tableName": "docs",
"queryRequest": {
"full_text_search": {"match": "RELEVANT KEYWORDS", "field": "text"},
"semantic_search": "EXPANDED VERSION OF THE QUESTION",
"indexes": ["docs_vectors"],
"merge_config": {"strategy": "rrf"},
"hierarchy": {},
"limit": 5
}
}
Never request `_chunks.*` or broad source expansion. Never run queries in parallel.
If the first result has enough text, answer immediately; otherwise make at most one
focused fallback query. Never make more than two queries for one answer.
Build answers from returned text. Filenames, scores, and metadata without content
are not evidence. If retrieval succeeds but the evidence is thin, say what remains
unsupported instead of filling the gap from memory.
If a query times out, the connection closes, or the service returns an error, make
no further tool calls for that answer. Say that retrieval is temporarily
unavailable.
Use only read tools. Business actions such as opening a ticket are separate n8n
tools, not Antfly ones.
Replace docs, docs_vectors, and text with your own table, embeddings index, and text field. Two details carry weight: semantic_search is rejected with a 422 when indexes is missing, and hierarchy: {} asks for direct chunk-level matches rather than whole source documents.
Set the chat model temperature to 0 or 0.1 and the agent's maximum iterations between 4 and 6. That is tight enough to suppress speculative tool calls while allowing the one focused fallback.
4. Send a Message and Read the Trace
Open the chat panel and ask something your table can answer. Then open the execution and read the agent's tool calls, not just the prose.
A healthy execution makes one query call, gets chunks with real text in them, and cites pages that exist. Then check the negative case: ask it to create a table. It must decline, because no write tool was ever offered.
When a call comes back invalid query request, open the failed tool call and look at its actual input. The error will not say which property was wrong; the input will. It is nearly always queryRequest arriving as a quoted string, or shorthand arguments mixed in beside it.
Tradeoffs
When a tool call fails, the agent stops rather than retrying, and the system message is what enforces that.
In a coded integration a transport failure is something you catch. Here there is no catch block, and an agent's instinct on a failed tool call is to try again, differently: a second query, then a third, fanning out against an instance that is already unhealthy or a credential that was already rejected.
None of those retries can succeed. An expired key returns 401 every time. A closed MCP connection stays closed. What the retries do produce is a slow execution that ends in a confident answer written from the model's memory instead of your documents, which is worse than an error message. So the system message tells the agent to stop calling tools for the rest of that answer and report the outage.
When you diagnose one: if every client fails, it is an instance or gateway problem, not a prompt problem. If only n8n fails, recreate the Bearer credential, refresh the node connection, and run the MCP node alone again.
Use Agent Skills
Everything above is also encoded in the Antfly skill, so a coding agent can execute this guide for you:
npx skills add antflydb/antfly-skills
Then prompt it with the outcome, for example "Set up an n8n workflow that answers questions from my Antfly docs table over MCP", and use this page to judge the result.
Next Steps
- Build a Support Answer Agent: the same outcome with reranking and pruning, when you control the code
- Tune Hybrid Search: the fusion behind the exact-term query above
- Quickstart: create and index the table this workflow reads from