MCP Server

Estratos is a Model Context Protocol (MCP) server, so AI assistants can work with your workspace's memory. Use it with Claude, Codex, Copilot Cowork, or any MCP-compatible client.

  • Endpoint: POST https://estratos.ai/mcp
  • Auth: OAuth 2.1 Bearer tokens (or an API key), with the same scopes as the REST API
  • Requires: the api-access entitlement on your workspace's plan

Just want to connect an agent? The Connecting agents section has step-by-step guides for Claude Desktop, Codex, Copilot Cowork, and generic MCP clients. This page is the protocol-level reference: the tools, scopes, and discovery documents.

Connecting

For most clients you install the Estratos Memory plugin from a marketplace; generic clients point at the raw endpoint. The first connection runs a one-time OAuth consent in your browser where you pick a workspace — no client ID or API key in any config.

  • Claude Desktop / Claude Code — add the plugin marketplace at https://estratos.ai/plugins. In Claude Code: /plugin marketplace add https://estratos.ai/plugins then /plugin install estratos-memory@estratos.
  • Codex, Copilot Cowork — add the same marketplace source from the client's plugin browser.
  • Any other MCP client (Cursor, MCP Inspector, …) — give it the URL https://estratos.ai/mcp and approve the consent. See OAuth discovery below for what happens automatically.

Connecting with an API key

For headless setups — scripts, CI, or clients without OAuth support — use an API key instead. Workspace owners create one under API Keys in the sidebar (grant it the memories:read, memories:write, and/or memories:delete scopes for the memory tools). Configure your client to send the key as a Bearer token:

{
  "mcpServers": {
    "estratos": {
      "url": "https://estratos.ai/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_API_KEY"
      }
    }
  }
}

API keys are long-lived, so there's no refresh step — but they're a static secret. Treat them like any credential, and revoke them from the API Keys page if they leak.

The six memory tools

Estratos exposes exactly six memory tools. All six are always listed; each enforces its own OAuth scope when called, so a token missing the required scope gets a clear "insufficient scope" error (not a missing tool). Two rules hold across every tool:

  • Paths address scopes, never individual memories. A memory body is only ever returned as part of a scope bundle. No tool returns a single memory by key, id, version, or a memory-suffixed path. The one per-memory handle any tool takes is the opaque memory_id on delete_memory, and only to delete.
  • Identity comes from the token. The workspace is determined by your access token; you never pass a tenant, account, or workspace argument. Unknown arguments are rejected.
Tool Required scope
describe_hierarchy memories:read
retrieve memories:read
list_memories memories:read
remember memories:write
remember_tagged memories:write
delete_memory memories:delete

Errors are returned as a JSON-RPC-shaped error object inside the tool result (with isError set). Two application codes appear: -32602 (invalid params) and -32002 (insufficient scope).

describe_hierarchy

Describe the active memory hierarchy for the connected workspace. Call this first, so an assistant learns the folder hierarchy before reading or writing.

  • Parameters: none.
  • Returns: the hierarchy version and status, the ordered array of layer slugs (layers), and layer_details — per-layer display_name, description, naming_guidance, examples, depth, and effective allow_tagged_memories. A brand-new workspace with no active hierarchy returns empty layers/layer_details and null version/status (a success, not an error).
  • Scope: memories:read.

retrieve

Retrieve every memory that applies to a scope path, as one Markdown bundle.

  • Parameters: path (string, required) — a dot-separated scope path such as root.pennine-joinery.vat. Canonical or aliased; never a memory address.
  • Behavior: walks from the root to the target, interleaving scoped, layer-wide tagged, then value-targeted tagged memories in a fixed order (see how retrieval works). Each block carries a header comment with its kind, title, key, memory id, and version. The requester's own pending content folds in for them only.
  • Returns: the concatenated Markdown bundle as text. Zero matches is a success whose text is the empty string.
  • Errors: a path that doesn't resolve to a live scope folder — malformed, unknown, archived, or with a memory suffix — returns invalid params. There is no single-memory fallback.
  • Scope: memories:read.

list_memories

List the memory metadata at exactly one scope folder.

  • Parameters: path (string, required) — the scope path whose memories to list.
  • Returns: metadata only — memory_id, title, key, kind, scope, version_number, and timestamps — for the scoped memories attached exactly at that folder. Plus the requester's own in-flight proposals at that folder (each with proposal_id, status, and action). Never any memory content, and never ancestors, descendants, or tagged memories (those surface only in a retrieve bundle). The returned memory_ids are management handles for delete_memory.
  • Errors: the path must already exist (canonically or via an alias); list_memories never creates a folder, so an unknown path is invalid params.
  • Scope: memories:read.

remember

Store a scoped memory at a folder scope path.

  • Parameters: path (required) — the scope path; title (required) — a concise sentence-case noun phrase the assistant generates from the content; content (required) — the memory body as Markdown.
  • Behavior: resolves the path against the active hierarchy, creating missing folders where the hierarchy allows, and derives a stable storage key from your title and scope (you never supply a key). Routes through the review workflow: a publisher's write publishes; a Basic user's write queues a proposal.
  • Returns: the canonical path, the status (published or queued_for_review), the stable key (a preview key for a queued proposal), the memory_id (published) or proposal_id (queued), and any folders_created.
  • Errors: a blank title or content, or an unresolvable path, returns invalid params.
  • Scope: memories:write.

remember_tagged

Store a tagged memory on a hierarchy layer, optionally restricted to one segment value.

  • Parameters: layer (required) — the layer slug (e.g. services); title (required); content (required); restricted_to (optional) — a segment value such as vat to target the memory; omit or leave empty for a layer-wide memory.
  • Behavior: resolves the layer against the active hierarchy. Rejects unknown layers, the structural root layer, and layers whose allow_tagged_memories is false. A concrete restricted_to resolves-or-creates that value; blank means layer-wide. Same publish-vs-propose routing as remember.
  • Returns: a scope descriptor (services for layer-wide, services=vat when value-targeted) plus the same status/key/id fields as remember.
  • Errors: an unknown layer returns invalid params listing the valid layer slugs; a layer that disallows tagged returns invalid params; blank title/content returns invalid params.
  • Scope: memories:write.

delete_memory

Soft-delete a memory by its opaque id.

  • Parameters: memory_id (required) — the id returned by list_memories. Not a path, key, or version.
  • Behavior: for a publisher, writes a tombstone version and marks the memory deleted (the version history is preserved). For a Basic user, queues a delete proposal — or, if they already have a pending delete on that memory, calling it again withdraws their own pending delete. Returns no memory content, ever.
  • Returns: a status (deleted, queued_for_review, or withdrawn) and the ids involved.
  • Errors: an unknown id, an id in another workspace, and an already-deleted id all return the same "memory not found" error, so the tool never leaks whether a memory exists.
  • Scope: memories:delete.

OAuth scopes

Tokens carry scopes that limit what they can do. The memory tools declare and enforce these per call; a token that acts through a user can never exceed that user's role.

Scope Grants Notes
memories:read describe_hierarchy, retrieve, list_memories Available to every role
memories:write remember, remember_tagged Available to every role; a Basic user's writes route through review
memories:delete delete_memory Available to every role; a Basic user's deletes route through review
memories:export Memory exports Available to every role
hierarchy:admin Reserved — hierarchy management Owner/Admin only
members:admin Reserved — member management Owner only
audit:read Reserved — audit log access Owner only
profile:read Baseline identity for the REST API See the API overview
webhooks:manage Webhook endpoint management (REST) See Webhooks

The MCP resource advertises and grants only memories:read, memories:write, and memories:delete — the three scopes its six tools enforce. Its Protected Resource Metadata lists exactly these three, and an authorization request that binds the canonical /mcp resource but asks for any other scope is rejected with invalid_scope. The remaining scopes (memories:export, hierarchy:admin, members:admin, audit:read, profile:read, webhooks:manage) stay valid on the authorization server and REST API but are neither offered on the MCP consent screen nor grantable against /mcp. Granting a scope to a token whose user doesn't hold the matching role has no effect anyway — the role sets the ceiling — and a role downgrade takes effect immediately: a token carrying a scope its user can no longer justify is denied on every call.

Protocol details

  • Endpoint: POST https://estratos.ai/mcp
  • Protocol: JSON-RPC 2.0 over HTTP, stateless (no server-side sessions)
  • Server name / version: estratos / 1.0.0
  • GET /mcp returns 405 Method Not Allowed (SSE streaming is not supported in stateless mode)
  • DELETE /mcp returns 204 No Content (no sessions to clean up)
  • Rate limits are shared with the REST API: 60 requests/minute and 500 requests/hour per token
  • A 401 from /mcp includes WWW-Authenticate: Bearer realm="Estratos", resource_metadata="…" per RFC 6750 — the entry point for discovery

OAuth discovery

Compliant clients discover everything from the endpoint alone. For client implementers, the pieces are:

  • Protected Resource Metadata (RFC 9728): /.well-known/oauth-protected-resource — declares the MCP endpoint a protected resource and names the authorization server, the three MCP scopes (memories:read, memories:write, memories:delete — a subset of the authorization server's full scope list), and this documentation.
  • Authorization Server Metadata (RFC 8414): /.well-known/oauth-authorization-server — publishes the authorize, token, revoke, introspect, and registration endpoints; the supported response types (code), grant types (authorization_code, refresh_token, client_credentials), PKCE method (S256), and token endpoint auth methods (client_secret_basic, client_secret_post, none).

Dynamic client registration

POST /oauth/register (RFC 7591) lets a client register itself without a human creating an app first — registration is open and rate-limited. Send at least a client_name and redirect_uris; the response returns a client_id (and a client_secret for confidential clients). Registering grants no data access — the consent at /oauth/authorize remains the real gate.

PKCE and resource indicators

For dynamically registered (public MCP) clients, two requirements are enforced at authorization time:

  • PKCE (RFC 7636) is mandatory, with code_challenge_method=S256.
  • Resource indicators (RFC 8707): the resource parameter is required and must equal the canonical MCP URL (https://estratos.ai/mcp). It's validated on both the authorize and token requests, and the token is bound to that resource, so it can't be replayed against another audience.

Access tokens expire after two hours and refresh automatically; refresh tokens last 30 days. When a token can't be refreshed (or is revoked), the client re-runs the consent.

Plugin marketplace manifest

Estratos publishes a Claude-compatible plugin marketplace manifest so clients can install Estratos Memory as a plugin rather than adding the MCP server by hand:

  • GET /plugins — the marketplace URL the Configure agents cards display
  • GET /.claude-plugin/marketplace.json — the well-known path some tooling fetches directly

Both serve identical content: a marketplace entry for the estratos-memory plugin whose only payload is an MCP server pointer at this deployment's /mcp endpoint. No client ID, secret, or API key goes in the manifest — it's the same OAuth auto-discovery described above, just installed as a plugin. See Connecting agents for the per-client install steps.

Next steps