MCP
Fontana Knowledge Graph exposes agent retrieval as a first-party Model Context Protocol server on your tenant origin at /_kg-engine/mcp (Streamable HTTP). Agents explore through an evidence loop: search or open a chunk, read its position, section, entities and neighbours in the same payload, then hop to more chunks. Every answer contains only what the caller may read (Permissions). Enable the seeded Knowledge Graph connection on agents you assign namespaces to.
The engine resolves the caller's namespace allow-list from Convex on every call and fails closed: missing or unresolvable caller context returns an empty result with an explicit auth error, never a cross-namespace answer.
Tool catalog
Section titled “Tool catalog”| Tool | What it does |
|---|---|
kg_search |
Hybrid search (full-text, vector, graph expansion) fused with RRF; several namespaces fuse by rank. Returns capped chunk packages. Disabled and unreadable content is excluded. |
kg_open |
Open packages by exactly one of chunkKey, outlineKey (that section’s chunks), entityKey (chunks mentioning it), or fileId (the file’s chunks in order). |
kg_hop |
Typed hop onto related packages: next_chunk, prev_chunk, similar (from a chunkKey); mentions, rel, same_type (from an entityKey); outline_child, outline_parent, outline_siblings (from an outlineKey). |
kg_outline |
A file’s page index: sections in document order with outlineKey, title, depth, parent and pages. Paged with cursor / nextCursor; limit maxDepth for large files. |
kg_ontology |
Published TBox for a namespace (entity types, relation types, PATTERN endpoints). |
kg_entity_search |
Named-entity entry by text and/or vector similarity; returns type labels and mention evidence packages. |
kg_file_entities |
File-scoped entity inventory: all entities mentioned by the file’s chunks plus published entity types used in that file. Paginate with afterEntityKey when truncated. |
kg_file_triples |
File-scoped instance REL triples where both subject and object are mentioned in the file. |
kg_namespaces |
List Knowledge Graph namespaces the caller may read. |
kg_files |
Find files in one namespace. folderPrefix, name (a path glob), and pattern (a content regex) combine. Omit pattern to list a page (cursor / nextCursor). Each file includes namespace, path, and fileId. Hidden files stay out of the page. |
kg_file |
Read or query one file: namespace plus path or fileId. Omit format for size, mime, and status. A csv or tsv also returns columns. sql is one SELECT against table data. See Query a file. |
kg_cypher |
One read-only OpenCypher statement for an exact word, a figure, or a known path (at most 50 rows, 2 second limit). Return the file path and the chunk text. An entity name alone is not a citation. A misspelling is entity search, then a walk from the resolved name. |
Enable these tools on an agent with the Knowledge capability tile on the agent card.
Chunk packages
Section titled “Chunk packages”Every search, open, hop, and entity-search hit is a chunk package. Lists carry truncated and total when clipped at the requested cap.
| Field | Contents |
|---|---|
text |
The chunk text, plus contextHeader (the “Document › Heading › Subheading” trail) and citation (namespace/path › sections (pp.)) |
position |
chunkIndex, charStart / charEnd in the parsed text, page and line span, tokenCount, prevChunkKey, nextChunkKey |
outline |
The chunk’s page-index section: outlineKey, title, depth, order, and its ancestors, siblings and children |
mentions |
Entities the chunk mentions: key, name, type id and label, how it was found (method), and the quoted text |
relNeighbors |
Typed relations of those entities, when a file you may read states them |
dates |
The file’s documentDate, effective window and collections |
similarFiles |
Readable files similar to the chunk’s file, best first |
| Cap | Default | Hard max |
|---|---|---|
topK |
8 | 32 |
mentions |
8 | 24 |
rel |
8 | 24 |
ancestors |
6 | 12 |
siblings |
8 | 24 |
children |
8 | 24 |
similar |
4 | 16 |
Pass caps on the tool call to override defaults. Values over the hard max fail closed with an error. Optional tokenBudget omits or truncates chunk text. Files ingested before character offsets existed report trace.missingOffsets until they are reprocessed.
Hybrid search (kg_search)
Section titled “Hybrid search (kg_search)”kg_search runs one or more retrieval lanes and fuses results with reciprocal rank fusion (RRF):
| Parameter | Default | Purpose |
|---|---|---|
query |
(required) | Search text |
namespaces |
All allowed | Subset of the caller’s namespace allow-list |
lanes |
fulltext, vector, graph_expand |
Which lanes to run. co_annotation is opt-in and is not in the default. A failed lane soft-fails empty without aborting the whole search |
tokenBudget |
none | Estimated token cap on returned chunk text |
filters |
none | Collection, folder, temporal, and relation filters |
ranking.rrfK |
60 | RRF constant k |
ranking.laneWeights |
1 each | Per-lane multipliers on RRF contributions |
ranking.minScore |
none | Drop hits below this display score (0–1 scale) |
Across several namespaces, results interleave by rank within each namespace, not by raw score — scores from different corpora are not comparable. Multi-namespace search keeps per-namespace and per-lane soft-fail: empty the failed lane or namespace, continue others, never abort the agent turn.
When permissions or filters hide most of a namespace, the vector lane widens its candidate pool in rounds instead of returning fewer hits; trace.vectorWidening reports the final pool and whether its cap was reached.
Co-annotation lane
Section titled “Co-annotation lane”The assistant includes co_annotation in lanes when it wants chunks that mention two entities named in the question. That lane stays off unless the search asks for it. Studio search has no switch for it. People asking in chat do not set this argument.
The span linker runs only when co-annotation is on. It attaches a phrase in the question to a nearby entity when the published ontology did not already name it.
Grounding roles on the response label those entities from how often they are mentioned. The pipeline diagram stays the ingest stages in Processing lanes.
When the lane runs, the response includes grounding, one entry per namespace. Each entry lists the grounded entities with their roles, the chosen pair, directCount (chunks that mention both entities), and bridgeCount (chunks one relation away). When the lane cannot form that evidence, the entry carries a reason such as too_few_bridges.
Open, hop, ontology, entities
Section titled “Open, hop, ontology, entities”kg_open: Resolve one key to packages when you already have a chunk, outline, entity, or file id.kg_hop: Expand fromfromKeywith a typedkind.similarmoves to the first chunks of files similar to the chunk’s file.kg_outline: Read a file’s table of contents, then open a section withkg_open {outlineKey}.kg_ontology: Fetch the published type box when you need TBox without stuffing it onto every search hit.kg_entity_search: Start from a name; results still land on mention packages so answers stay citation-backed. Each hit carriesdegree(how many chunks mention the entity) androle:bridge(specific enough to connect the question to evidence),filter(common enough to narrow the question, not to connect chunks), orignore(too common to connect the question to evidence).kg_file_entities: List entities and entity types already extracted for one file before you edit them or re-run an ontology review. UseafterEntityKeywhen the response istruncated.kg_file_triples: List typed REL instance triples for one file when both endpoints are mentioned in that file. Whentruncatedis true, passcontinueAfterback asafterSourceEntityKey,afterRelationTypeId, andafterTargetEntityKey.
Query a file
Section titled “Query a file”kg_files finds a file. kg_file reads or queries that one file. Pass namespace and exactly one of path or fileId. Chat @kg:<namespace>/<path> maps to that namespace and path.
Omit format for size, mime type, and status. A csv or tsv also returns columns, the header names.
| format | files | query |
|---|---|---|
sql |
csv, tsv | One read-only SELECT or WITH against the table data. Quote a header that is not a bare name: "Market Value (AUD)". |
text |
text, including csv, tsv, markdown, and JSON as text | An in-file regular expression, or omit query and pass startLine and endLine for a line window. |
jsonpath, jsonata, jinja |
JSON | A query over the document. Jinja receives the parsed JSON as data. |
A file larger than 10 MiB returns its size. Read it with text and a line window.
OpenCypher (kg_cypher)
Section titled “OpenCypher (kg_cypher)”kg_cypher runs one read-only OpenCypher statement against a single namespace. Label every node, follow one relationship at a time, project a property such as f.vfsPath, and end with a literal LIMIT from 1 to 50. The platform stops each query after 2 seconds. Parallel calls wait in line, and Falkor still runs one of these statements at a time.
List the namespaces you may read with kg_namespaces, and read a namespace’s published type box with kg_ontology, before you write a statement. The namespace argument selects the graph. Node labels are Chunk, FileRef, Entity, and EntityType. To read the next page, add WHERE ID(n) > $afterId. SKIP is rejected.
The graph stores:
- FileRef, a file (
vfsPath,name,fileId). A Folder (folderPath) connects withFolder -[:HAS_CHILD]-> FileRef. - Chunk, one text window (
text,path,chunkIndex).Chunk -[:PART_OF]-> FileRefandChunk -[:NEXT_CHUNK]-> Chunk. - OutlineNode, a heading (
title).OutlineNode -[:COVERS]-> Chunk. - Entity, a mention (
name,typeId). OnlyChunk -[:MENTIONS]-> Entity. - EntityType, the published schema (
typeId,label,side = "published"). - REL, a typed link between entities (
relationTypeId), when the namespace has any. Start from a chunk mention and alias the edge.
An entity, heading, or folder has to share the pattern with an aliased Chunk or FileRef. An exact word in a known path:
MATCH (c:Chunk)-[:PART_OF]->(f:FileRef)WHERE toLower(c.text) CONTAINS "dkim" AND f.vfsPath CONTAINS "reports"RETURN f.vfsPath AS path, c.text AS textLIMIT 10An answer cites the file path and the chunk text it came from. An entity name on its own is not a source. Cypher matches the text it is given: a misspelling such as “remed” for “Resmed” is an entity search, then a Cypher walk from that name back to the mentioning chunk. To connect two files, follow Chunk -[:MENTIONS]-> Entity <-[:MENTIONS]- Chunk and return each file path.
kg_search answers by meaning when you do not know the words or the path. Cypher answers an exact word, a figure, or a known path. The platform adds the enabled-file check and your folder and file permissions to each Chunk and FileRef before the query runs.
Permissions, fail closed
Section titled “Permissions, fail closed”Every KG tool call is permission-enforced. Fontana resolves the caller’s readable namespaces and their namespace, folder and file permissions on each call. Nothing from a file the caller may not read, or from a disabled file, reaches the answer — not its chunks, not the entities only it mentions, not relations only it states, not its similar-file links. If the caller context is missing or cannot be resolved, the call fails closed: an explicit auth error, never a silent empty result or a cross-namespace answer.
In-app agents and external PAT clients both execute tools under your identity. An in-app agent reads only what both it and you may read.
Using Knowledge Graph MCP in Flow
Section titled “Using Knowledge Graph MCP in Flow”- Agents: enable the seeded Knowledge Graph MCP connection from AI → Tools and assign namespaces on the agent (Knowledge capability tile).
- Chat: when the Knowledge Graph toggle is on, qualifying search evidence may be injected into the turn automatically. An answer that uses a file shows a bookmark for that file. Hover the bookmark to see the namespace and path. Click it to open the file in Knowledge Graph.
- KG Studio: graph layout, ontology editing, and search debugging use the product UI against the same tenant data plane.
Agent Memory writes use the separate Agent Memory tile (knowledge_addMemory / knowledge_forgetMemory), not MCP.
Tenant endpoints
Section titled “Tenant endpoints”On your tenant Flow origin:
- Health:
https://<tenant>.<baseDomain>/_kg-engine/health(no auth) - MCP (Streamable HTTP):
https://<tenant>.<baseDomain>/_kg-engine/mcp
In Flow: enable the seeded Knowledge Graph connection on an agent from AI → Tools. Flow runs tool calls as the signed-in user.
External MCP clients (Cursor, ChatGPT)
Section titled “External MCP clients (Cursor, ChatGPT)”Use a personal access token (PAT) to connect external MCP clients to your tenant’s public /_kg-engine/mcp endpoint. PATs authenticate as you; knowledge-graph:read and your permissions apply exactly as for in-app agents.
On AI → Tools, select the seeded Knowledge Graph MCP. Flow shows copyable URL, Authorization header, and Cursor JSON for ChatGPT, Claude, Cursor, and other Streamable HTTP clients. Create a PAT under Admin → Personal access tokens and paste the full fnt_pat_… value into your client config.
Issue a PAT
Section titled “Issue a PAT”- Sign in to your tenant Flow origin (the same HTTPS hostname you use for workflows, for example
https://acme.example.com). - Open Admin → Personal access tokens (
/admin/access-tokens). - Select Create PAT, then copy the full token (
fnt_pat_…). It is shown once; store it in a password manager. - Rotate or revoke at the same page if the token is exposed.
The PAT must be minted on the same tenant origin you configure in your MCP client. A token from one hostname does not work on another.
Cursor
Section titled “Cursor”Add a Streamable HTTP server in your Cursor MCP configuration (~/.cursor/mcp.json or a project-level .cursor/mcp.json):
{ "mcpServers": { "knowledge-graph": { "url": "https://<tenant>.<baseDomain>/_kg-engine/mcp", "headers": { "Authorization": "Bearer fnt_pat_…" } } }}After editing MCP config, run Developer: Reload Window in Cursor (or fully quit and reopen).
ChatGPT (Developer mode)
Section titled “ChatGPT (Developer mode)”ChatGPT connects to remote HTTPS MCP servers only (Streamable HTTP). You need a paid plan with Developer mode enabled (Settings → Security and login).
- Open Settings → Apps & Connectors (or ChatGPT Plugins → + in newer UI).
- Create a custom connector (Developer mode):
- Connector URL:
https://<tenant>.<baseDomain>/_kg-engine/mcp - Authentication: Token (not OAuth), or a single
Authorizationheader (see below).
- Connector URL:
- Paste your full
fnt_pat_…value. ChatGPT sendsAuthorization: Bearer fnt_pat_…to your tenant MCP endpoint.
Header-only setup (works in Cursor and ChatGPT):
| Field | Value |
|---|---|
| URL | https://<tenant>.<baseDomain>/_kg-engine/mcp |
| Bearer token env var | (leave empty unless you set the env var on the host) |
| Header name | Authorization |
| Header value | Bearer fnt_pat_… (full token, including the Bearer prefix) |
Env-var setup (ChatGPT desktop / Codex): set bearer_token_env_var to a name such as MCP_PAT, export that variable to the raw token (no Bearer prefix), and do not also send a conflicting Authorization header.
Verify PAT auth
Section titled “Verify PAT auth”Health checks do not use auth. Confirm the PAT on the MCP path:
export MCP_PAT='fnt_pat_…' # full token from /admin/access-tokens
curl -fsS "https://<tenant>.<baseDomain>/_kg-engine/health"# {"ok":true}
curl -sS -w "\nHTTP %{http_code}\n" -X POST \ -H "Authorization: Bearer $MCP_PAT" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' \ "https://<tenant>.<baseDomain>/_kg-engine/mcp"Replace <tenant>.<baseDomain> with your tenant origin. 401 means the token is missing, truncated, revoked, or minted on a different origin. 200 with a JSON-RPC body means auth succeeded.
Troubleshooting 401
Section titled “Troubleshooting 401”| Symptom | Likely cause | Fix |
|---|---|---|
| Health OK, MCP 401 | Bad or missing Authorization |
Use Authorization: Bearer fnt_pat_… only; pick one auth method (header or env var, not both) |
| Intermittent 401 | Bearer env var and header both set | Pick one auth method; clear the other |
| Always 401 | Truncated token in the UI | Re-copy the full PAT (~50+ characters after fnt_pat_) |
| Always 401 | PAT from another tenant origin | Create the PAT on the same hostname as your MCP client URL |
| Always 401 | Revoked or rotated PAT | Create a new PAT at /admin/access-tokens |