Developers

MCP tools

The twenty tools mantle exposes over MCP, grouped by purpose. Each tool has a focused job; picking the right one is usually obvious once you know the catalog. For agents wiring mantle in for the first time, the primary retrieval tools below are the ones that matter.

The tool descriptions below match what your agent will see in the MCP tool catalog, they're loaded into the agent's prompt at every turn, so we kept them crisp.

Primary retrieval

Start here

These are the tools an agent reaches for first. If you only learn four, learn these.

search_entities(query, type?, limit=10)

Resolve a name or alias to an entity_id. Your first call whenever the user names something. Case-insensitive substring match against every entity mantle has extracted across your connected sources.

When to call it: The user says “Who is Maren Vosh?” or “Tell me about Acme Corp.” You don't know an entity_id yet, this gets you one.

Returns: a ranked list of hits, each with entity_id, name, entity_type, and a preview of properties + source references.

// request

{
  "query": "Acme Corp",
  "type": "company",
  "limit": 3
}

// response

[
  { "entity_id": "ent_acme_8f2a",
    "name": "Acme Corp",
    "entity_type": "company",
    "score": 0.94,
    "aliases": ["Acme Corporation", "ACME"],
    "sources": ["salesforce", "hubspot"] },
  { "entity_id": "ent_acmegen_b1",
    "name": "Acme Generics",
    "score": 0.61, ... }
]

get_entity_context(entity_id, verbosity="concise")

One-call snapshot of an entity: identity, flat properties, aliases, and a bucketed summary of every relationship grouped by type. Pass verbosity="detailed" and each bucket gets three highest-confidence example edges inline, avoids a second round trip.

When to call it: “Tell me everything you know about X.” This is the workhorse after search_entities.

Doesn't return: raw document text. For that, use semantic_search or fetch_document.

// request

{
  "entity_id": "ent_acme_8f2a",
  "verbosity": "detailed"
}

// response

{
  "entity": {
    "entity_id": "ent_acme_8f2a",
    "name": "Acme Corp",
    "entity_type": "company",
    "properties": { "arr": "$420k", "health": 0.78 }
  },
  "rel_summary": [
    { "rel_type": "employs",      "count": 14 },
    { "rel_type": "signed",       "count": 3  },
    { "rel_type": "located_in",   "count": 1  }
  ]
}

get_relationships(entity_id, mode="summary", rel_type?, min_confidence=0.5, limit=20)

Enumerate an entity's relationships. Two modes:

  • mode="summary", relationship types grouped by count with three example edges each
  • mode="detailed", a paginated list of edges, optionally filtered by rel_type

Use this, not semantic_search, for enumeration questions: “Which properties does Helix own?”, “What companies does Maren advise?” Semantic search returns a ranked sample; this returns the complete linked set.

Completeness signal: the response carries a completeness field ("exhaustive" / "truncated" / "severely_truncated") and an optional suggestion string when the entity is a hub and the answer is incomplete. Read these, your agent will know whether to page or narrow.

// request

{
  "entity_id": "ent_acme_8f2a",
  "mode": "detailed",
  "rel_type": "employs",
  "limit": 5
}

// response

{
  "relationships": [
    { "rel_type": "employs",
      "target": { "entity_id": "ent_maren", "name": "Maren Vosh" },
      "confidence": 0.96,
      "source_ref": { "source": "salesforce" } },
    ...
  ],
  "completeness": "exhaustive",
  "page": { "cursor": null }
}

trace_connection(from_id, to_id, max_hops=4, min_confidence=0.5)

Shortest relationship path between two entities with per-hop evidence. One of the most valuable tools, agents want to say “X is connected to Y via Z” with confidence, not hallucinate a path.

When to call it: “How is A connected to B?”, “Is there any link between Acme and Globex?”

If no path exists within max_hops at the given min_confidence, the tool returns found=false, your agent can report that honestly and optionally retry with looser constraints.

// request

{
  "from_id": "ent_acme_8f2a",
  "to_id":   "ent_globex_3c1",
  "max_hops": 4
}

// response

{
  "found": true,
  "hops": [
    { "from": "Acme Corp", "rel": "employs",
      "to": "Maren Vosh",        "confidence": 0.96 },
    { "from": "Maren Vosh", "rel": "advises",
      "to": "Globex Industries", "confidence": 0.88 }
  ],
  "length": 2
}

Document retrieval

Fetch the text

Once an agent has identified entities, these fetch the underlying text.

semantic_search(query, limit=10, min_score=0.6, source_id?)

Vector search across every indexed document chunk. Returns a ranked sample, not an exhaustive list, the response's completeness field is always "top_k" to keep this honest.

When to call it: topic-style questions where no specific entity is named. “What do we know about the Series B close?”

For enumeration questions anchored on a named entity (“which properties in Brickell”), prefer search_entitiesget_relationships. If you do call semantic_search on an enumeration-style question and the query resolves to an indexed entity, the response will include an entity_suggestion field nudging you toward the graph path.

fetch_document(source_id?, file_id?, chunk_id?, window=1)

Pull source content. Two modes:

  • chunk_id, returns the specified chunk plus window chunks on each side. Fast; use after semantic_search to expand context.
  • (source_id, file_id), returns the full document. Slower; use when the chunk window isn't enough.

Graph / advanced

When you need structure

traverse_graph(entity_id, depth=2, limit=100, min_confidence=0.5)

Raw local-subgraph dump, every RELATES_TO edge reachable within depth hops. Annotated openWorldHint: true to signal breadth.

When to use: You want the whole neighborhood to render a visualization or reason over structure. For most narrative questions the primary retrieval tools are better.

search_relationships(query, limit=5)

Fuzzy-find relationship-type strings by meaning. Example: search_relationships("financing") might return financed_with_debt, has_lender, equity_investor. Use before get_relationships(rel_type=X) to discover which canonical rel-type the user's intent maps to.

Returns empty on no match, don't retry with variations. Report the gap to the user.

query_database(source_id, sql, limit=50)

Read-only SELECT against a connected PostgreSQL source. sqlparse-validated; INSERT / UPDATE / DELETE / DDL are rejected client-side. readOnlyHint: true.

Best practice: always call semantic_search("schema columns <table>") first to discover real column names. Don't guess.

Ops

Admin surface

These tools are read-only in the normal sense but mostly used by admin or ops agents, not customer-facing ones.

list_sources()

Every connected data source with status and document count. Your agent calls this to discover source_id values for semantic_search / query_database / fetch_document.

get_stats()

Aggregate corpus counts, sources, documents, entities, relationships, communities. “What's in my graph right now?”

get_usage_balance()

Current credit balance for the tenant. Call this before expensive operations if your agent is cost-sensitive.

trigger_sync(source_id)

Enqueue an async sync of the named source. Idempotent, not destructive. Useful for “pull the latest from Gmail” style requests. Returns immediately with a task_id; the sync runs in the background.

Tool-selection cheat sheet

Agent questionCall this
“Who/what is X?”search_entitiesget_entity_context
“Which X does Y have?” (enumeration)search_entitiesget_relationships(mode="detailed", rel_type=…)
“How is A connected to B?”two search_entitiestrace_connection
“What topics touch X?”semantic_search + get_entity_context
“Give me the whole local graph around X”traverse_graph (advanced)
“What rel_type matches the phrase '…'?”search_relationships
Admin / opslist_sources, get_stats, get_usage_balance, trigger_sync

Type registries

Browse what mantle can talk about

Before you write a query, you sometimes want to know what entity types and relationship types actually exist in your tenant. These three tools enumerate the registries.

list_object_types()

Lists every entity type observed across your data, person, company, contract, project, etc. Use it to choose a sensible entity_type filter for search_entities or query_objects.

When to call it: the user asks “what kinds of things does mantle know about?” or you're building a filtered UI.

Returns: a list of object_type rows with name, slug, count, and example entity ids.

get_object_type(type)

Detail view for a single entity type, definition, recommended properties, common relationship types it participates in. Useful when you want to know what fields a contract usually carries before writing a query.

list_link_types()

Lists every relationship type in your tenant, employed_by, located_in, references, etc. Pair with search_relationships when you have a vague phrase (“financing”) and want to resolve it to a concrete rel_type.

Query & facts

Structured slicing of the graph

When you want a typed list (“all companies in EMEA”) or the atomic-fact view of a single entity, these tools are sharper than free-text search.

query_objects(entity_type, filters?, limit=50)

List entities by type, optionally filtered on properties or relationships. Closer to SQL SELECT than to semantic search, predictable, paginated, deterministic.

When to call it: “give me every contract signed after 2026-01-01” or “all persons with role="CTO"”.

get_entity_facts(entity_id)

Atomic-facts view of an entity, every (subject, predicate, object) triple mantle knows about it, with source attribution. Lower-level than get_entity_context: no narrative summary, just the underlying facts.

When to call it: you're auditing extraction quality, building a custom UI on top of mantle, or asking “what does mantle actually claim about this entity?”

Cross-doc entity merge

Operator review of same_as candidates

mantle automatically proposes same_as links between entities that look like the same real-world thing across sources. High-confidence merges happen automatically; the rest are surfaced to a human operator for approval. These two tools drive that review flow, see Cross-doc entity merge for the four signals, the safety floors, and the full workflow.

list_entity_link_candidates(min_score?, limit=50)

Lists pending cross-doc merge candidates, pairs of entities the scorer flagged as probable matches but didn't auto-merge. Each row carries the score, the contributing signals (name similarity, shared neighbors, semantic embedding), and short evidence text.

When to call it: you're running an operator-review pass, or you want to know what merges are pending before triggering a consolidation report.

confirm_entity_link(candidate_id, decision)

Operator decision on a single candidate. decision="approve" creates a same_as edge and marks the two entities as merged; decision="reject" records a negative example so the scorer learns from it.

Restricted: tenant-admin scope. Not part of the default agent toolkit, surface it only in operator UIs.

Defaults worth knowing

  • get_relationships defaults to min_confidence=0.5, high-signal only. Pass 0.0 if you explicitly want every edge including low-confidence candidates.
  • trace_connection defaults to max_hops=4 and min_confidence=0.5. If found=false, lower min_confidence or raise max_hops (up to 6) before concluding no path exists.
  • get_entity_context returns concise shape by default. Pass verbosity="detailed" to inline example edges per relationship type.
  • semantic_search defaults to min_score=0.6, tight relevance. Lower to 0.4 if you want more breadth.