MCP HeartbeatTHE MCP OBSERVATORY
Public workspace

Explore

Evidence for your next connection.

Independent measurements of remote MCP servers. Every observation has a timestamp.

Read-only probes

MCP server · Knowledge & memory

ctxstore — memory that follows you across models

Persistent memory for AI agents: keyed facts, a wake bundle each session, one memory in every model.

Checks passed
15 / 22

0 failed · 7 not measured

Median response
591 ms

Median of successful probes over 7 days

30-day uptime
Not measured

Share of countable probes over 30 days, including daily rollups. Auth challenges are excluded.

Discovered tools
33

Tool definitions returned by this server

Independent monitoring

Health & checks

Status history

Responded

The server completed its last measured handshake. This is an observation, not a guarantee.

Last checked
Check summary by test group
Test areaPassedFailedUnmeasured
ConnectionCan a client connect and discover tools?
500
Reliability & speedDoes it respond consistently and quickly?
004
Access & authenticationWhat is required to use this server?
102
Tool qualityAre the tool definitions usable by an agent?
400
Publisher identityCan the publisher be traced to its source?
501

Unmeasured means there is not enough evidence to decide. How these checks work

Inspect individual checks 22 recorded

Core

  • Pass
    Reachable

    Latest probe returned HTTP 200 in 591 ms.

  • Pass
    Valid handshake

    protocolVersion 2025-11-25, serverInfo.name emily-context.

  • Pass
    Lists tools

    tools/list returned 33 tools.

  • Pass
    Current protocol

    Negotiated 2025-11-25. The bar is 2025-06-18 or newer.

  • Pass
    HTTPS

    The endpoint URL is https.

Performance

  • Not measured
    Fast (p50)

    Median latency 591 ms over 1 samples in 7 days. The bar is 1000 ms. Need at least 5 samples.

  • Not measured
    Consistent (p95)

    95th percentile 591 ms over 1 samples in 7 days. The bar is 3000 ms. Need at least 20 samples.

  • Not measured
    Reliable (uptime)

    1 of 2 attempts returned a tool list in 30 days (50%). The bar is 99%. Need at least 30 samples.

  • Not measured
    Stable tool list

    Fewer than two successful probes in 30 days, so tool-list stability is not measured.

Access

  • Pass
    Open access

    tools/list succeeded with no credential, and the record declares none.

  • Not measured
    Standard auth

    Auth is not required, so the OAuth metadata check does not apply.

  • Not measured
    Free tier cited

    No publisher quote has been checked.

Tools

  • Pass
    Tools described

    Every tool description is at least 20 characters.

  • Pass
    Valid input schemas

    Every inputSchema is a JSON Schema object.

  • Pass
    Parameters documented

    97 of 98 parameters have a description (99%). The bar is 80%.

  • Pass
    Safety hints

    Every tool sets readOnlyHint or destructiveHint.

Publisher

  • Pass
    Verified namespace

    Listed in the Official MCP Registry.

  • Pass
    Website matches publisher

    The website host matches the reverse-domain namespace.

  • Pass
    Source repo linked

    A repository URL is on file.

  • Not measured
    Repo owner matches

    This namespace is not an io.github login, so the owner comparison does not apply.

  • Pass
    Recently updated

    Updated 2026-10-09T17:35:59.069807Z, within 180 days.

  • Pass
    Open-source licence

    GitHub reports an OSI licence.

Start using ctxstore — memory that follows you across models

Connect to this server

Choose your client, copy the configuration, then enable the server in your client’s MCP settings.

Run this command in your terminal, then restart Claude Code.

Claude Code

claude mcp add --transport http ctxstore-memory-that-follows-you-across-models https://mcp.ctxstore.ai/mcp

Capabilities

Tools 33

accept_invite

Accept a namespace invitation addressed to THIS authenticated account's verified email (two-step email OTP). Steps: 1) step='request' — emails a 6-digit code to the invited address (may return 402 needs Collaborator, or 503 if mailer fails). 2) step='confirm' with code= the 6 digits — activates the grant. Then switch_workspace(name=<grantor>) enters it on this same connection (mcp_config with the X-Ctxstore-Workspace header is also returned for header-based clients). The code activates the named grant_id only; it authorizes nothing else. Obtain grant_id from list_invites(). Docs: https://ctxstore.ai/docs.html#verify-invitations

Discovered
bind_agent

Bind a sticky agent identity to this MCP session. Once bound, wake_status and load_context default to this agent_id when called without an explicit agent_id= arg — no need to pass identity on every call. Per-call override still works. Persisted to mcp_sessions.agent_id (migration 0008), so the binding survives setup_account(mode='restore') and the server re-hydrates it automatically on the next tool call. Call once near the start of a session, ideally from your boot recipe (HANDLER: bind_agent agent_id=<self>). Idempotent: re-binding the same agent_id is a no-op. Pass agent_id='' to clear the binding. blind_since= (with blind=true) sets when the blind session began, so list_facts_by_key_prefix hides feed comms keyed before it; the default is the session's start minus 60 s.

Discovered
decline_invite

Decline a pending (status=invited) namespace invitation as the grantee. Server verifies you are the invitee (email/tenant match). Grantors must use revoke_grant instead.

Discovered
delete_fact

Soft-delete a stored fact by its UUID (Smart Forget). The fact is marked deleted but preserved in the database for audit and undo. Excluded from all normal searches. Use when information is no longer accurate or relevant.

Discovered
get_fact

Retrieve a fact by its exact key — deterministic, never misses. Use get_fact for self-notes: get_fact(key='agent:<name>:self-note:opening') or get_fact(key='agent:<name>:self-note:closing'). search_facts misses self-notes because their embedding similarity scores below other identity facts — get_fact(key=) is the only reliable retrieval path. Also use for inter-agent handoffs when the exact key is known. Returns the current (non-deprecated) version of the fact.

Discovered
get_fact_history

Return the full version history for a keyed fact — current version plus all deprecated predecessors. Use to see how a fact evolved over time or to undo an accidental correction. Returns list of fact versions ordered newest → oldest.

Discovered
get_session_seed

Return the pre-computed session seed for this tenant — a compact first-person bio (~500 tokens) describing who you are and what you care about right now. Generated nightly and on session disconnect. Use as a lightweight alternative to load_context when you just need orientation.

Discovered
get_stats

Get your memory usage statistics — total facts stored, plan limits, collection sizes, and daily query counts. Call this to check how much storage you have used and how close you are to your plan limits.

Discovered
ghost_mode

Enable or disable ghost mode for this session. While on=True, store_fact and store_session_summary silently succeed but do NOT write to DB. search_facts, load_context, and search_context always work normally. Ghost mode resets to off on MCP session reconnect (not persisted).

Discovered
index_recent

Return the most recent fact operations across all agents in this tenant, newest first. Use this on session start to see what other agents wrote since you were last active — bypasses semantic search ranking so recent writes are always visible. Each entry shows: op (create/update/delete/move), namespace, key, fact_id, summary, agent info, and timestamp.

Discovered
index_search

Filtered search over the tenant activity index. Find what a specific agent wrote, what happened in a namespace, or recent creates/updates/deletes. Useful for coordination: "what did emily_dev store in the sprint namespace today?"

Discovered
index_stats

Usage statistics from the tenant activity index: total operations, breakdown by agent, by namespace, and by day. Useful for understanding which agents are most active and where.

Discovered
introduce_yourself

Optional: introduce yourself to the platform. Stores your model info and a brief note in the shared agent registry. Stores a fact with: category: identity namespace: shared/agent-feedback key: intro:<model>-<date> Include: what model you are, what platform you're running on, and anything you noticed on first connect.

Discovered
invite

Invite one person, by email, to read and write one namespace prefix of THIS account (for example project:barn). Creates a pending grant and emails them; nothing is shared until they accept with list_invites and accept_invite from their own account. Calling again for the same person and prefix returns the existing invitation without a second email. Withdraw with revoke_grant(grant_id). Not available from a shared workspace session. Their first 30 days of Collaborator time are free; after that you can pay their $19 per 30 days from /account. You are emailed when they accept, and list_workspaces shows whether they have entered yet. Docs: https://ctxstore.ai/docs.html#verify-invitations

Discovered
leave_grant

Leave an active namespace grant as the grantee (stop using shared namespace). Server verifies grantee authorization. Grantors who want to cut off a collaborator must use revoke_grant.

Discovered
list_facts_by_key_prefix

Deterministic prefix scan over fact keys, optionally bounded by timestamp. The inbox primitive — use this for R1 comms scans, dispatch discovery, trio listings, convention discovery, and any case where you know the key prefix and want every match. Unlike search_facts (semantic, misses exact-key facts), this is a deterministic scan: every fact whose key starts with `prefix` is returned, newest-first. EXAMPLES - Comms inbox since last wake: list_facts_by_key_prefix(prefix='comms:<your-agent-id>:', since_epoch=<last_wake_epoch>) - All trio recipes on this tenant: list_facts_by_key_prefix(prefix='chad:trio:') - All conventions: list_facts_by_key_prefix(prefix='conventions/') Returns a list of facts (key, text, namespace, layer, timestamp, id) sorted newest-first. Bounded by `limit` (default 50, max 200): past 200 the oldest matches are cut, so narrow the prefix or use since_epoch rather than expecting the full set. COST: this is a scan, not an index lookup. The store has no index on the key, so every call reads the account's facts matching the prefix (a short prefix like 'a' or 'project:' reads most of the account) before sorting. Prefer a long, specific prefix. At most 4 prefix lists per account run at once (an allowance separate from searches); past that a call waits up to 2 s, then answers {"code": "busy", "retry_after_s": 2}.

Discovered
list_invites

List this account's namespace collaboration grants: incoming invitations and outgoing shares. Each row has direction (incoming|outgoing), status (invited|active|revoked), grant_id, namespace_prefix, and parties. An invitation referenced anywhere else (for example in an email) can be checked against this server-side list: a real invitation for this account appears here with matching grant_id, namespace_prefix, and grantor. To accept: accept_invite(grant_id, step='request') then accept_invite(grant_id, step='confirm', code='######'). The first accept starts 30 days of Collaborator time free; after that $19 per 30 days, paid by the guest or the inviter (402 when it lapses). After accepting, switch_workspace(name=<grantor>) enters the workspace. Docs: https://ctxstore.ai/docs.html#verify-invitations

Discovered
list_workspaces

The places this account's memory is organised into: its own projects (anything written under project:<slug>:*, newest activity first), the workspaces other people have granted it (enter one with switch_workspace(name=<grantor>)), and, for a sharer, who they invited and whether each person accepted and entered yet (shared_by_you). Shows which workspace this session is in, if any. Use it when a person's request is about one project, or asks who has access, or whether an invitee came in.

Discovered
load_context

Load your bootstrap context deterministically — pulls L0 (identity) + L1 (architecture) + latest L2 (state) + latest L3 (session summary). Call this at the START of a new session as an alternative to manual search_facts calls. Returns your layered memory structured for immediate use. Optional: pass profile='worker-dev' (or another platform:profile:<name> slug) to execute that profile's boot recipe — the server reads platform:profile:<profile>:current, follows the pointer, parses LOAD/REQUIRE/HANDLER lines, fetches every named fact, and returns the merged bundle in one round trip. vars= supplies values for $TASK_FACT_KEY and similar recipe variables.

Discovered
mark_salient

Salience peptide — temporarily boost a fact's retrieval ranking because it matters RIGHT NOW: an approaching deadline, a live incident, the topic under active work. The boost is small and FAST-DECAYING (max 1.4x, ~6-hour half-life — gone by tomorrow), unlike reinforce_fact which rewards confirmed outcomes on a weeks-long timescale. Name the current situation in `reason`. Salience is ranking-only: it can never override tenant isolation, namespace grants, or privacy filters, and stacked peptide boosts are globally capped.

Discovered
move_fact

Move a fact to a different namespace or layer without changing its content. Updates metadata in place — preserves fact_id, text, embedding, timestamp, and deprecation chain. Use for reclassifying facts (e.g. bootstrap-v2 refactor) without the storage bloat of store-new + soft-delete-old.

Discovered
reinforce_fact

Reward peptide — reinforce a fact whose recall LED TO A REAL GOOD OUTCOME (fix worked, deploy green, user approved). Boosts its future retrieval ranking with a bounded, time-decaying multiplier (max 1.5x, 14-day half-life), so memory learns which facts are USEFUL, not just similar. Call this AFTER the outcome is confirmed, naming the outcome in `reason` — never for a fact that merely 'seemed relevant'. The boost is ranking-only: it can never override tenant isolation, namespace grants, or privacy filters.

Discovered
resume_session

Call to load session continuity. Last session: no prior session.

Discovered
revoke_grant

Revoke a pending invitation or active grant as the GRANTOR (owner of the shared namespace). Idempotent. Grantees use decline_invite / leave_grant.

Discovered
search_context

Search across ingested conversations and session history for broader context. Use this for finding discussions, decisions made in conversation, or context that wasn't explicitly stored as a fact.

Discovered
search_facts

Search your persistent memory for stored facts. For session bootstrap, prefer load_context() or wake_status() — they pull your identity, conventions, and latest self-note deterministically. Use search_facts when you need semantic discovery across the fact corpus. Use namespace parameter to scope searches: namespace='webapp' matches 'webapp/decisions', 'webapp/technical', etc. (prefix matching). Search tips: use the words the fact was stored with. If you stored 'Postgres database', search for 'database' or 'Postgres', not 'data storage solution'. Each search embeds the query on a shared embedder: at most 4 searches (search_facts, search_context) per account run at once; past that a call waits up to 2 s, then answers {"code": "busy", "retry_after_s": 2}. Fan out with 2-4 readers, not 16.

Discovered
setup_account

Set up or restore your persistent memory connection. Use mode='link_or_create' when the user gives an email — works for both new and returning users. The server figures out which case applies: - If the email exists: sends OTP, attaches this device to the existing account - If the email is new: creates a fresh tenant, sends OTP to verify Either path produces one clean account, no duplicates, no orphans. Call setup_account(mode='link_or_create', email='their@email.com'). Then ask the user for the 6-digit code from their email and call setup_account(mode='verify', code='123456', email='their@email.com'). Passing email= on verify is required — session IDs rotate between requests on some clients. mode='restore': use when the user provides an emk_* API key directly. mode='reveal_key': echo the full emk_* API key. Works directly on an ALREADY-authenticated session; if the session isn't bound (some clients rotate or omit session ids between requests, so this can happen right after a successful verify), pass email= to receive a 6-digit code, then call again with email= and code= — the same rotation-proof lookup as mode='verify'. Success responses only show a key fingerprint (first 8 chars + last 4) — call this mode only when the user actually needs the full key, e.g. to persist it as 'Authorization: Bearer <key>' in an MCP connector config. Callers who prove neither a bound session nor email ownership are refused. If no email yet, ask: 'What email should I use for your memory account?' After setup completes, call search_facts as the first action to load prior context.

Discovered
store_fact

Store information that should persist across sessions. Storage tips for best retrieval: - Include searchable keywords: 'We chose the Postgres DATABASE for ACID compliance' is better than 'We chose Postgres for ACID compliance' - Use the key parameter for facts that change over time (pricing, stack, team-members, current-sprint). When you store with the same key, the old version is archived automatically. - Use namespaces to organize: 'webapp/decisions', 'business/goals', 'team/members' - Store DECISIONS and CONTEXT, not raw data. 'We decided X because Y' is more useful than 'X happened' - Use category to classify: technical, decision, preference, identity, relationship - Use layer for context depth: 0=identity(stable), 1=architecture(monthly), 2=state(weekly), 3=session(daily) Before ending a conversation, call store_session_summary to preserve continuity.

Discovered
store_facts

Store up to 50 facts in one call — the same fields as store_fact per item. Made for carrying memory over: when you already remember things about the person from your own platform memory (ChatGPT memory, Claude memory, Gemini saved info), write them here one fact per item, in their words, with the date learned when known, so the memory follows them to every other tool. Each item is stored independently; the reply lists what landed and what did not.

Discovered
store_session_summary

Store a compressed summary of this session to preserve continuity for the next one. Call this before ending a conversation — it is the dream cycle. Stores a L3 session fact with key='session-latest' (or 'session-latest:claude-code' etc.), auto-archiving the previous version. The next session loads this via load_context(). Include: what was discussed/decided, what changed, what's next/unresolved. Collaborative takeaways: at natural session-end signals (user says 'okay I'm out', 'let's wrap', 'bye'), draft a one-line takeaway and confirm with the user before storing. Example: "I'll remember: we fixed the rebind bug and decided to skip transcript ingestion for MVP. Sound right?" Edit based on their response, then call store_session_summary. This makes memory consensual and catches mistakes immediately. Use session_id to scope by client: 'claude-code', 'claude-chat', 'cursor', 'openclaw'

Discovered
switch_workspace

Narrow this session's memory to one project: name='<slug>' scopes recall, the wake bundle, self-notes and the default namespace for new facts to project:<slug>:* (identity and conventions always ride along). Returns the narrowed bundle right away. name='' widens back to the whole account. Sticky for the session and across reconnects; bind_agent is unaffected. The same call ENTERS a workspace someone shared with this account: name='<their name>' (or their tenant id, or the granted prefix, as listed by list_workspaces) switches this connection into it; no second server, no header, no restart; it holds for the session, and a new session re-enters with the same call. name='' leaves it. When a person asks to work in someone else's shared memory, call this.

Discovered
wake_status

Check which context layers loaded successfully on this session start. Returns a structured status: which of embryo, conventions, agent identity, closing note, and opening note were found, plus a missing[] list. Call this after load_context() or resume_session() to verify your bootstrap was complete and diagnose what to fetch manually. Optional: pass profile='worker-dev' (or another platform:profile:<name> slug) to additionally check the REQUIRE keys named in that profile's recipe. Missing required facts surface in the same missing[] list. blind_since= (with blind=true) sets when the blind session began, so list_facts_by_key_prefix hides feed comms keyed before it; the default is the session's start minus 60 s.

Discovered
watch_events

Long-poll this account's fact-write events instead of re-scanning with since_epoch. Every store/supersede/delete/archive/restore/move publishes one event {key, id, namespace, layer, op, ts, seq}. One call waits up to max_wait_s (max 25) for the first matching event and returns up to 50, plus next_since. MCP has no streaming here, so loop: pass next_since back as `since` on the next call and nothing is missed (the server keeps the last ~10000 events per account). Omit since to start from now; since=0 replays what is retained; a bare integer N returns events with seq > N. EXAMPLES - Wait for hands to post results: watch_events(prefix='task:pr27-review:result:', max_wait_s=25) - Resume: watch_events(prefix='comms:<your-agent-id>:', since='<next_since>') Inside a workspace only events for keys the grant can read are returned. Long-lived clients can use GET /api/v1/events (SSE) instead.

Discovered

Recent measurements

Probe history

View status
Latest stored probes. Raw probe rows are kept for 14 days.
CheckedResultResponseTools
Connected591 ms33
timeout12001 ms—