> ## Documentation Index
> Fetch the complete documentation index at: https://helix-digitalocean.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Guide

> A guide to get you started with HelixDB MCP Endpoints

***

# Introduction

Build agentic graph queries that evolve step-by-step without rebuilding from scratch. HelixDB’s MCP endpoints provide a stateful, incremental query session via a `connection_id`, so each call extends the same traversal. This allows agents to chain and build complex traversal and filter queries over time while being able to view intermediate results. Stream results with `mcp/next` or batch with `mcp/collect`.

You can also dynamically pass lists created at runtime, toggle AND/OR property groups, and filter by temporary traversals. Run multiple traversals in concurrently and asynchronously using multiple connection IDs by initializing each traversal with its own `connection_id` to keep them separate and easy to manage.

***

# MCP Tools

These tools are used to manage the MCP connection and interact with the MCP endpoints.

<h2>Initialization `init`</h2>
<h4> Endpoint `"mcp/init"` </h4>
Creates a new MCP connection, which is a blank traversal.

The request for this endpoint is empty (`{}`).

Response Format

```rust theme={null}
"<connection-id>"
```

<h2>Iterate Results `next`</h2>
<h4> Endpoint `"mcp/next"` </h4>
Returns the next item in the MCP traversal results.

Request Format

```rust theme={null}
{
    "connection_id": "<connection-id>"
}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

Response Format

```rust theme={null}
{<node-edge-data>}
```

<h2>Collect Results `collect`</h2>
<h4> Endpoint `"mcp/collect"` </h4>
Collects all the results from the MCP traversal.

Request Format

```rust theme={null}
{
    "connection_id": "<connection-id>", 
    "range": {"start": <start-index>, "end": <end-index>}, 
    "drop" : <true-false>
}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

<ParamField path="range" type="json">
  Range of results to collect (default: `{"start": 0, "end": -1}`)
</ParamField>

<ParamField path="drop" type="boolean">
  Resets the traversal after collecting results (default: `true`)
</ParamField>

Response Format

```rust theme={null}
[
    {<node-edge-data>},
    ...
]
```

<h2>Reset Connection `reset`</h2>
<h4> Endpoint `"mcp/reset"` </h4>
Resets the MCP connection with the given connection ID to a blank traversal.

Request Format

```rust theme={null}
{"connection_id": "<connection-id>"}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

Response Format

```rust theme={null}
"<connection-id>"
```

<h2>Schema Context `schema_resource`</h2>
<h4> Endpoint `"mcp/schema_resource"` </h4>
Returns the schema and query information of the database for LLM context.

Request Format

```rust theme={null}
{"connection_id": "<connection-id>"}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

Response Format

```rust expandable theme={null}
{
    "schema": {
        "nodes": [
            {
                "name": "<node-name>",
                "properties": {
                    "<property-name>": "<property-type>",
                    ...
                }
            },
            ...
        ],
        "vectors": [
            {
                "name": "<vector-name>",
                "properties": {
                    "<property-name>": "<property-type>",
                    ...
                }
            },
            ...
        ],
        "edges": [
            {
                "name": "<edge-name>",
                "properties": {
                    "<property-name>": "<property-type>",
                    ...
                }
            },
            ...
        ]
    },
    "queries": [
        {
            "name": "<query-name>",
            "parameters": {
                "<parameter-name>": "<parameter-type>",
                ...
            },
            "returns": [
                "<return-variable-name>",
                ...
            ]
        }
    ]
}
```

***

# MCP Traversals

These tools are used to dynamically traverse the graph and retrieve nodes and edges.
However, they do not return the results of the traversal.

<h2>Retrieve Nodes `n_from_type`</h2>
<h4> Endpoint `"mcp/n_from_type"` </h4>
Retrieves all nodes of a given type.

Request Format

```rust theme={null}
{"connection_id": "<connection-id>", "data": {"node_type": "<node-type>"}}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

<ParamField path="node_type" type="string" required>
  The label of node to retrieve (name in schema)
</ParamField>

<h2>Retrieve Edges `e_from_type`</h2>
<h4> Endpoint `"mcp/e_from_type"` </h4>
Retrieves all edges of a given type.

Request Format

```rust theme={null}
{"connection_id": "<connection-id>", "data": {"edge_type": "<edge-type>"}}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

<ParamField path="edge_type" type="string" required>
  The label of edge to retrieve (name in schema)
</ParamField>

<h2>Out `out_step`</h2>
<h4> Endpoint `"mcp/out_step"` </h4>
Traverses out from current nodes or vectors in the traversal with the given edge type to nodes or vectors.
Assumes that the current state of the traversal is a collection of nodes or vectors that is the source of the given edge type and label.

Request Format

```rust theme={null}
{
    "connection_id": "<connection-id>",
    "data": {"edge_type": "<edge-type>", "edge_label": "<edge-label>"}
}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

<ParamField path="edge_type" type="string" required>
  The target entity (`node` or `vec`)
</ParamField>

<ParamField path="edge_label" type="string" required>
  The label of edge to traverse out (name in schema)
</ParamField>

<h2>OutE `out_e_step`</h2>
<h4> Endpoint `"mcp/out_e_step"` </h4>
Traverses out from current edges to their target nodes or vectors.
Assumes that the current state of the traversal is a collection of edges with the target of the given edge label.

Request Format

```rust theme={null}
{"connection_id": "<connection-id>", "data": {"edge_label": "<edge-label>"}}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

<ParamField path="edge_label" type="string" required>
  The label of edge to traverse out (name in schema)
</ParamField>

<h2>In `in_step`</h2>
<h4> Endpoint `"mcp/in_step"` </h4>
Traverses into the current nodes or vectors in the traversal with the given edge type to nodes or vectors.
Assumes that the current state of the traversal is a collection of nodes or vectors that is the target of the given edge type and label.

Request Format

```rust theme={null}
{
    "connection_id": "<connection-id>", 
    "data": {"edge_type": "<edge-type>", "edge_label": "<edge-label>"}
}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

<ParamField path="edge_type" type="string" required>
  The source entity (`node` or `vec`)
</ParamField>

<ParamField path="edge_label" type="string" required>
  The label of edge to traverse into (name in schema)
</ParamField>

<h2>InE `in_e_step`</h2>
<h4> Endpoint `"mcp/in_e_step"` </h4>
Traverses into the current edges to their source nodes or vectors.
Assumes that the current state of the traversal is a collection of edges with the source of the given edge label.

Request Format

```rust theme={null}
{"connection_id": "<connection-id>", "data": {"edge_label": "<edge-label>"}}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

<ParamField path="edge_label" type="string" required>
  The label of edge to traverse into (name in schema)
</ParamField>

# MCP Filter Tool

<h2>Filter `filter_items`</h2>
<h4> Endpoint `"mcp/filter_items"` </h4>
Filters the current state of the traversal.

Request Format

```rust theme={null}
{
    "connection_id": "<connection-id>", 
    "data": {"filter": <filters>}
}
```

Where `filters` is a list of filters to apply to the current state of the traversal.
The format of the filters is as follows:

```rust theme={null}
// Filter layer
{
    "properties" : [
        <property-filters>,
        ...
    ],
    "filter_traversals" : [
        <traversal-filters>,
        ...
    ]
}
```

<h3>Property Filter</h3>
The property filter is used to filter the current state of the traversal by the properties of the entity.
The outer list is the `OR` operation and the inner list is the `AND` operation.

```rust theme={null}
// OR layer
"properties" : [
    // AND layer
    [
        // Filters
        {"key": "<property-name>", "operator": "<operator>", "value": "<property-value>"},
        ...
    ],
    ...
]
```

<ParamField path="key" type="string" required>
  The name of the property to filter on
</ParamField>

<ParamField path="operator" type="string" required>
  The operator to use for the filter
</ParamField>

<ParamField path="value" type="string | [string]" required>
  The value to filter on
</ParamField>

<h4>Operators</h4>

| Operator | Description  | Operator | Description              |
| -------- | ------------ | -------- | ------------------------ |
| `==`     | equals       | `!=`     | not equals               |
| `>`      | greater than | `>=`     | greater than or equal to |
| `<`      | less than    | `<=`     | less than or equal to    |

<Note>
  List to value and value to list comparisons will use the OR operator for each element in the list.\
  List to list comparisons will also use the OR operator for each element in each list.

  This allows for using `contains` and `not_contains` operators by using the `==` and `!=` operator with a list of values.
</Note>

<h3>Traversal Filter</h3>
The traversal filter is used to filter the current state of the traversal by the results of a traversal.
It doesn't actually change the state of the current traversal, it just temporarily traverses and checks the results of the traversal.
You can have nested filters in the inner filter layer, which can include property and traversal filters with the same structure.
The traversal filter only has an `AND` operation.

```rust theme={null}
// AND layer
"filter_traversals" : [
    {
        // Traversal tool name
        "tool_name" : "<tool-name>",
        // Traversal tool args
        "args" : {
            "<parameter-name>" : "<parameter-value>",
            ...,
            // Inner filter layer
            "filter" : {
                "properties" : [
                    <property-filters>,
                    ...
                ],
                "filter_traversals" : [
                    <traversal-filters>,
                    ...
                ]
            }
        }
    },
    ...
]
```

***

# MCP Aggregation Tools

<h2>Group `group_by`</h2>
<h4> Endpoint `"mcp/group_by"` </h4>
Groups the current state of the traversal by the given properties.
It returns a list of unique property combinations and their count.

Request Format

```rust theme={null}
{
    "connection_id": "<connection-id>", 
    "properties": ["<property-name>", ...]
}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

<ParamField path="properties" type="[string]" required>
  The properties to group by
</ParamField>

Response Format

```rust theme={null}
[
    {<property-name>: <property-value>, ... , "count": <count>},
    ...
]
```

<h2>Aggregate `aggregate_by`</h2>
<h4> Endpoint `"mcp/aggregate_by"` </h4>
Aggregates the current state of the traversal by the given properties.
It returns a list of groups of jsons each with a count and data as a list of items in that group.

Request Format

```rust theme={null}
{
    "connection_id": "<connection-id>", 
    "properties": ["<property-name>", ...]
}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

<ParamField path="properties" type="[string]" required>
  The properties to aggregate by
</ParamField>

Response Format

```rust theme={null}
[
    {
        "count": <count>,
        "data": [
            {<node-edge-data>},
            ...
        ]
    },
    ...
]
```

<h2>Order `order_by`</h2>
<h4> Endpoint `"mcp/order_by"` </h4>
Orders the current state of the traversal by a given property in ascending or descending order.

Request Format

```rust theme={null}
{
    "connection_id": "<connection-id>", 
    "data": {"properties": "<property-name>", "order": "<asc-desc>"}
}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

<ParamField path="properties" type="string" required>
  The property to order by
</ParamField>

<ParamField path="order" type="string" required>
  The order to use for the property (asc or desc)
</ParamField>

Response Format

```rust theme={null}
{<first-item>}
```

***

# MCP Search Tools

<h2>SearchV `search_vector`</h2>
<h4> Endpoint `"mcp/search_vector"` </h4>
Searches for vectors by their vector representation with the given vector.
It returns the top `k` results with a minimum score of `min_score`.
Additionally, you can continue the traversal from the search results by using the traversal tools.

Request Format

```rust theme={null}
{
    "connection_id": "<connection-id>", 
    "data": {
        "vector": <array-of-floats>, "k": <limit>, "min_score": <min-score>
    }
}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

<ParamField path="vector" type="[F64]" required>
  The vector to search for
</ParamField>

<ParamField path="k" type="I64" required>
  The number of results to return
</ParamField>

<ParamField path="min_score" type="F64">
  The minimum score to return (default: `0.0`)
</ParamField>

Response Format

```rust theme={null}
[
    {<vector-data>},
    ...
]
```

<h2>SearchV Text `search_vector_text`</h2>
<h4> Endpoint `"mcp/search_vector_text"` </h4>
Searches for vectors by their vector representation with given text.
It uses the embedding inside the database to embed the text and then does HNSW search for the vector.
It returns the top 5 results of the vectors with the `label`.

Request Format

```rust theme={null}
{
    "connection_id": "<connection-id>", 
    "data": {
        "query": "<text>", "label": "<vector-label>"
    }
}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

<ParamField path="query" type="string" required>
  The text to search for
</ParamField>

<ParamField path="label" type="string" required>
  The label of the vectors to search for (name in schema)
</ParamField>

Response Format

```rust theme={null}
[
    {<vector-data>},
    ...
]
```

<h2>Search BM25 `search_keyword`</h2>
<h4> Endpoint `"mcp/search_keyword"` </h4>
Searches for nodes of the given label by their keyword representation using BM25.

Request Format

```rust theme={null}
{
    "connection_id": "<connection-id>", 
    "data": {
        "query": "<text>", "label": "<label>", "limit": <limit>
    }
}
```

<ParamField path="connection_id" type="string" required>
  Connection ID of the MCP connection
</ParamField>

<ParamField path="query" type="string" required>
  The text to search for
</ParamField>

<ParamField path="label" type="string" required>
  The label of the node, edge, or vector to search for (name in schema)
</ParamField>

<ParamField path="limit" type="I64" required>
  The number of results to return
</ParamField>

Response Format

```rust theme={null}
[
    {<node-data>},
    ...
]
```

***

# Knowledge Graph Examples

In this example, we will be using the Python SDK to interact with the MCP endpoints on a local instance of HelixDB.

We will use a knowledge graph with the schema below, which has
a triplet node to represent a fact and an entity node to represent the subject and object of the triplet.
We will also have an embedding of the triplet's summary defined as a vector node.

Schema.hx

```rust expandable theme={null}
N::Triplet {
    INDEX uuid: String,
    summary: String,
    predicate: String,
    value: String,
    created_at: Date DEFAULT NOW
}

E::Triplet_to_Embedding {
    From: Triplet,
    To: Triplet_Embedding,
    Properties: {
    }
}

V::Triplet_Embedding {
    embedding: [F64]
}

E::Triplet_to_Subject {
    From: Triplet,
    To: Entity,
    Properties: {
    }
}

E::Triplet_to_Object {
    From: Triplet,
    To: Entity,
    Properties: {
    }
}

N::Entity {
    INDEX uuid: String,
    name: String,
    entity_type: String,
    description: String,
    created_at: Date DEFAULT NOW
}
```

Python SDK

```py theme={null}
from helix import Client
client = Client(local=True, port=6969)
```

<Tip>
  Click [here](../documentation/sdks/helix-py) for more information about the Python SDK.
</Tip>

### 1. Filter properties by a list of values.

We will filter the entities with the names "John" or "Jane".

```py expandable theme={null}
# Initialize the connection
connection_id = client.query('mcp/init', {})[0]

# Get all entities
client.query('mcp/n_from_type', {'connection_id': connection_id, 'data': {'node_type': 'Entity'}})

# Filter entities by the name "John" or "Jane"
client.query('mcp/filter_items', {
    'connection_id': connection_id, 
    'data': {'filter': {
        'properties': [
            [
                {'key': 'name', 'operator': '==', 'value': ['John', 'Jane']}
            ]
        ]
    }}
})

# Collect the entities
entities = client.query('mcp/collect', {'connection_id': connection_id})[0]
```

### 2. Filter multiple properties by a list of values.

We will filter the entities with the names "John" or "Jane" and the created\_at property between 2025-01-01 and 2025-01-31.

```py expandable theme={null}
# Initialize the connection
connection_id = client.query('mcp/init', {})[0]

# Get all entities
client.query('mcp/n_from_type', {'connection_id': connection_id, 'data': {'node_type': 'Entity'}})

# Filter entities by the name "John" or "Jane" and the created_at property between 2025-01-01 and 2025-01-31
client.query('mcp/filter_items', {
    'connection_id': connection_id, 
    'data': {'filter': {
        'properties': [
            [
                # AND layer
                {'key': 'name', 'operator': '==', 'value': ['John', 'Jane']},
                {'key': 'created_at', 'operator': '>=', 'value': "2025-01-01T00:00:00+00:00"},
                {'key': 'created_at', 'operator': '<=', 'value': "2025-01-31T23:59:59+00:00"}
            ]
        ]
    }}
})
```

### 3. Filter properties by multiple lists of values.

We will filter by date range of the `created_at` property from January to March or June to September.

```py expandable theme={null}
# Initialize the connection
connection_id = client.query('mcp/init', {})[0]

# Get all entities
client.query('mcp/n_from_type', {'connection_id': connection_id, 'data': {'node_type': 'Entity'}})

# Filter entities by the created_at property between January and March or June and September
client.query('mcp/filter_items', {
    'connection_id': connection_id, 
    'data': {'filter': {
        'properties': [
            # OR layer
            [
                # AND layer
                {'key': 'created_at', 'operator': '>=', 'value': "2025-01-01T00:00:00+00:00"},
                {'key': 'created_at', 'operator': '<=', 'value': "2025-03-31T23:59:59+00:00"}
            ],
            [
                # AND layer
                {'key': 'created_at', 'operator': '>=', 'value': "2025-06-01T00:00:00+00:00"},
                {'key': 'created_at', 'operator': '<=', 'value': "2025-09-30T23:59:59+00:00"}
            ]
        ]
    }}
})

# Collect the entities
entities = client.query('mcp/collect', {'connection_id': connection_id})[0]
```

### 3. Filter by traversal result properties.

We will filter the triplets connected to the subject name "John".\
This example has 2 answers:

```py expandable theme={null}
# Initialize the connection
connection_id = client.query('mcp/init', {})[0]

# Get all entities
client.query('mcp/n_from_type', {'connection_id': connection_id, 'data': {'node_type': 'Entity'}})

# Filter entities by the name "John"
client.query('mcp/filter_items', {
    'connection_id': connection_id, 
    'data': {'filter': {
        'properties': [
            [
                {'key': 'name', 'operator': '==', 'value': 'John'}
            ]
        ]
    }}
})

# Get all triplets connected to the entities
# (traverses the In of the edge to triplet nodes connected to the entities)
client.query('mcp/in_step', {"connection_id": connection_id, "data": {"edge_type": "Triplet_to_Subject", "edge_label": "node"}})

# Collect the triplets
triplets = client.query('mcp/collect', {'connection_id': connection_id})[0]
```

OR

```py expandable theme={null}
# Initialize the connection
connection_id = client.query('mcp/init', {})[0]

# Get all triplets
client.query('mcp/n_from_type', {'connection_id': connection_id, 'data': {'node_type': 'Triplet'}})

# Filter triplets with the subject name "John"
client.query('mcp/filter_items', {
    'connection_id': connection_id, 
    'data': {'filter': {
        'filter_traversals': [
            # Traverse out from the triplet nodes to the subject nodes
            {
                'tool_name': 'out_step',
                'args': {
                    'edge_type': 'Triplet_to_Subject',
                    'edge_label': 'node'
                },
                # Filter the subject nodes by the name "John"
                'filters': {
                    'properties': [
                        [
                            {'key': 'name', 'operator': '==', 'value': 'John'}
                        ]
                    ]
                }
            }
        ]
    }}
})

# Collect the triplets
triplets = client.query('mcp/collect', {'connection_id': connection_id})[0]
```

### 4. Filter by multiple traversal results.

We will filter the triplets connected to the subject name "John" and the object name "Jane".

```py expandable theme={null}
# Initialize the connection
connection_id = client.query('mcp/init', {})[0]

# Get all triplets
client.query('mcp/n_from_type', {'connection_id': connection_id, 'data': {'node_type': 'Triplet'}})

# Filter the triplets by the subject name "John" and the object name "Jane"
client.query('mcp/filter_items', {'connection_id': connection_id, 'data': {'filter': {
    'filter_traversals': [
        # AND layer
        # Traverse out from the triplet nodes to the subject nodes
        {
            'tool_name': 'out_step',
            'args': {
                'edge_type': 'Triplet_to_Subject',
                'edge_label': 'node'
            },
            # Filter the subject nodes by the name "John"
            'filters': {
                'properties': [
                    [
                        {'key': 'name', 'operator': '==', 'value': 'John'}
                    ]
                ]
            }
        },
        # Traverse out from the triplet nodes to the object nodes
        {
            'tool_name': 'out_step',
            'args': {
                'edge_type': 'Triplet_to_Object',
                'edge_label': 'node',
                # Filter the object nodes by the name "Jane"
                'filters': {
                    'properties': [
                        [
                            {'key': 'name', 'operator': '==', 'value': 'Jane'}
                        ]
                    ]
                }
            }
        }
    ]
}}})

# Collect the triplets
triplets = client.query('mcp/collect', {'connection_id': connection_id})[0]
```

### 5. Collecting intermediate results.

We will get all triplets and their embeddings in one MCP connection.

```py expandable theme={null}
# Initialize the connection
connection_id = client.query('mcp/init', {})[0]

# Get all triplets
client.query('mcp/n_from_type', {'connection_id': connection_id, 'data': {'node_type': 'Triplet'}})

# Collect without resetting
triplets = client.query('mcp/collect', {'connection_id': connection_id, "drop": False})[0]

# Traverse out from the triplets to the embeddings
client.query('mcp/out_step', {'connection_id': connection_id, 'data': {'edge_type': 'Triplet_to_Embedding', 'edge_label': 'vec'}})

# Collect the embeddings
embeddings = client.query('mcp/collect', {'connection_id': connection_id})[0]
```

### 6. Search by vector.

We will search for the top 10 triplets that are most similar to an example embedding of `[0.1, 0.2, 0.3, 0.4, 0.5]` with a minimum score of 0.7.

```py expandable theme={null}
# Initialize the connection
connection_id = client.query('mcp/init', {})[0]

# Get all triplets
client.query('mcp/n_from_type', {'connection_id': connection_id, 'data': {'node_type': 'Triplet'}})

# Traverse to embeddings
client.query('mcp/out_step', {'connection_id': connection_id, 'data': {'edge_type': 'Triplet_to_Embedding', 'edge_label': 'vec'}})

# Search for the triplets that are most similar to an example embedding of [0.1, 0.2, 0.3, 0.4, 0.5]
client.query('mcp/search_vector', {'connection_id': connection_id, 'data': {'vector': [0.1, 0.2, 0.3, 0.4, 0.5], 'k': 10, 'min_score': 0.7}})

# Traverse to the triplets
client.query('mcp/in_step', {'connection_id': connection_id, 'data': {'edge_type': 'Triplet_to_Embedding', 'edge_label': 'node'}})

# Collect the triplets
triplets = client.query('mcp/collect', {'connection_id': connection_id})[0]
```
