Skip to content

MCP API reference

The Memnex MCP server exposes three primitives: Tools (functions agents call), Resources (read-only data the host app fetches), Prompts (reusable templates the host LLM can adopt).

Connection

Memnex is self-hosted. Two transports are supported.

stdio subprocess (most portable)

The MCP client launches Memnex as a child process and talks to it over stdin/stdout. Works with Claude Desktop, Cursor, Cline, and any client that supports the standard subprocess MCP pattern.

{
  "mcpServers": {
    "memnex": {
      "command": "memnex",
      "args": ["serve", "mcp", "--transport", "stdio"],
      "env": {
        "MEMNEX_SECRET_KEY": "mx_live_kXXXX_<secret>",
        "MEMNEX_CHANNEL": "voice"
      }
    }
  }
}

The operator running this subprocess must export server-side infra (GOOGLE_API_KEY, MEMNEX_POSTGRES_URL, MEMNEX_REDIS_URL, MEMNEX_QDRANT_URL, etc.) in the shell that launches the MCP client. These are server-side secrets and must not appear in the env block above.

streamable-http (network endpoint)

Run the server as a long-lived HTTP service (memnex serve mcp --transport streamable-http --port 8500), and clients reach it over the network with their API key in headers.

{
  "mcpServers": {
    "memnex": {
      "url": "https://memory.your-company.example/mcp",
      "headers": {
        "Authorization": "Bearer mx_live_kXXXX_<secret>",
        "X-Memnex-Channel": "voice"
      }
    }
  }
}

The URL is wherever you deploy Memnex (Railway, Fly.io, AWS, your own VM). See operator-guide.md for deployment details.

Tools

memory_write

Store one or more facts about the user. Pydantic-validated; bypasses the rule-based extractor when structured facts are provided.

Arguments: - user_id (string, required) — opaque tenant-chosen identifier - facts (array of fact objects) — preferred; see fact shape below - raw_text (string) — legacy unstructured input; runs the rule-based extractor - session_id (string, optional) — opaque session label - trust_level (enum, default user_content) — user_content / agent_action / verified_external / system - source (string, optional) — free-text source label

Fact object: - fact (string, ≤4096 chars, required) - type (enum, required) — intent / preference / issue / resolution / profile - entities (array of strings, ≤50, default []) — formatted "type:value" (e.g. "order:XYZ") - confidence (number, 0.0–1.0, default 0.9)

Example:

{
  "tool": "memory_write",
  "arguments": {
    "user_id": "u_123",
    "facts": [
      {
        "fact": "Wants to cancel order XYZ",
        "type": "intent",
        "entities": ["order:XYZ"],
        "confidence": 0.95
      },
      {
        "fact": "Order XYZ never arrived",
        "type": "issue",
        "entities": ["order:XYZ"],
        "confidence": 0.9
      }
    ]
  }
}

Returns: {"written": <int>, "memory_ids": [<string>, ...]}

memory_read

Fetch formatted memory context for one user, sized to a token budget. Call this once at the start of every turn.

Arguments: - user_id (string, required) - token_budget (integer, default 2000, max 32000) - target_format (enum, optional) — voice / whatsapp / web / sms / app

Returns: {"context": "<formatted text>"}

Semantic search over a single user's memories.

Arguments: - user_id (string, required) - query (string, required, ≤2048 chars) - max_results (integer, default 5, max 50)

Returns: {"results": [{"memory_id", "fact", "type", "salience"}, ...]}

memory_forget

GDPR purge. Wipes the user's data from Redis, Postgres, Qdrant, and any pending events.

Arguments: - user_id (string, required) - reason (string, default gdpr_request, ≤256 chars)

Returns: {"deleted_memories": <int>, "receipt": <signed receipt>}

memory_trace

Given a draft agent reply, return the source memories that could have produced it. Empty hits = suspected hallucination.

Arguments: - user_id (string, required) - agent_output (string, required, ≤50000 chars)

Returns: {"hits": [{"memory_id", "fact", "score"}, ...]}

Resources

URI MIME Returns
memnex://schema/fact-types text/markdown The 5 fact types with examples + the entities "type:value" convention. Read once at agent startup.
memnex://users/{user_id}/memories application/json All active memories for one user (tenant-scoped automatically).
memnex://tenants/me/stats application/json Per-tenant counts (total memories, by-type breakdown, oldest/newest timestamps).

Resources are tenant-scoped by construction — the API key in the client config determines which tenant's data is reachable. Cross-tenant URIs are impossible.

Prompts

Name Arguments What it teaches
memory-writer agent_role (optional) When to call memory_write (per sub-intent), the 5 fact types, the entities convention, why structured facts is preferred over raw_text.
memory-reader target_format (optional, default web) How to call memory_read once per turn, where to fold the returned context, what NOT to do with it.
hallucination-check agent_output (required) Wraps memory_trace: before sending a draft, trace it; if hits is empty and the draft asserts user-specific facts, soften or ask.

Pull these once at agent startup (or once per session) and inject them into your system prompt. They encode the best-practice usage guidance so every adopter doesn't reinvent it.

Errors

All tools return JSON with an error field on failure:

error Meaning
bad_request Input failed validation. detail field has the specific reason.
forbidden Permission denied (typically a trust-policy violation).
internal Unexpected server error. Includes detail for debugging; nothing leaks across tenants.

Resources return {"error": "not_found", "detail": "..."} for unknown URIs.

Tenant scoping

Every tool call, every resource read, and every prompt invocation is scoped by the tenant derived from the API key. The agent's LLM never sees, supplies, or has any knowledge of tenant_id — it works exclusively with user_id, which is the tenant's chosen opaque identifier for the end user.