Skip to main content
Glama

emem, the verifiable memory protocol for the physical world

k-NN over the corpus by embedding

emem_find_similar
Idempotent

k-NN over the corpus by cell embedding or inline vector. Returns neighbours ordered nearest-first, each with cell64, score and the band scanned, plus a signed receipt over the vectors read. Scoring is mode: cosine is exact fp32; hamming is a sign-bit popcount that scans far more cells for the same budget; hamming_then_rerank does both. k is 1..1000, default 10. It ranks what the corpus already holds; only when the KEY's own vector is missing does it materialise that one band for the key, signed and reported in materialize_notes, then retry. Neighbours are never materialised, so an empty result means nobody has attested a vector nearby, not that nowhere resembles the key.

When to use: Call when the user asks 'find places like X', 'where else looks like this', or hands an embedding to find neighbours. key is either a cell64 or inline:[x,y,...]. Default band is geotessera (128-D Tessera foundation embedding); pass band: "geotessera.multi_year" for the 1152-D 9-vintage (2017–2025) fusion.

Example arguments: {"key":"damO.zb000.xUti.zde78","k":10}

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
kNoHow many neighbours to return.
keyYescell64 (look up that cell's vector) or 'inline:[x,y,...]' literal vector
bandNovector band to scan (default: 128-D Tessera foundation embedding). For mode=hamming/hamming_then_rerank you can pass either the cosine band (e.g. 'geotessera') or its binary sibling ('geotessera.bin128'), the responder picks the right one.geotessera
cellNoAlias for `key`.
modeNoScoring mode. cosine = fp32 over full vector (precise, ~256 B/cell scan). hamming = sign-bit popcount over the binary sibling band (~16 B/cell, ~1000× faster, ~65% recall@10). hamming_then_rerank = triage with Hamming on 4·k candidates then re-rank by cosine, matches cosine precision at ~16× less work.cosine
scopeNoMulti-tenant scope `{user_id, agent_id, run_id, org_id}`. Setting it bypasses the ANN index entirely, because that index carries no scope column, and runs the brute-force scan instead: the tenant filter is honoured truthfully, and the call is slower.
cell64NoAlias for `key`.
filterNoClaim-algebra predicate evaluated against every candidate before ranking. A cell with no fact for the filter's band is DROPPED rather than treated as false, so 'places like X where NDVI > 0.5' never silently includes cells with no NDVI.
as_of_tslotNoBi-temporal valid-time bound. Applied to candidate cells BEFORE cosine scoring, a cell with no fact whose tslot ≤ as_of_tslot under the scoring band is dropped from the candidate pool (undecidable→drop). When set, the Lance ANN fast-path is bypassed (the index has no signed_at column); brute-force k-NN runs instead so as_of is honoured truthfully.
as_of_signed_atNoBi-temporal transaction-time bound (RFC 3339). Also applied to candidates BEFORE cosine. Same Lance-bypass note as as_of_tslot.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed4 schema fields changed
    • addedInput schema / properties / cell
      Added value: +{
      +  "description": "Alias for `key`.",
      +  "type": "string"
      +}
    • addedInput schema / properties / cell64
      Added value: +{
      +  "description": "Alias for `key`.",
      +  "type": "string"
      +}
    • addedInput schema / properties / filter
      Added value: +{
      +  "description": "Claim-algebra predicate evaluated against every candidate before ranking. A cell with no fact for the filter's band is DROPPED rather than treated as false, so 'places like X where NDVI > 0.5' never silently includes cells with no NDVI.",
      +  "type": "object"
      +}
    • addedInput schema / properties / scope
      Added value: +{
      +  "description": "Multi-tenant scope `{user_id, agent_id, run_id, org_id}`. Setting it bypasses the ANN index entirely, because that index carries no scope column, and runs the brute-force scan instead: the tenant filter is honoured truthfully, and the call is slower.",
      +  "type": "object"
      +}
  2. Changed1 schema field changed
    • addedInput schema / properties / k / description
      Added value: +"How many neighbours to return."
  3. Changed3 schema fields changed
    • changedInput schema / properties / as_of_tslot / description
      Previous value: -"Bi-temporal valid-time bound. Applied to candidate cells BEFORE cosine scoring — a cell with no fact whose tslot ≤ as_of_tslot under the scoring band is dropped from the candidate pool (undecidable→drop). When set, the Lance ANN fast-path is bypassed (the index has no signed_at column); brute-force k-NN runs instead so as_of is honoured truthfully."New value: +"Bi-temporal valid-time bound. Applied to candidate cells BEFORE cosine scoring, a cell with no fact whose tslot ≤ as_of_tslot under the scoring band is dropped from the candidate pool (undecidable→drop). When set, the Lance ANN fast-path is bypassed (the index has no signed_at column); brute-force k-NN runs instead so as_of is honoured truthfully."
    • changedInput schema / properties / band / description
      Previous value: -"vector band to scan (default: 128-D Tessera foundation embedding). For mode=hamming/hamming_then_rerank you can pass either the cosine band (e.g. 'geotessera') or its binary sibling ('geotessera.bin128') — the responder picks the right one."New value: +"vector band to scan (default: 128-D Tessera foundation embedding). For mode=hamming/hamming_then_rerank you can pass either the cosine band (e.g. 'geotessera') or its binary sibling ('geotessera.bin128'), the responder picks the right one."
    • changedInput schema / properties / mode / description
      Previous value: -"Scoring mode. cosine = fp32 over full vector (precise, ~256 B/cell scan). hamming = sign-bit popcount over the binary sibling band (~16 B/cell, ~1000× faster, ~65% recall@10). hamming_then_rerank = triage with Hamming on 4·k candidates then re-rank by cosine — matches cosine precision at ~16× less work."New value: +"Scoring mode. cosine = fp32 over full vector (precise, ~256 B/cell scan). hamming = sign-bit popcount over the binary sibling band (~16 B/cell, ~1000× faster, ~65% recall@10). hamming_then_rerank = triage with Hamming on 4·k candidates then re-rank by cosine, matches cosine precision at ~16× less work."
  4. Changed2 schema fields changed
    • addedInput schema / properties / as_of_signed_at
      Added value: +{
      +  "description": "Bi-temporal transaction-time bound (RFC 3339). Also applied to candidates BEFORE cosine. Same Lance-bypass note as as_of_tslot.",
      +  "format": "date-time",
      +  "type": "string"
      +}
    • addedInput schema / properties / as_of_tslot
      Added value: +{
      +  "description": "Bi-temporal valid-time bound. Applied to candidate cells BEFORE cosine scoring — a cell with no fact whose tslot ≤ as_of_tslot under the scoring band is dropped from the candidate pool (undecidable→drop). When set, the Lance ANN fast-path is bypassed (the index has no signed_at column); brute-force k-NN runs instead so as_of is honoured truthfully.",
      +  "minimum": 0,
      +  "type": "integer"
      +}
  5. Changed2 schema fields changed
    • changedInput schema / properties / band / description
      Previous value: -"vector band to scan (default: 128-D Tessera foundation embedding)"New value: +"vector band to scan (default: 128-D Tessera foundation embedding). For mode=hamming/hamming_then_rerank you can pass either the cosine band (e.g. 'geotessera') or its binary sibling ('geotessera.bin128') — the responder picks the right one."
    • addedInput schema / properties / mode
      Added value: +{
      +  "default": "cosine",
      +  "description": "Scoring mode. cosine = fp32 over full vector (precise, ~256 B/cell scan). hamming = sign-bit popcount over the binary sibling band (~16 B/cell, ~1000× faster, ~65% recall@10). hamming_then_rerank = triage with Hamming on 4·k candidates then re-rank by cosine — matches cosine precision at ~16× less work.",
      +  "enum": [
      +    "cosine",
      +    "hamming",
      +    "hamming_then_rerank"
      +  ],
      +  "type": "string"
      +}
  6. First observed

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds rich behavioral context far beyond the annotations: mode tradeoffs (exact vs approximate vs rerank), the meaning of an empty result under open-world semantics, the materialisation behavior for a missing key vector, and the Lance-index bypass for scope/as-of filters. It also clarifies that filter-relevant cells with no fact are dropped rather than treated as false. This aligns with and enriches the openWorldHint/idempotentHint annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but well organized: it front-loads the core return contract, then explains scoring modes, k bounds, open-world semantics, when to use, and an example. The occasional redundancy with the schema is minor and serves narrative clarity rather than padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no output schema, the description fully explains the return shape, the meaning of missing neighbours, the side-effect of materialising the key's band, mode/band selection, and the consequences of scope/as_of/filter. An agent has everything needed to decide, invoke, and interpret the result correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is 100%, the description adds substantial parameter meaning: mode-specific precision/performance tradeoffs, band naming and dimensionality, the effect of scope and as_of on the ANN fast-path, and the semantic behavior of the filter. This goes well beyond the schema's own property descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific operation (k-NN over the corpus) with a concrete resource (cell embedding or inline vector) and exact outputs (ordered neighbours with cell64, score, band, and signed receipt). It also disambiguates by giving canonical user phrasings ('find places like X', 'where else looks like this'), making it clearly distinct from sibling memory/entity tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description has an explicit 'When to use' section with concrete query phrasings and example arguments, plus guidance on choosing bands and modes. It does not name specific sibling tools to avoid, nor give explicit 'when not to use' conditions, so it stops just short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.