# Typed Edges in the Knowledge Graph: How Agents Share Causal Chains in MCP-Memory-Service

> Discover typed edges in knowledge graphs for agent causal chain sharing via semantic relationships like causes, fixes, and supports in the MCP-Memory-Service.

- Repository: [Henry/mcp-memory-service](https://github.com/doobidoo/mcp-memory-service)
- Tags: deep-dive
- Published: 2026-02-28

---

**Typed edges in the knowledge graph are semantic relationships that connect memory nodes, enabling agents to store, query, and reason over causal chains using directional links like `causes`, `fixes`, and `supports`.**

The `mcp-memory-service` repository implements a persistent knowledge graph that records not just isolated memories, but the rich semantic connections between them. These **typed edges** transform a simple memory store into a causal reasoning engine where agents can trace why events occurred, what fixed them, and how concepts relate across sessions.

## What Are Typed Edges in the Knowledge Graph?

Typed edges are first-class relationships defined in the ontology model that describe how two memory nodes semantically interact. Unlike generic "related" links, each type carries specific directional semantics and symmetry constraints.

The system defines six relationship types in [`src/mcp_memory_service/models/ontology.py`](https://github.com/doobidoo/mcp-memory-service/blob/main/src/mcp_memory_service/models/ontology.py):

| Edge type | Symmetry | Meaning |
|-----------|----------|---------|
| `causes` | Asymmetric (directed) | A → B means "A **causes** B". The reverse edge is **not** stored. |
| `fixes` | Asymmetric | A → B means "A **fixes** B". |
| `supports` | Asymmetric | A → B means "A **supports** B". |
| `follows` | Asymmetric | A → B means "A **follows** B". |
| `contradicts` | Symmetric (bidirectional) | A ↔ B means "A **contradicts** B". |
| `related` | Symmetric | A ↔ B means "A **related to** B". |

The ontology definition for `causes` explicitly marks it as asymmetric with a directional description【/src/mcp_memory_service/models/ontology.py#L166-L167】. This distinction determines how the storage layer writes edges to the database.

## How Typed Edges Are Stored in the Graph Database

The graph storage layer in [`src/mcp_memory_service/storage/graph.py`](https://github.com/doobidoo/mcp-memory-service/blob/main/src/mcp_memory_service/storage/graph.py) handles the persistence logic for typed edges, respecting their symmetry constraints. For asymmetric relationships like `causes`, the system stores only the directed edge (A→B), while symmetric types like `contradicts` are stored bidirectionally to enable efficient traversal from either node【/src/mcp_memory_service/storage/graph.py#L164-L175】.

When an agent creates a causal link, it calls `store_association()` with the `relationship_type` parameter:

```python

# Example: an agent records that a recent decision caused an error

await graph_storage.store_association(
    source_hash="decision_a",
    target_hash="error_b",
    confidence=0.9,
    tags=["causal"],
    relationship_type="causes",   # ← typed edge

)

```

This call inserts a single directed row representing the causal relationship【/src/mcp_memory_service/storage/graph.py#L321-L335】. The storage layer validates the relationship type against the ontology before persisting, ensuring only defined semantic relationships enter the graph.

## How Agents Share Causal Chains Using Typed Edges

Agents leverage typed edges to build collective intelligence by recording observations and querying the causal history of events. The system provides multiple mechanisms for traversing these semantic links.

### Storing Causal Links

Agents persist causal observations using the `causes` relationship type to document decision outcomes. This creates a directed acyclic graph of events where each edge represents a causal hypothesis with an associated confidence score.

```python

# src/mcp_memory_service/examples/store_causal_edge.py

import asyncio
from mcp_memory_service.storage.graph import GraphStorage

async def main():
    storage = GraphStorage()
    await storage.store_association(
        source_hash="decision_123",
        target_hash="error_456",
        confidence=0.95,
        tags=["runtime", "crash"],
        relationship_type="causes",
    )
    print("Causal edge stored.")

asyncio.run(main())

```

### Querying Upstream Causes

To understand why an event occurred, agents query incoming edges using the `find_connected()` method with `direction="incoming"`. This retrieves all memories that directly caused the target event.

```python
async def get_upstream_causes(error_hash: str):
    storage = GraphStorage()
    incoming = await storage.find_connected(
        memory_id=error_hash,
        relationship_type="causes",
        direction="incoming",
    )
    return [mem for mem, score in incoming]

# usage

causes = asyncio.run(get_upstream_causes("error_456"))
print("Causes:", causes)

```

The `find_connected` API supports filtering by relationship type and direction, enabling agents to traverse specific semantic pathways such as `fixes` or `supports`【/src/mcp_memory_service/storage/graph.py#L164-L175】.

### Transitive Causal Inference

The **Semantic Reasoner** extends simple edge traversal by computing transitive closure over causal chains. The `infer_transitive()` method recursively walks `causes` edges to find indirect causal relationships up to a specified hop limit.

```python
async def full_causal_chain(target_hash: str, hops: int = 3):
    reasoner = InferenceEngine()
    chain = await reasoner.infer_transitive(
        relationship_type="causes",
        max_hops=hops,
        start_hash=target_hash,
    )
    return chain   # → {'error_456': ['decision_123', 'observation_9', ...]}

# Example

chain = asyncio.run(full_causal_chain("error_456"))
print(chain)

```

The reasoner implements this via `find_causes()`, which calls `_get_connected()` with `direction="incoming"` to build the causal graph【/src/mcp_memory_service/reasoning/inference.py#L112-L131】.

### Visualizing Causal Chains

The **Knowledge-Graph Dashboard** renders typed edges in an interactive D3 force-directed graph, allowing users and agents to visually trace causal, fix, and contradiction paths across the memory network【/docs/features/knowledge-graph-dashboard.md#L70-L79】.

## Summary

- **Typed edges** are semantic relationships (`causes`, `fixes`, `supports`, `follows`, `contradicts`, `related`) defined in [`src/mcp_memory_service/models/ontology.py`](https://github.com/doobidoo/mcp-memory-service/blob/main/src/mcp_memory_service/models/ontology.py) that connect memory nodes with specific directional semantics.
- **Asymmetric edges** (like `causes`) store single directed links, while **symmetric edges** (like `contradicts`) store bidirectional links in [`src/mcp_memory_service/storage/graph.py`](https://github.com/doobidoo/mcp-memory-service/blob/main/src/mcp_memory_service/storage/graph.py).
- Agents create causal chains by calling `store_association()` with `relationship_type="causes"`, and retrieve them using `find_connected()` with `direction="incoming"`.
- The **Semantic Reasoner** in [`src/mcp_memory_service/reasoning/inference.py`](https://github.com/doobidoo/mcp-memory-service/blob/main/src/mcp_memory_service/reasoning/inference.py) computes transitive causal chains across multiple hops using `infer_transitive()`.
- The **Knowledge-Graph Dashboard** visualizes these chains, enabling shared causal reasoning across agent sessions.

## Frequently Asked Questions

### What is the difference between asymmetric and symmetric typed edges?

Asymmetric typed edges, such as `causes`, `fixes`, `supports`, and `follows`, represent directional relationships where the order of nodes matters. The system stores only the directed link (A→B) without implying the reverse. Symmetric edges like `contradicts` and `related` represent bidirectional relationships where A→B implies B→A, so the storage layer persists both directions to enable efficient traversal from either node【/src/mcp_memory_service/storage/graph.py#L164-L175】.

### How does the Semantic Reasoner infer transitive causal chains?

The Semantic Reasoner implements transitive inference by recursively walking the `causes` edges using the `infer_transitive()` method. It starts from a target memory and follows incoming `causes` edges up to a configurable maximum hop count (default 3), aggregating all indirect causal ancestors. The implementation in [`src/mcp_memory_service/reasoning/inference.py`](https://github.com/doobidoo/mcp-memory-service/blob/main/src/mcp_memory_service/reasoning/inference.py) uses `_get_connected()` with `direction="incoming"` to build the complete causal graph for a given event【/src/mcp_memory_service/reasoning/inference.py#L112-L131】.

### Can agents share causal chains across different sessions?

Yes, because the knowledge graph persists typed edges in SQLite-vec via the `GraphStorage` class, causal chains survive beyond individual agent sessions. Any agent—whether built with LangGraph, CrewAI, AutoGen, or a generic HTTP client—can query the stored `causes` edges using `find_connected()` or the Semantic Reasoner to reconstruct the causal history of events created by other agents in previous sessions.

### What file defines the available typed edge relationships?

The ontology model in [`src/mcp_memory_service/models/ontology.py`](https://github.com/doobidoo/mcp-memory-service/blob/main/src/mcp_memory_service/models/ontology.py) defines the six available typed edge relationships: `causes`, `fixes`, `supports`, `follows`, `contradicts`, and `related`. This file specifies each relationship's metadata, including its description, symmetry properties, and directional semantics, which the storage layer references when validating and persisting edges【/src/mcp_memory_service/models/ontology.py#L166-L170】.