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.

Initialization init

Endpoint "mcp/init"

Creates a new MCP connection, which is a blank traversal.
The request for this endpoint is empty ({}). Response Format
"<connection-id>"

Iterate Results next

Endpoint "mcp/next"

Returns the next item in the MCP traversal results.
Response Format
{<node-edge-data>}

Collect Results collect

Endpoint "mcp/collect"

Collects all the results from the MCP traversal.
Request Format
{
    "connection_id": "<connection-id>", 
    "range": {"start": <start-index>, "end": <end-index>}, 
    "drop" : <true-false>
}
Optional Parameters
  • range (optional) : range of results to collect (default: {"start": 0, "end": -1})
  • drop (optional) : resets the traversal after collecting results (default: true)
Response Format
[
    {<node-edge-data>},
    ...
]

Reset Connection reset

Endpoint "mcp/reset"

Resets the MCP connection with the given connection ID to a blank traversal.
Request Format
{"connection_id": "<connection-id>"}
Response Format
"<connection-id>"

Schema Context schema_resource

Endpoint "mcp/schema_resource"

Returns the schema and query information of the database for LLM context.
Request Format
{"connection_id": "<connection-id>"}
Response Format
{
    "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.

Retrieve Nodes n_from_type

Endpoint "mcp/n_from_type"

Retrieves all nodes of a given type.
Request Format
{"connection_id": "<connection-id>", "data": {"node_type": "<node-type>"}}
Parameters
  • node_type : the label of node to retrieve

Retrieve Edges e_from_type

Endpoint "mcp/e_from_type"

Retrieves all edges of a given type.
Request Format
{"connection_id": "<connection-id>", "data": {"edge_type": "<edge-type>"}}
Parameters
  • edge_type : the label of edge to retrieve

Out out_step

Endpoint "mcp/out_step"

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
{
    "connection_id": "<connection-id>",
    "data": {"edge_type": "<edge-type>", "edge_label": "<edge-label>"}
}
Parameters
  • edge_type : the target entity (node or vec)
  • edge_label : the label of edge to traverse out

OutE out_e_step

Endpoint "mcp/out_e_step"

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
{"connection_id": "<connection-id>", "data": {"edge_label": "<edge-label>"}}
Parameters
  • edge_label : the label of edge to traverse out

In in_step

Endpoint "mcp/in_step"

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
{
    "connection_id": "<connection-id>", 
    "data": {"edge_type": "<edge-type>", "edge_label": "<edge-label>"}
}
Parameters
  • edge_type : the source entity (node or vec)
  • edge_label : the label of edge to traverse into

InE in_e_step

Endpoint "mcp/in_e_step"

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
{"connection_id": "<connection-id>", "data": {"edge_label": "<edge-label>"}}
Parameters
  • edge_label : the label of edge to traverse into

MCP Filter Tool

Filter filter_items

Endpoint "mcp/filter_items"

Filters the current state of the traversal.
Request Format
{
    "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:
// Filter layer
{
    "properties" : [
        <property-filters>,
        ...
    ],
    "filter_traversals" : [
        <traversal-filters>,
        ...
    ]
}

Property Filter

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.
// OR layer
"properties" : [
    // AND layer
    [
        // Filters
        {"key": "<property-name>", "operator": "<operator>", "value": "<property-value>"},
        ...
    ],
    ...
]
Parameters
  • key : the name of the property to filter on
  • operator : the operator to use for the filter
  • value : the value to filter on
Operators:
OperatorDescriptionOperatorDescription
==equals!=not equals
>greater than>=greater than or equal to
<less than<=less than or equal to
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.

Traversal Filter

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.
// 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 Search Tools

SearchV search_vector

Endpoint "mcp/search_vector"

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
{
    "connection_id": "<connection-id>", 
    "data": {
        "vector": <array-of-floats>, "k": <limit>, "min_score": <min-score>
    }
}
Parameters
  • vector : the vector to search for
  • k : the number of results to return
  • min_score (optional) : the minimum score to return (default: 0.0)
Response Format
[
    {<vector-data>},
    ...
]

SearchV Text search_vector_text

Endpoint "mcp/search_vector_text"

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
{
    "connection_id": "<connection-id>", 
    "data": {
        "query": "<text>", "label": "<vector-label>"
    }
}
Parameters
  • query : the text to search for
  • label : the label of the vectors to search for
Response Format
[
    {<vector-data>},
    ...
]

Search BM25 search_keyword

Endpoint "mcp/search_keyword"

Searches for nodes of the given label by their keyword representation using BM25.
Request Format
{
    "connection_id": "<connection-id>", 
    "data": {
        "query": "<text>", "label": "<label>", "limit": <limit>
    }
}
Parameters
  • query : the text to search for
  • label : the label of the nodes, edges, or vectors to search for
  • limit : the number of results to return
Response Format
[
    {<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
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
from helix import Client
client = Client(local=True, port=6969)
Click here for more information about the Python SDK.

1. Filter properties by a list of values.

We will filter the entities with the names “John” or “Jane”.
# 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.
# 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.
# 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:
# 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
# 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”.
# 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.
# 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.
# 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]