On this page

Context

query-context

Run a read-only Cypher query against the project's context graph. Needs the fabric:query.read grant.

curl -sS -X POST https://fabric.wexa.ai/mcp/$FABRIC_PROJECT_ID \
  -H "authorization: Bearer $FABRIC_API_KEY" \
  -H "Mcp-Session-Id: $MCP_SESSION_ID" \
  -H "content-type: application/json" -H "accept: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"query-context","arguments":{"query":"MATCH (n) WHERE n.project_id = $project_id RETURN n LIMIT 1"}}}'
{
  "content": [
    {
      "type": "text",
      "text": "{\"lifecycle_id\":\"qlc_000167\",\"result\":{\"columns\":[\"n\"],\"row_count\":1,\"rows\":\"\\u2026\",\"stats\":{\"elapsed_ms\":240},\"truncated\":false}}"
    }
  ],
  "isError": false
}

Parameters

ParameterTypeRequiredNotes
querystringRequiredRead-only Cypher; must filter on project_id = $project_id. Write clauses are rejected.
parametersobjectOptionalValues the query refers to as $name; see passing values. Never project_id or project_ids.
limitintegerOptionalSets the LIMIT added when the query has none and caps any LIMIT it has. 1 or more; above 1000 is reduced to 1000. Without a LIMIT the server adds LIMIT 100.
timeout_msintegerOptionalQuery timeout in ms. A call has about 25 seconds in total, so values above about 25000 have no effect.
explainbooleanOptionalReturn the query plan instead of rows.
explain_denialsbooleanOptionalWhen your access profile hid rows or masked fields, also return a governance block naming them and the clearance each needed (never values).
Errors
  • UpstreamError (504): the call ran past about 25 seconds. See rows and time.
Show full response

A real response, captured from a live call to query-context:

rows came back populated and is shown as … here, because the real value runs to thousands of characters. Read it from your own call rather than from this page.

{
  "content": [
    {
      "type": "text",
      "text": "{\"lifecycle_id\":\"qlc_000167\",\"result\":{\"columns\":[\"n\"],\"row_count\":1,\"rows\":\"\\u2026\",\"stats\":{\"elapsed_ms\":240},\"truncated\":false}}"
    }
  ],
  "isError": false
}
More details

Full description from the tool, as the gateway advertises it:

Run a read-only Cypher query against this project's Wexa context graph. Queries must filter on project_id = $project_id (bound server-side). Write clauses are rejected. For CODE TEXT search (symbols, strings, file contents), use search-code then fetch-code — do NOT invent Cypher for that. query-context is for structural graph queries (callers, imports, ontology). For other large string properties (diffs, notes), prefer CALL db.index.fulltext.queryNodes('idx_codetext_fulltext', '\<terms\>') YIELD node, score over CONTAINS/regex.

Which projects a query reads

FilterReads
n.project_id = $project_idThis project, plus the projects that org-shared connectors and data sources shared with this project write into
n.project_id IN $project_idsEvery project you can access

The server binds both from your credential. On servers built before 10 October 2026, = $project_id also matched every other project you can access; to be sure of one project there, check project_id in the rows you get back. The map form (n {project_id: $project_id}) reads only this project. Do not put project_id or project_ids in parameters: a project_id other than your own is refused.

Passing values: parameters

rows = fabric.query_context(
    query="""
        MATCH (t:Ticket)
        WHERE t.project_id = $project_id
          AND t.status IN $statuses
          AND t.due >= $from AND t.due < $to
        RETURN t.id AS id, t.due AS due
        ORDER BY due
        LIMIT 200
    """,
    parameters={"statuses": ["open", "blocked"], "from": "2026-10-15", "to": "2026-10-29"},
)

Refer to each value as $name instead of pasting it into the query text. Range comparisons (>=, <, …) work on any property. Values are stored exactly as save-context received them: a number stays a number, and a date sent as text stays text. Text compares character by character, so a range filter on a date stored as text only works when the date is ISO 8601 (2026-10-15); 10/15/2026 sorts wrongly across months and years.

Rows and time

  • Rows: without a LIMIT the server adds LIMIT 100, and a LIMIT above 1000 is reduced to 1000. The limit argument sets the LIMIT added when the query has none and caps any LIMIT it has (1 or more; above 1000 it is reduced to 1000).
  • Time: a call has about 25 seconds in total; past that it answers 504 (UpstreamError in both SDKs). timeout_ms can only shorten that, so values above about 25000 have no effect.

The captured call returned one row, so the example shows rows as "\u2026", the value the capture holds in place of the row itself.

Marked consequential: it is audited in full, and a policy rule may hold it for a person to approve. See Policy and approvals.

Every tool call works the same way: How every tool call works.