Skip to content

MCP tools

The PLUR MCP server (@plur-ai/mcp) exposes ~24 tools. These are the same tools the OpenClaw plugin, Hermes adapter, and CLI delegate to under the hood — same names, same parameters, same return shape.

Tools are grouped below by lifecycle: sessionmemoryepisodesingestionmetasystempacksstores.

Every tool returns _next (most logical follow-up tool) and _related (2–4 related tool names) where applicable, creating an implicit navigation graph the agent can follow without prompting.

Start a session and inject relevant engrams for the upcoming task. This is the most important tool — it’s the one that makes PLUR feel like memory rather than a tool the agent has to think about.

plur_session_start(task: string, tags?: string[]) → SessionStartResult

When agents call it: at the start of every conversation. Adapters with lifecycle hooks (Claude Code via SessionStart, OpenClaw via bootstrap, Hermes via pre_llm_call) call it automatically. Direct callers (Cursor, Windsurf, custom) should call it as the first tool invocation per task.

What happens server-side: the engine runs plur_inject against the task, picks the top engrams within the token budget, formats them into a ## DIRECTIVES / ## CONSTRAINTS / ## ALSO CONSIDER block, and returns the formatted text along with the engram IDs for downstream feedback.

Return shape:

{
session_id: string,
engrams: {
text: string, // ready-to-paste system-prompt block
count: number,
injected_ids: string[] // for plur_feedback later
},
store_stats: {
engram_count: number,
episode_count: number,
pack_count: number
},
guide: string // short instruction back to the agent
}

Gotchas:

  • Calling plur_session_start twice in the same conversation is harmless but produces a new session ID — episodes can get split across IDs. Prefer one start per task.
  • An empty task (e.g., the user’s first message is “hi”) still works; injection falls back to high-activation pinned engrams.

End a session, capture summary and learnings.

plur_session_end(
session_id?: string,
summary: string,
engram_suggestions: EngramSuggestion[]
) → SessionEndResult

When agents call it: before the conversation wraps up. engram_suggestions is a list of typed assertions the agent learned during the session (“user prefers terse responses,” “this codebase uses Caddy not nginx,” …). The server runs each suggestion through dedup, classification, and the candidate → active pipeline.

What happens server-side: writes a final episode for the session, processes each suggestion (some are auto-accepted, some become candidates pending recurrence), and updates activation for any engrams that were injected and not corrected.

Gotchas:

  • Don’t dump every thought as a suggestion. The bar is “I’d want this engram on Monday morning.” Filter aggressively before calling.
  • If session_id is omitted, the server uses the most recent open session for the calling agent.

Save an engram. The explicit write path, parallel to the CLI’s plur learn.

plur_learn(
statement: string,
type?: "behavioral" | "terminological" | "procedural" | "architectural",
domain?: string,
scope?: string,
tags?: string[],
rationale?: string,
commitment?: "exploring" | "leaning" | "decided" | "locked",
pinned?: boolean,
source?: string,
locked_reason?: string
) → LearnResult

When agents call it: any time the user says something the agent should remember — corrections (“from now on, X”), preferences (“always Y”), conventions (“we name files Z”). With adapter hooks, this fires automatically; without hooks, the agent should call it explicitly whenever the user uses correction language.

Return shape:

{ engram: Engram, _next: "plur_feedback", _related: [...] }

Gotchas:

  • A self-contained statement is critical. “Always validate input at API boundaries” beats “Do that.”
  • commitment defaults to leaning — fine for most. Reserve locked for safety/operating principles you never want to drift away from.
  • Setting pinned: true makes the engram always-load — see Activation & decay.

The default search. BM25 + local embeddings + Reciprocal Rank Fusion. Fully local, zero API cost.

plur_recall_hybrid(
query: string,
domain?: string,
scope?: string,
limit?: number, // default 20
include_episodes?: boolean
) → RecallResult

When agents call it: before answering a factual question the user asks, especially anything project-specific. The PLUR convention is “check memory before guessing” — if plur_recall_hybrid returns relevant engrams, cite them; if it returns nothing, fall back to other tools.

Return shape:

{
results: Array<{
id: string,
statement: string,
type: string,
scope: string,
domain?: string,
retrieval_strength: number,
score: number, // RRF-fused score
episode_summary?: string // if include_episodes
}>,
count: number,
truncated: boolean,
mode: "hybrid"
}

Gotchas:

  • limit > 100 rarely helps and starts to bloat latency from embedding scoring.
  • For a sub-100ms keyword-only path, use plur_recall instead.

BM25 keyword search. Instant; no embedder needed.

plur_recall(query: string, scope?: string, domain?: string, limit?: number) → RecallResult

When to choose this over hybrid: latency-sensitive paths (inline tab-completion suggestions, real-time autocompletes), or when you know the exact word the engram uses. Otherwise default to plur_recall_hybrid.

Load relevant memories for a current task — returns a structured block ready to drop into a system prompt.

plur_inject(task: string, max_engrams?: number, max_tokens?: number) → InjectResult
plur_inject_hybrid(task: string, max_engrams?: number, max_tokens?: number) → InjectResult

Difference from recall: recall returns by relevance to a query string. inject returns budget-aware, diversity-aware results suitable for prepending to context. The hook layer calls inject_hybrid automatically; agents rarely call it themselves.

When agents call it manually: when starting a sub-task within a session that’s substantively different from the session task (plur_session_start already injected). Example: mid-conversation pivot from “fix login bug” to “deploy frontend” — call plur_inject_hybrid("deploy frontend") to refresh context.

Rate an engram. Trains future recall.

plur_feedback(id: string, signal: "positive" | "negative") → FeedbackResult

When agents call it: at the end of a turn or session, for engrams that were injected at session start. Positive when the engram visibly helped; negative when it was off-topic or contradicted. Hooks emit implicit feedback automatically; the explicit call is reserved for the unambiguous cases.

Return shape:

{ engram_id: string, activation_delta: number, ok: true }

Gotchas:

  • One feedback signal moves activation a small amount; the loop matters at volume, not per-call.
  • Negative signals are weighted ~3× stronger than positive — calibrate accordingly.

Retire an engram. History preserved; eligible for un-retirement.

plur_forget(id_or_query: string, reason?: string) → ForgetResult

When agents call it: when a saved rule was wrong (not just outdated — outdated engrams decay naturally). Include a reason so the audit trail makes sense later.

Promote a candidate engram to active.

plur_promote(id: string) → PromoteResult

Candidates are engrams created by auto-extraction that need confirmation. plur_promote makes one active immediately — useful in workflows where you ingest a batch (plur_ingest) and then promote selectively after review.

Record an episode (timestamped event).

plur_capture(
summary: string,
channel?: "session" | "hook" | "incident" | "mcp" | "webhook",
agent?: string,
links?: string[] // engram IDs to associate
) → CaptureResult

When agents call it: anything you’d put in an event log — deploys, incidents, decisions, agent-emitted milestones. Hooks call plur_capture automatically at afterTurn / on_session_end; explicit calls are for application-driven events.

Query episode history.

plur_timeline(
from?: ISO-date,
to?: ISO-date,
agent?: string,
channel?: string,
session?: string,
limit?: number
) → TimelineResult

When agents call it: post-mortem questions (“what happened in this session before the failure?”), weekly-review questions (“what got captured in incident channel last week?”). Pair with plur_recall_hybrid for the engrams that correspond to those episodes.

Promote a recurring episode into an engram.

plur_episode_to_engram(episode_id: string, type?: EngramType) → LearnResult

When agents call it: post-mortem distillation. When an incident timeline reveals a recurring failure mode, promoting the lesson into an engram makes it persist and inject next time.

Extract engrams from arbitrary text.

plur_ingest(
text: string,
domain?: string,
scope?: string,
auto_promote?: boolean
) → IngestResult

When agents call it: meeting transcripts, ADRs, post-mortem write-ups, slack threads — anything narrative-shaped that contains engram-worthy lessons. The server runs an extractor LLM (or pattern-matcher in zero-LLM mode), surfaces candidates, and (by default) leaves them as status: candidate for review.

Return shape:

{ candidates: EngramSuggestion[], extracted: number }

Gotchas:

  • auto_promote: true writes directly to active. Only use on trusted input.
  • Long inputs are chunked — extraction is per-chunk so context can be lost across chunk boundaries. Provide structured input where possible.

Distil cross-domain principles from your engrams. Looks for patterns that appear in multiple engrams (e.g., “validate at boundaries” appears in API, deploy, and DB engrams → meta-engram).

plur_extract_meta(scope?: string, min_examples?: number) → ExtractMetaResult

When agents call it: rarely directly; usually as part of a scheduled maintenance pass. The Enterprise admin dashboard exposes this as a button.

List extracted meta-engrams.

plur_meta_engrams(limit?: number) → MetaListResult

Test a principle against a new domain.

plur_validate_meta(meta_id: string, domain: string) → ValidateMetaResult

Returns a confidence score for whether the meta-engram applies to engrams in the target domain — useful when porting principles between projects.

Health check.

plur_status() → StatusResult

Returns: storage path, engram count, episode count, embedder health, index status, hook installation. The same shape as plur status --json from the CLI.

When agents call it: the user asks “is PLUR working?” or the agent suspects something’s off (tools silently returning empty results).

Diagnose embedder, hooks, MCP config, permissions.

plur_doctor() → DoctorResult

Detailed diagnostic — each red line includes a fix command. Same as CLI plur doctor.

Sync engrams across machines via git.

plur_sync(remote?: string) → SyncResult

First call requires remote; subsequent calls reuse it. The MCP path is functionally identical to the CLI’s plur sync — see Sync for the full conceptual walkthrough.

plur_packs_install(source: string) → PacksInstallResult

source can be a local path, URL, or pack identifier (@plur-ai/datacore-conventions). The server verifies the integrity hash before importing; conflicts are surfaced for review.

plur_packs_list() → PacksListResult
plur_packs_uninstall(name: string) → PacksUninstallResult

Retires the engrams that came from the pack — history preserved.

plur_packs_export(
scope?: string,
ids?: string[],
out: string,
version: string,
target_scope?: string
) → PacksExportResult

Either scope or ids is required. Writes the pack directory with a manifest including the computed integrity hash. See Building a Knowledge Pack.

plur_packs_discover() → PacksDiscoverResult
plur_packs_preview(source: string) → PacksPreviewResult

discover hits the static community index; preview inspects a pack’s contents without installing.

Connect to a remote PLUR store (typically a PLUR Enterprise server).

plur_stores_add(
name: string,
url: string,
token: string // API key from /me/api-keys
) → StoresAddResult

After this, your local PLUR can read from and write to scopes you have access to on the named store. Personal engrams (global, project:*, user:*) stay local; shared scopes (group:*, org:*) hit the server.

plur_stores_list() → StoresListResult

Every tool returns a JSON object with:

{
...payload,
_next?: string, // most logical next tool
_related?: string[] // 2-4 related tools
}

_next is contextual: a successful plur_learn suggests plur_feedback; a failed plur_recall suggests plur_inject. Agents can follow these hints without further prompting — the navigation graph is implicit in the responses.

All tool errors are returned as MCP error objects with a stable code:

{ error: { code: "INVALID_SCOPE", message: "...", details: {...} } }

Common codes: INVALID_SCOPE, NOT_FOUND, PERMISSION_DENIED, EMBEDDER_UNAVAILABLE, INTEGRITY_MISMATCH (pack install), VALIDATION (bad input).

When the MCP server is @plur-ai/enterprise, every tool call goes through permission-wrapper.ts — the user’s resolved scope set is checked against the requested operation server-side. Local @plur-ai/mcp has no permission layer (single user); the tool surface is identical so agents work the same in both modes.

Do not rename these tools. Agents trained on PLUR — including the engram store itself, which references tool names in stored engrams — expect exact names. If you’re building a custom adapter, preserve the names verbatim.