Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/jbarrasa/goingmeta/llms.txt

Use this file to discover all available pages before exploring further.

Season 3, Episode 1 of Going Meta explores how LLM agents can create ontologies interactively using the Neo4j Data Modeling MCP (Model Context Protocol) Server. Rather than hand-crafting OWL files from scratch, the session demonstrates a workflow where an agent converses with the MCP server to build a graph data model, which is then exported as a Mermaid diagram and automatically converted to a fully-formed OWL ontology in Turtle format — and back again.

Watch the Recording

Season 3, Episode 1 — October 2025

Session Code

Python scripts and example ontologies

The Blue Plaques Domain Model

The session uses the London Blue Plaques dataset as a running example. The data model captures people commemorated by blue plaques, the plaques themselves, the organisations that erected them, addresses, and musical compositions. This is the Mermaid diagram produced by the MCP server during the live session:

Converting Mermaid to OWL with mermaid2owl.py

The mermaid2owl.py script parses the Mermaid diagram and produces an rdflib graph with proper OWL class declarations, datatype properties (mapped to XSD types), and object properties derived from labelled edges.

Type mapping

Mermaid property types are mapped to XSD datatypes via a configurable dictionary:
XSD_MAP = {
    "STRING": XSD.string,
    "INTEGER": XSD.integer,
    "INT": XSD.integer,
    "FLOAT": XSD.float,
    "DOUBLE": XSD.double,
    "BOOLEAN": XSD.boolean,
    "DATE": XSD.date,
    "DATETIME": XSD.dateTime,
}

Parsing nodes

The parser extracts class names and their properties from the node label syntax (ClassName["ClassName<br/>prop: TYPE"]), stripping Mermaid styling lines and comments:
def parse_nodes(mermaid: str) -> Tuple[Dict[str, Dict[str, str]], List[str]]:
    node_props: Dict[str, Dict[str, str]] = {}
    classes: List[str] = []

    # Matches: Person["Person<br/>name: STRING | KEY<br/>year: INTEGER"]
    node_re = re.compile(r'^\s*([A-Za-z_]\w*)\s*\["(.+?)"\]\s*$', re.MULTILINE)

    for m in node_re.finditer(mermaid):
        cls = m.group(1)
        label_html = m.group(2)
        parts = [p.strip() for p in label_html.split("<br/>")]

        if cls not in node_props:
            node_props[cls] = {}
            classes.append(cls)

        for line in parts[1:]:
            if ":" not in line:
                continue
            pname, ptype = line.split(":", 1)
            pname = pname.strip()
            # ignore flags after " | "
            ptype = ptype.split("|", 1)[0].strip().upper()
            node_props[cls][pname] = ptype

    return node_props, classes

Parsing edges

Labelled Mermaid arrows (A -->|REL| B) become OWL object properties with rdfs:domain and rdfs:range axioms:
def parse_edges(mermaid: str) -> List[Tuple[str, str, str]]:
    edge_re = re.compile(
        r'^\s*([A-Za-z_]\w*)\s*-->\s*\|\s*([A-Za-z_][\w]*)\s*\|\s*([A-Za-z_]\w*)\s*$',
        re.MULTILINE,
    )
    edges = []
    for m in edge_re.finditer(mermaid):
        src, rel, tgt = m.group(1), m.group(2), m.group(3)
        edges.append((rel, src, tgt))
    return edges

Generating Turtle output

def mermaid_to_owl_turtle(
    mermaid: str,
    base_uri: str = "http://example.org/ontology#",
    ontology_iri: str = "http://example.org/ontology",
) -> str:
    g = mermaid_to_rdflib_graph(mermaid, base_uri, ontology_iri)
    ttl = g.serialize(format="turtle")
    return ttl.decode("utf-8") if isinstance(ttl, (bytes, bytearray)) else ttl
To convert the Blue Plaques diagram to Turtle at the http://voc.neo4j.com/blueplaques namespace:
with open("ontos/blue_plaques_model.mermaid", "r", encoding="utf-8") as f:
    mermaid = f.read()

ttl = mermaid_to_owl_turtle(
    mermaid,
    base_uri="http://voc.neo4j.com/blueplaques#",
    ontology_iri="http://voc.neo4j.com/blueplaques"
)

with open("ontos/blueplaques.ttl", "w", encoding="utf-8") as f:
    f.write(ttl)

Reverse-Converting OWL Back to Mermaid with owl2mermaid.py

The companion script owl2mermaid.py performs the inverse transformation: it reads any OWL Turtle file, extracts classes and properties via rdflib, and reconstructs a graph TD Mermaid diagram. This is useful for visualising imported ontologies or verifying a round-trip conversion.

XSD-to-Mermaid type mapping

XSD_TO_MERMAID = {
    XSD.string: "STRING",
    XSD.integer: "INTEGER",
    XSD.float: "FLOAT",
    XSD.double: "DOUBLE",
    XSD.boolean: "BOOLEAN",
    XSD.date: "DATE",
    XSD.dateTime: "DATETIME",
}

Building the diagram from an OWL file

def ontology_ttl_to_mermaid(ttl_path: str) -> str:
    g = Graph()
    g.parse(ttl_path, format="turtle")
    return build_mermaid(g)

# Example: reverse-convert a sales ontology
mermaid = ontology_ttl_to_mermaid("ontos/sales-onto.ttl")
with open("ontos/sales-onto.mermaid", "w", encoding="utf-8") as f:
    f.write(mermaid)
The build_mermaid function collects owl:Class nodes, groups owl:DatatypeProperty entries by domain, and renders each owl:ObjectProperty as a labelled edge — producing a diagram in the same format the Neo4j Data Modeling MCP Server generates natively.
The mermaid2owl.py parser strips Mermaid styling lines (classDef, class) before processing, so visual colour annotations in the diagram do not affect the generated ontology.

Workflow Summary

1

Design with the MCP Server

Use the Neo4j Data Modeling MCP Server inside your LLM agent (Claude Desktop, Cursor, etc.) to interactively create a graph data model through natural language. The server exposes tools for adding node types, properties, and relationships.
2

Export as Mermaid

Export the resulting model as a .mermaid file. The MCP server generates the graph TD format with <br/>-delimited property lists and labelled -->|REL| edges.
3

Convert to OWL Turtle

Run mermaid2owl.py with your chosen base URI and ontology IRI to produce a standards-compliant OWL ontology in Turtle syntax, ready to load into Neo4j with n10s or any triple store.
4

Round-trip verify

Run owl2mermaid.py on the generated .ttl file to confirm that all classes, datatype properties, and object properties survive the round trip back into a Mermaid diagram.
Both scripts depend only on rdflib. Install with pip install rdflib before running.

Build docs developers (and LLMs) love