mcpField
I
indykite-ciq-read

indykite-ciq-read

github.com/indykiteData & databases465 installsUpdated 3d ago
Repository

About indykite-ciq-read

An agent skill for creating read-only IndyKite ContX IQ policies and Knowledge Queries over the IndyKite Graph. It guides schema setup, execution, and result checks for teams retrieving graph data without enabling writes.

Key features

  1. 01Define Cypher patterns and subject filters
  2. 02Whitelist readable graph variables
  3. 03Create read-only Knowledge Queries
  4. 04Execute queries with parameters and paging
  5. 05Check returned rows and troubleshoot

Use cases

  1. 01Retrieve a person's related graph records
  2. 02Prepare queries for the IndyKite MCP server
  3. 03Debug empty or forbidden query results

MCP support

The skill explains that a Knowledge Query created with it can be run through the `indykite-mcp-server` `ciq_execute` tool. It also covers execution through the ContX IQ HTTP endpoint.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/indykite/skills --skill indykite-ciq-read

After installing, type/indykite-ciq-readin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

assets/
knowledge-query-read-cars.json
policy-read-cars.json
references/
execution-reference.md
knowledge-query-reference.md
policy-reference.md
scripts/
execute.sh

Details

From the project README

IndyKite ContX IQ - read-only policy + Knowledge Query

ContX IQ (CIQ) is IndyKite's context-aware data layer over the IKG — IndyKite's knowledge graph, a property-graph database queried with Cypher (the Neo4j / openCypher graph query language). A CIQ policy declares what graph elements may be touched and under what conditions; a CIQ Knowledge Query declares what to do with them; an execution call runs the Knowledge Query at runtime with concrete parameter values.

This skill covers the read-only path:

  • A policy whose condition.cypher matches nodes and relationships and whose allowed_reads whitelists the variables the Knowledge Query may return.
  • A Knowledge Query that lists those variables in nodes, relationships, and/or aggregate_values.
  • An execute call that supplies values for the policy's partial filters ($variable) and returns the rows.

allowed_upserts and allowed_deletes are intentionally out of scope here - leave them out entirely for read-only use.

When to use

Activate this skill when the user:

  • wants to read data from the IKG and shape the result through a CIQ policy + Knowledge Query;
  • is building the (workflow, agent_list) query the indykite-agent-gateway skill consumes from ContX IQ;
  • is preparing a Knowledge Query that the indykite-mcp-server skill will run via ciq_execute;
  • is debugging a read CIQ that returns nothing or 403s for a subject that should have access.

Do not activate this skill when the user:

  • needs to create, update, or delete nodes or relationships through CIQ - that uses allowed_upserts / allowed_deletes and upsert_* / delete_* Knowledge Query fields, which this skill leaves out for clarity;
  • is calling AuthZEN for a yes/no authorization decision (use authzen_evaluate and the MCP skill);
  • is calling the External Data Resolver to fetch data from an external API at query time (different feature).

Prerequisites

  • An IndyKite project, an AppAgent, and AppAgent credentials (the token that goes into X-IK-ClientKey at execution time).
  • A Service Account token with Config API access, and the project's GID in PROJECT_GID (both used to create the policy and Knowledge Query).
  • The IKG already populated with the nodes and relationships the policy will match. CIQ only filters and projects; it does not seed data.
  • A subject type to authenticate against - Person, User, _Application, etc. CIQ policies are restricted to a single subject type, so if you need two subjects, plan for two policies.

If any of these are missing, stop and tell the user - fixing them first is much cheaper than debugging an opaque CIQ rejection.

Steps

1. Pick the subject and the Cypher pattern

Subject type - pick one. The schema is identical across both choices; only subject.type, the filter, and the execute-time auth differ:

SubjectUse whenAuth at execute timeFilter convention
_ApplicationSystem-side / ETL / catalog work; no user in the loop.X-IK-ClientKey only.subject.external_id = $_appId (reserved).
Person / UserThe authenticated user is performing the operation themselves.X-IK-ClientKey + Authorization: Bearer <token>.subject.external_id = $token.sub.

A policy is restricted to a single subject type - if both should be allowed, write two policies. The subject's variable in cypher is conventionally named subject. The runnable example below uses Person; an _Application variant - for example, a service reading the catalog - differs only in subject.type, the filter, and the execute headers.

Cypher pattern - the MATCH / OPTIONAL MATCH clauses naming every node and relationship the query will touch. Each one must have a variable name so the policy and Knowledge Query can reference it. If the exact node types, relationship types, or property spellings in the project's IKG are unknown, read them from the Data Schema API first (indykite-data-schema) - a typoed name silently matches nothing.

Working example used throughout this skill:

A Person (subject) OWNS Cars. Given a person's external_id, return the cars they own.

MATCH (subject:Person)-[r:OWNS]->(car:Car)

Variables: subject, r, car.

2. Author the read-only CIQ policy

Build the policy JSON. For a read-only policy you need three things and only three things:

  • meta.policy_version - currently 1.0-ciq.
  • subject.type - the chosen subject type.
  • condition.cypher and (optionally) condition.filter - the pattern and any filters. Use $varname to mark partial filters that will be supplied at execution time. A third, optional condition.skip_resource_label exists for a condition that stays slow after it is anchored and bounded - see the policy reference before using it.
  • allowed_reads - list every variable the Knowledge Query will be allowed to return. Use <var>.* to allow all properties of a node/relationship, or <var>.property.<name> for a single property.

Skip allowed_upserts and allowed_deletes entirely - omitting them is the supported way to forbid writes.

A complete read-only policy for the running example: see assets/policy-read-cars.json.

Create it through the Config API:

# set the current project_id, and stringify only the `policy` field, before POSTing
jq --arg pid "$PROJECT_GID" '.project_id = $pid | .policy |= tojson' assets/policy-read-cars.json \
  | curl -X POST "$API_URL/configs/v1/authorization-policies" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $SERVICE_ACCOUNT_TOKEN" \
      -d @-

A 201 Created returns the policy's id (GID). Export it as POLICY_ID - the Knowledge Query create injects it into policy_id.

For the full schema (every operator, every attribute pattern, what token_filter is for) see references/policy-reference.md.

3. Create the Knowledge Query

A read-only Knowledge Query references the policy and lists what to return. The four read-relevant fields are:

  • nodes - node variables (or <var>.property.<name>) to include in the response.
  • relationships - relationship variables to include.
  • aggregate_values - variables produced by aggregate functions in cypher (e.g. COLLECT(...) AS xs → "xs").
  • batch_read - set to true only when you expect a result set big enough to risk the default timeout; raises the timeout to 5 minutes.

A complete Knowledge Query for the running example: see assets/knowledge-query-read-cars.json.

Create it through the Config API (with POLICY_ID set to the policy's GID from the previous step):

# set the current project_id and policy_id, and stringify only the `query` field, before POSTing
jq --arg pid "$PROJECT_GID" --arg polid "$POLICY_ID" '.project_id = $pid | .policy_id = $polid | .query |= tojson' assets/knowledge-query-read-cars.json \
  | curl -X POST "$API_URL/configs/v1/knowledge-queries" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $SERVICE_ACCOUNT_TOKEN" \
      -d @-

A 201 Created returns the Knowledge Query's id (GID). This is what execute (and the MCP ciq_execute tool) will reference.

Schema details for every Knowledge Query field, including upsert_* and delete_* (omitted for the read case): references/knowledge-query-reference.md.

4. Execute the query

The execute endpoint runs the Knowledge Query at runtime with concrete parameter values:

POST <API_URL>/contx-iq/v1/execute

Authentication:

  • Always: X-IK-ClientKey: <AppAgent-credentials-token>.
  • If subject.type is not _Application: also Authorization: Bearer <user-access-token>. The token's sub is the subject identifier. To see the exact type / id a token resolves to, call GET /contx-iq/v1/whoami (indykite-ciq-whoami).
  • If subject.type is _Application: the reserved $_appId parameter is auto-filled from the application's external_id; do not pass it in input_params.

Request:

{
  "id": "<knowledge_query_gid_or_name>",
  "input_params": {
    "person_external_id": "alice"
  }
}

A runnable shell helper: scripts/execute.sh.

Large result sets page with two optional body fields: page_size (rows per page, default 100) and page_token, a 1-based page number (1 or omitted is the first page, 2 the next). The response carries no token, so increment the number yourself and stop at the first page shorter than page_size. The helper sends the first page; add the two fields to the raw body for the others. The MCP ciq_execute tool takes the same two optional arguments (indykite-mcp-server).

The full execute reference (auth combinations, response shape, paging, error semantics) lives in references/execution-reference.md.

5. Read the response and verify

The response shape is:

{
  "data": [
    { "nodes": { "<var>.<attr>": "<value>", ... } },
    { "relationships": { ... } }
  ]
}

One row per match, with nodes keyed <var>.<attr> and relationships keyed similarly. If the policy or Knowledge Query whitelists a variable but the IKG has nothing matching, the data array is simply empty.

If the response is not what you expected, walk through this check list before changing the policy:

  1. Variable in the response? It must appear in both the policy's allowed_reads.nodes / relationships / aggregate_values and the Knowledge Query's nodes / relationships / aggregate_values. The intersection is what gets returned.
  2. Filter actually firing? A typo in attribute (e.g. subject.external_id vs. person.external_id) silently matches nothing. Re-read the attribute naming conventions.
  3. Subject set up correctly? For non-_Application subjects, the Bearer token's sub is the subject identifier; without a token the subject is not bound and many policies match nothing.
  4. Data actually in the IKG? Run a probe query against the same shape but with IS NOT NULL filters to confirm the data exists.

Outcome

When this skill has been applied successfully:

  • A read-only CIQ policy exists in the project; it has a single subject.type, a cypher pattern with named variables, optional partial filters, and an allowed_reads whitelist - but no allowed_upserts or allowed_deletes.
  • A Knowledge Query references that policy and lists exactly the variables it should return in nodes / relationships / aggregate_values.
  • POST /contx-iq/v1/execute (or the MCP ciq_execute tool) returns the expected rows for valid input_params and an empty data array for valid-but-non-matching ones.
  • The same Knowledge Query can be invoked from the indykite-mcp-server skill via ciq_execute without further changes.

Files in this skill

Agent-specific notes

This skill uses generic markdown instructions and works across all agents listed in the README. The agent needs to be able to issue HTTP requests (curl, an HTTP client, or the IndyKite Terraform provider - see References). No Claude Code hooks, Cursor @-mentions, or Copilot workspace context are required.

References

Comments

Markdown supported