Skip to main content
Glama

store

Unified storing for structured, file-backed, or combined payloads in one request. Choose path by source: file- or resource-sourced (attachment/file to preserve) → use file_content+mime_type or file_path; conversation- or tool-sourced (chat…

Instructions

Unified storing for structured, file-backed, or combined payloads in one request. Choose path by source: file- or resource-sourced (attachment/file to preserve) → use file_content+mime_type or file_path; conversation- or tool-sourced (chat or other MCP) → use entities. You may send both entities and file input in the same call. File bytes create a content-addressed sources row (SHA-256 dedup per user); the response includes source_id / content_hash for the unstructured leg. The server does not invent structured fields from opaque blobs without an explicit interpretation block or a separate interpretation flow. Agents should parse and extract entities first when they need structured data from a readable file, then send those entities alongside the raw file. IMPORTANT FOR STRUCTURED DATA: Include ALL fields from source data. Schema fields go to observations; non-schema fields go to raw_fragments for future schema expansion. Relationships must link entities you own; a refused relationship is reported in relationships_refused rather than failing the call.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
commitNoWhen false, runs in plan/dry-run mode: resolves entities and returns planned actions ("would_create" / "would_match_existing") without persisting observations or source rows. Useful for previewing a structured store before committing.
strictNoWhen true, refuse silent merges: only match an existing entity when the entity's schema declares canonical_name_fields that the request matches, or when target_id is supplied. Prevents accidental coalescing into a pre-existing record.
user_idNo
entitiesNo
file_pathNoA path on the SERVER's filesystem, not yours. The file is read by the Neotoma instance, so this only works when your client runs on the same machine as the instance — the axis is co-located vs remote, not desktop vs web. Against a hosted or otherwise remote instance it cannot see your disk and is rejected with ERR_FILE_PATH_IS_SERVER_LOCAL. To send a file from a remote client: upload the bytes (POST /sources/upload, multipart/form-data) and pass the returned source_id, or inline small files with file_content (base64) + mime_type. MIME type is auto-detected from the content or extension when not provided.
mime_typeNoMIME type (e.g., 'application/pdf', 'text/csv') - required with file_content, optional with file_path (auto-detected from extension)
file_contentNoBase64-encoded file content. Use file_path for local files instead of base64 encoding.
relationshipsNoOptional. Create relationships between entities in this request. Use `source_index` or `target_index` for entities in this request, and `source_entity_id` or `target_entity_id` for existing entities. Index and id endpoints may be mixed in one relationship.
external_actorNoUpstream artifact author (e.g. GitHub user) stamped into observation provenance alongside AAuth agent attribution. Matches `ExternalActorInputSchema` in `action_schemas.ts`.
interpretationNoOptional interpretation provenance for source-derived structured extraction. Supplying this creates an interpretation row and links new observations to it. Omit for ordinary already-structured/chat-native facts, which keep observations.interpretation_id NULL.
source_peer_idNoOptional Neotoma peer id to stamp on observations for cross-instance sync loop prevention (Phase 5). Requires `observation_source: sync` in practice.
source_storageNoStorage mode for file ingestion. Default 'inline' copies bytes into the database (portable, durable). 'reference' stores only a path + metadata row without copying bytes — zero DB bloat, but host-local and depends on the file staying in place. Requires file_path (not file_content). Derivations (observations/entities) are still materialized at ingest. Use 'reference' for large local files you control; use 'inline' for anything that must be shared or portable.
idempotency_keyNoRequired for structured path, optional for unstructured-only path.
source_priorityNoTrust/priority of this observation's source. Only affects snapshot resolution for fields whose merge strategy is highest_priority (set via register_schema reducer_config); under the default last_write strategy it is stored but ignored.
original_filenameNoOriginal filename or source label (optional). For unstructured: auto-detected from file_path if not provided. For structured (entities): omit when data is agent-provided (no file origin); the source will have no filename. Pass only when mirroring a real file name or when a display label is desired.
observation_sourceNoClassifies the *kind* of write being performed, orthogonal to `source_priority`. See `Observation.observation_source` for the full semantic contract. Defaults to `llm_summary` when unspecified. Applies to every observation created by this request.
file_idempotency_keyNoOptional idempotency key for file path when sending structured + unstructured in one call.
expected_entity_absentNoWhen true, atomically create exactly one structured entity only if its complete schema-declared physical identity is absent. Requires commit=true and a nonempty idempotency_key; file, relationship, interpretation, intake, target and sync combinations are refused. Omitted or false preserves ordinary upsert behavior. Exact retries return the original immutable operation receipt without new effects.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed4 schema fields changedv0.25.0
    • addedInput schema / properties / expected_entity_absent
      Added value: +{
      +  "description": "When true, atomically create exactly one structured entity only if\nits complete schema-declared physical identity is absent. Requires\ncommit=true and a nonempty idempotency_key; file, relationship,\ninterpretation, intake, target and sync combinations are refused.\nOmitted or false preserves ordinary upsert behavior. Exact retries\nreturn the original immutable operation receipt without new effects.\n",
      +  "type": "boolean"
      +}
    • addedInput schema / properties / external_actor / properties / delivery_id / description
      Added value: +"Not carried over from a request body; set only by the signed\nGitHub webhook route.\n"
    • addedInput schema / properties / external_actor / properties / verified_via / description
      Added value: +"Accepted for compatibility, but a request body can only assert an\nexternal actor: the stored value is always `claim`. The stronger\ntiers are assigned by server-side verification paths (the signed\nGitHub webhook route, AAuth token claims, grant linkage).\n"
    • changedInput schema / properties / relationships / items / oneOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "metadata": {
      -        "additionalProperties": true,
      -        "type": "object"
      -      },
      -      "relationship_type": {
      -        "enum": [
      -          "PART_OF",
      -          "CORRECTS",
      -          "REFERS_TO",
      -          "SETTLES",
      -          "DUPLICATE_OF",
      -          "DEPENDS_ON",
      -          "SUPERSEDES",
      -          "EMBEDS",
      -          "works_at",
      -          "owns",
      -          "manages",
      -          "part_of",
      -          "related_to",
      -          "depends_on",
      -          "references",
      -          "transacted_with",
      -          "member_of",
      -          "reports_to",
      -          "located_at",
      -          "created_by",
      -          "funded_by",
      -          "acquired_by",
      -          "subsidiary_of",
      -          "partner_of",
      -          "competitor_of",
      -          "supplies_to",
      -          "contracted_with",
      -          "invested_in"
      -        ],
      -        "type": "string"
      -      },
      -      "source_index": {
      -        "description": "Index into the entities array for the source entity.",
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "target_index": {
      -        "description": "Index into the entities array for the target entity.",
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "relationship_type",
      -      "source_index",
      -      "target_index"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "metadata": {
      -        "additionalProperties": true,
      -        "type": "object"
      -      },
      -      "relationship_type": {
      -        "enum": [
      -          "PART_OF",
      -          "CORRECTS",
      -          "REFERS_TO",
      -          "SETTLES",
      -          "DUPLICATE_OF",
      -          "DEPENDS_ON",
      -          "SUPERSEDES",
      -          "EMBEDS",
      -          "works_at",
      -          "owns",
      -          "manages",
      -          "part_of",
      -          "related_to",
      -          "depends_on",
      -          "references",
      -          "transacted_with",
      -          "member_of",
      -          "reports_to",
      -          "located_at",
      -          "created_by",
      -          "funded_by",
      -          "acquired_by",
      -          "subsidiary_of",
      -          "partner_of",
      -          "competitor_of",
      -          "supplies_to",
      -          "contracted_with",
      -          "invested_in"
      -        ],
      -        "type": "string"
      -      },
      -      "source_index": {
      -        "description": "Index into the entities array for the source entity.",
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "target_entity_id": {
      -        "description": "Existing target entity ID.",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "relationship_type",
      -      "source_index",
      -      "target_entity_id"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "metadata": {
      -        "additionalProperties": true,
      -        "type": "object"
      -      },
      -      "relationship_type": {
      -        "enum": [
      -          "PART_OF",
      -          "CORRECTS",
      -          "REFERS_TO",
      -          "SETTLES",
      -          "DUPLICATE_OF",
      -          "DEPENDS_ON",
      -          "SUPERSEDES",
      -          "EMBEDS",
      -          "works_at",
      -          "owns",
      -          "manages",
      -          "part_of",
      -          "related_to",
      -          "depends_on",
      -          "references",
      -          "transacted_with",
      -          "member_of",
      -          "reports_to",
      -          "located_at",
      -          "created_by",
      -          "funded_by",
      -          "acquired_by",
      -          "subsidiary_of",
      -          "partner_of",
      -          "competitor_of",
      -          "supplies_to",
      -          "contracted_with",
      -          "invested_in"
      -        ],
      -        "type": "string"
      -      },
      -      "source_entity_id": {
      -        "description": "Existing source entity ID.",
      -        "type": "string"
      -      },
      -      "target_index": {
      -        "description": "Index into the entities array for the target entity.",
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "relationship_type",
      -      "source_entity_id",
      -      "target_index"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "metadata": {
      -        "additionalProperties": true,
      -        "type": "object"
      -      },
      -      "relationship_type": {
      -        "enum": [
      -          "PART_OF",
      -          "CORRECTS",
      -          "REFERS_TO",
      -          "SETTLES",
      -          "DUPLICATE_OF",
      -          "DEPENDS_ON",
      -          "SUPERSEDES",
      -          "EMBEDS",
      -          "works_at",
      -          "owns",
      -          "manages",
      -          "part_of",
      -          "related_to",
      -          "depends_on",
      -          "references",
      -          "transacted_with",
      -          "member_of",
      -          "reports_to",
      -          "located_at",
      -          "created_by",
      -          "funded_by",
      -          "acquired_by",
      -          "subsidiary_of",
      -          "partner_of",
      -          "competitor_of",
      -          "supplies_to",
      -          "contracted_with",
      -          "invested_in"
      -        ],
      -        "type": "string"
      -      },
      -      "source_entity_id": {
      -        "description": "Existing source entity ID.",
      -        "type": "string"
      -      },
      -      "target_entity_id": {
      -        "description": "Existing target entity ID.",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "relationship_type",
      -      "source_entity_id",
      -      "target_entity_id"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "metadata": {
      +        "additionalProperties": true,
      +        "type": "object"
      +      },
      +      "relationship_type": {
      +        "description": "Relationship type. The vocabulary is a runtime registry, not a closed enum: call list_relationship_types to read what this instance accepts, and register_relationship_type to add to it. Names are identifier-shaped and casing-agnostic (both SCREAMING_SNAKE and lower_snake are in use).",
      +        "type": "string"
      +      },
      +      "source_index": {
      +        "description": "Index into the entities array for the source entity.",
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "target_index": {
      +        "description": "Index into the entities array for the target entity.",
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "relationship_type",
      +      "source_index",
      +      "target_index"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "metadata": {
      +        "additionalProperties": true,
      +        "type": "object"
      +      },
      +      "relationship_type": {
      +        "description": "Relationship type. The vocabulary is a runtime registry, not a closed enum: call list_relationship_types to read what this instance accepts, and register_relationship_type to add to it. Names are identifier-shaped and casing-agnostic (both SCREAMING_SNAKE and lower_snake are in use).",
      +        "type": "string"
      +      },
      +      "source_index": {
      +        "description": "Index into the entities array for the source entity.",
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "target_entity_id": {
      +        "description": "Existing target entity ID.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "relationship_type",
      +      "source_index",
      +      "target_entity_id"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "metadata": {
      +        "additionalProperties": true,
      +        "type": "object"
      +      },
      +      "relationship_type": {
      +        "description": "Relationship type. The vocabulary is a runtime registry, not a closed enum: call list_relationship_types to read what this instance accepts, and register_relationship_type to add to it. Names are identifier-shaped and casing-agnostic (both SCREAMING_SNAKE and lower_snake are in use).",
      +        "type": "string"
      +      },
      +      "source_entity_id": {
      +        "description": "Existing source entity ID.",
      +        "type": "string"
      +      },
      +      "target_index": {
      +        "description": "Index into the entities array for the target entity.",
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "relationship_type",
      +      "source_entity_id",
      +      "target_index"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "metadata": {
      +        "additionalProperties": true,
      +        "type": "object"
      +      },
      +      "relationship_type": {
      +        "description": "Relationship type. The vocabulary is a runtime registry, not a closed enum: call list_relationship_types to read what this instance accepts, and register_relationship_type to add to it. Names are identifier-shaped and casing-agnostic (both SCREAMING_SNAKE and lower_snake are in use).",
      +        "type": "string"
      +      },
      +      "source_entity_id": {
      +        "description": "Existing source entity ID.",
      +        "type": "string"
      +      },
      +      "target_entity_id": {
      +        "description": "Existing target entity ID.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "relationship_type",
      +      "source_entity_id",
      +      "target_entity_id"
      +    ],
      +    "type": "object"
      +  }
      +]
  2. Changed1 schema field changedv0.22.2
    • changedInput schema / properties / file_path / description
      Previous value: -"Local file path (alternative to file_content). If provided, file will be read from filesystem. MIME type will be auto-detected from extension if not provided. Works in local environments (Cursor, Claude Code) where MCP server has filesystem access. Does NOT work in web-based environments (claude.ai, chatgpt.com) - use file_content for those."New value: +"A path on the SERVER's filesystem, not yours. The file is read by the Neotoma instance, so this only works when your client runs on the same machine as the instance — the axis is co-located vs remote, not desktop vs web. Against a hosted or otherwise remote instance it cannot see your disk and is rejected with ERR_FILE_PATH_IS_SERVER_LOCAL. To send a file from a remote client: upload the bytes (POST /sources/upload, multipart/form-data) and pass the returned source_id, or inline small files with file_content (base64) + mime_type. MIME type is auto-detected from the content or extension when not provided."
  3. Changed2 schema fields changedv0.21.0
    • addedInput schema / properties / source_priority / description
      Added value: +"Trust/priority of this observation's source. Only affects snapshot resolution for fields whose merge strategy is highest_priority (set via register_schema reducer_config); under the default last_write strategy it is stored but ignored."
    • addedInput schema / properties / source_storage
      Added value: +{
      +  "description": "Storage mode for file ingestion. Default 'inline' copies bytes into the database (portable, durable). 'reference' stores only a path + metadata row without copying bytes — zero DB bloat, but host-local and depends on the file staying in place. Requires file_path (not file_content). Derivations (observations/entities) are still materialized at ingest. Use 'reference' for large local files you control; use 'inline' for anything that must be shared or portable.",
      +  "enum": [
      +    "inline",
      +    "reference"
      +  ],
      +  "type": "string"
      +}
  4. Addedv0.15.0
  5. Removedv0.14.0
  6. Addedv0.12.1
  7. Removedv0.11.0
  8. First observedv0.1.0

TDQS

A4/5.0
Behavior4/5

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

With no annotations, the description carries the burden and does substantial work: content-addressed SHA-256 dedup per user, source_id/content_hash returned for the unstructured leg, refusal of relationships reported in relationships_refused rather than failing, and the explicit refusal to invent structured fields without an interpretation block. It omits some behaviors like the required idempotency_key on the structured path and dry-run/atomicity semantics.

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

Conciseness4/5

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

The purpose and the source-based routing decision are front-loaded in the first two sentences, and later sentences add scoping constraints (no invented fields, include ALL fields, relationship refusal). Dense but essentially every sentence carries decision-relevant information for an 18-parameter tool.

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

Completeness4/5

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

For a high-complexity, 18-param tool with no annotations and no output schema, the description is reasonably complete on the decisions an agent must make (which leg, whether interpretation is needed, how refusals surface). It leans on the rich schema for parameter-level detail, which is appropriate at 89% coverage, though a note on dry-run/commit and atomicity would round it out.

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

Parameters4/5

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

Schema coverage is 89%, so the schema already documents most parameters. The description adds genuine cross-parameter meaning the schema does not express: the source-based routing between entities and file inputs, that both can coexist in one call, and the flattening requirement for entity fields (reinforced by the schema's ERR_STORE_RESOLUTION_FAILED hint).

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

Purpose4/5

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

States a specific verb (store) and resource scope (structured, file-backed, or combined payloads) plus the key axis of variation: source type decides the path. It distinguishes the structured vs unstructured legs, though it does not directly name sibling tools like submit_entity or create_relationship that an agent might confuse it with.

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?

Gives condition-based routing: file/resource-sourced data goes through file_content+mime_type or file_path, while conversation/tool-sourced data goes through entities, and states both may be combined. It also advises extracting entities before sending a readable file. No explicit when-not or named alternative tool, so not a full 5.

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