Skip to content
Contextely

Machine surface

MCP server

Contextely speaks JSON-RPC 2.0 over the MCP Streamable HTTP transport at https://www.contextely.com/api/mcp. It is stateless: every call carries its own credential, so there is no session to resume and a dropped connection is a non-event.

Connect

{
  "mcpServers": {
    "contextely": {
      "url": "https://www.contextely.com/api/mcp",
      "headers": { "Authorization": "Bearer ctx_sk_..." }
    }
  }
}

Create a key under API keys in the dashboard. The key speaks as one member and is scored against that member's entitlement scopes.

Tools

context_search

counts against your retrieval allowance

The main call. Searches the workspace's condensed working memory and returns what this asker is entitled to see, refreshing anything past its freshness TTL from its system of record first.

REST equivalent: POST /api/v1/search

Arguments

  • query string (required): What you want to know, in natural language.
  • limit integer: 1-50, default 8.
  • skip_refresh boolean: Serve stored memory without a freshness check. Faster; may be stale.
  • subject string: Search only this end customer's memory. Omitted, memory that has a subject is never returned.
  • filters string: An object: metadata (key to value or any-of list, ANDed across keys) and topics_any.

context_related

Walk from one memory object to its neighbours, ranked by shared entities, then topics, then keywords. Use it when one search result is the right thread and you want the rest of it. A neighbour outside the asker's scopes is never named or counted.

REST equivalent: GET /api/v1/memory/{id}/related

Arguments

  • id string (required): The memory object to find neighbours of.
  • limit integer: 1-25, default 5.

context_expand

counts against your refresh allowance

Read the full current record from the system of record a memory object was condensed from, for when the summary is not enough. No model is involved, so it returns exactly what the source says. Costs one source round-trip, metered against the monthly refresh allowance.

REST equivalent: POST /api/v1/memory/{id}/expand

Arguments

  • id string (required): The memory object to expand.

memory_get

Fetch one memory object by id. Returns not_found rather than forbidden when the asker is not entitled to it, so probing for ids cannot reveal what exists.

REST equivalent: GET /api/v1/memory/{id}

Arguments

  • id string (required): Memory object id.

sources_list

List the connected systems of record with their freshness policies, sync status, and whether this asker is entitled to anything from each.

REST equivalent: GET /api/v1/sources

Arguments

  • (none)

memory_add

Store a memory directly, without connecting a system of record. It is kept as written rather than condensed, its searchable terms are extracted locally with no model call, and it carries both a share list and whatever entitlement scopes you give it. It has no source, so it is never re-fetched and context_expand reports that there is nothing fuller to read. Give it review_after_seconds and it will be labelled overdue once nobody has confirmed it for that long. Its relations are built shortly after it is stored rather than during the call, so it returns immediately and reports graph_state.

REST equivalent: POST /api/v1/memory

Arguments

  • text string (required): The thing to remember.
  • title string: Optional label. Derived from the first sentence if omitted.
  • scopes string: Scopes required to read it back. Omit for workspace-wide.
  • topics string: Optional subject labels.
  • key string: Your own id. Reusing it replaces rather than duplicates.
  • review_after_seconds integer: How long it stays trusted. Past it, results label it stored_unreviewed. Omit for no window.
  • visibility string: private, team or workspace. Omit to take the workspace's default.
  • share_with_teams string: Team ids to share with, when visibility is team.
  • subject string: End-customer partition. Part of the key: the same key under two subjects is two memories.
  • metadata string: An object of flat labels, up to 32 keys and 4KB.

source_tools_list

The passthrough reads this caller may make. A tool an admin has not classified as a read never appears, and neither does one whose entitlement scopes the caller does not hold.

REST equivalent: GET /api/v1/source-tools

Arguments

  • query string: A few words to narrow the list. Without it the whole list comes back, which can be very large.
  • limit integer: 1-100, default 25 when a query is given.

source_tool_call

counts against your refresh allowance

Performs one passthrough read. Entitlement is checked at entry and again immediately before the round-trip, the allowance is charged only when an answer came back, and every call, refusals included, is recorded in the passthrough log. The result is not ranked and not stored.

REST equivalent: POST /api/v1/source-tools/{name}/call

Arguments

  • name string (required): The tool's name.
  • args string: The arguments, as an object.

workspace_usage

Plan, metered usage and remaining allowance for the month. Call it before a batch run to decide whether to proceed or back off.

REST equivalent: GET /api/v1/usage

Arguments

  • (none)

actions_list

The enabled actions the caller may invoke. Proposed and disabled actions never appear, and neither do actions whose required write scopes the caller does not hold.

REST equivalent: GET /api/v1/actions

Arguments

  • (none)

action_preview

Validates arguments and returns a rendered description plus the request hash, without contacting the source. It reports upstream_dry_run:false rather than simulating an effect, because a fabricated preview is indistinguishable from a real one.

REST equivalent: POST /api/v1/actions/{name}/preview

Arguments

  • name string (required): The action's name.
  • args string: The arguments, as an object.

action_invoke

counts against your refresh allowance

Performs one enabled action. Entitlement is checked at entry and again immediately before the effect; the allowance is charged only when it reaches upstream; and every attempt, refusals included, is recorded in the action log.

REST equivalent: POST /api/v1/actions/{name}/invoke

Arguments

  • name string (required): The action's name.
  • args string: The arguments, as an object.
  • idempotency_key string (required): Required. A server-generated key is not a replay guard.

graph_search

counts against your retrieval allowance

Runs a normal search, then follows the relationships outward from the memory it found and returns them as triples. Every triple carries the memory object that asserted it, so nothing here is a claim without a source. The walk is bounded (depth, and a cap on how many relationships are followed from any one thing) so its cost does not grow with the size of your graph, and a relationship you are not entitled to read is never followed, never returned, and never uses up that budget.

REST equivalent: POST /api/v1/graph/search

Arguments

  • query string (required): What you want to know.
  • depth integer: Hops to follow, 1 to 3. Default 2.
  • limit integer: Maximum triples. Default 50.
  • include_structural boolean: Include bookkeeping edges. Off by default.

graph_neighbours

The neighbourhood of one memory object or one named entity, as triples with the memory that asserted each. Give it an id when you have one and a name when you do not; a name resolves to the closest few nodes by how connected they are. Nothing is returned that the asker could not have read directly.

REST equivalent: POST /api/v1/graph/neighbours

Arguments

  • id string: Memory object id to start from.
  • name string: Entity name to start from instead.
  • depth integer: Hops to follow. Default 1.
  • limit integer: Maximum triples. Default 30.

memory_history

The version chain behind one memory object. Each entry carries valid_from and valid_to, so you can see exactly what was believed when, and an object still in force has a null valid_to. Absent or unentitled answers not_found, like every other read.

REST equivalent: GET /api/v1/memory/{id}/history

Arguments

  • id string (required): The memory object id.

memory_forget

Removes a memory object, or only the relationships derived from it. It needs the same memory-write permission as storing one, because a key that can erase a company's memory is a key that can change what its agents believe. It cannot reach a system of record, so a sourced memory returns on the next sync.

REST equivalent: POST /api/v1/memory/{id}/forget

Arguments

  • id string (required): The memory object id.
  • graph_only boolean: Discard the relationships only, and rebuild them.

session_record

Opens or continues a session and records one turn in it, with the memory objects the answer used. Sessions are what the activity dashboard groups by and what feedback attaches to. Nothing here changes a ranking on its own: it becomes a weight only once somebody rates the turn and the improve pass runs, and only if the deployment has set a feedback influence.

REST equivalent: POST /api/v1/sessions/record

Arguments

  • session string: Your own id for the run. Reuse to continue it.
  • kind string: recall, remember, tool or action. Default recall.
  • query string: What was asked.
  • used_memory_ids string: The memory ids the answer used.
  • client string: What you are, e.g. claude-code.

session_feedback

Rates one turn. Ratings are folded into the memory objects that turn used by the improve pass, as an exponential moving average, so one rating nudges and five consistent ones move a weight visibly. A rating can demote a memory and can never remove it, because removal is an entitlement decision and this is not one.

REST equivalent: POST /api/v1/sessions/feedback

Arguments

  • turn string (required): The turn id from session_record.
  • score integer (required): 1 to 5.
  • note string: Optional free text for a person.

What a search returns

{
  "query": "acme renewal date",
  "results": [
    {
      "id": "…",
      "title": "Acme renewal terms",
      "summary": "Acme renews 2027-01-31 at $48,000/yr…",
      "citation_url": "https://crm.internal/accounts/acme",
      "sourceName": "Production CRM",
      "score": 0.412,
      "matchedTerms": ["acme", "renewal"],
      "freshness": {
        "last_fetched_at": "2026-08-18T14:02:11Z",
        "ttl_seconds": 900,
        "state": "refreshed"
      }
    }
  ],
  "entitlement": {
    "asker": "[email protected]",
    "role": "member",
    "scopes": ["sales"],
    "withheld_for_entitlement": 2
  },
  "freshness": { "refreshed": 1, "refresh_failed": 0 }
}

Read withheld_for_entitlement. When it is above zero, relevant context existed that this asker may not see. A well-behaved agent says so, with “there may be more here that needs finance access”, rather than answering confidently from a partial picture.

Read freshness.state. fresh and refreshed mean the fact was verified within its TTL. stale_refresh_failed means it could not be verified, and the attached warning says why. stored was given to us directly and has no source to check against; stored_unreviewed is the same and is also past a review window, which nothing can clear except somebody storing it again.

Read matched_by before deciding a result is odd. lexical matched your words. semantic matched by meaning, so it has an empty matched_terms, which is the ranking working rather than failing. Semantic ranking runs only where a deployment has named an embedding model, and the ranking block on every response says which mode produced it.

Errors

A tool that fails for a caller-fixable reason returns a normal tool result with isError: true and a machine-readable code, so an agent can branch rather than parse prose. quota_exceeded means back off or upgrade; not_found means never retry. An invalid credential is a transport-level JSON-RPC error.