# Docker Compose - Complete Setup

This guide runs the full MemGQL stack using Docker Compose: Memgraph as the
graph backend, MemGQL as the federated query engine, Memgraph Lab for visual
exploration, PostgreSQL as a relational backend, the MCP server for AI agent
integration, and structured2graph to create the mappings.

## Prerequisites

- [Docker](https://docs.docker.com/get-started/get-docker/) with Docker Compose
- [mgconsole](https://github.com/memgraph/mgconsole) (Memgraph Bolt CLI client)

## Architecture

```
                                                ┌──────────────┐
┌──────────────┐          ┌──────────────┐ bolt │              │
│  mgconsole   │──bolt───▶│              │─────▶│  Memgraph    │
└──────────────┘          │              │      │         :7687│
                          │              │      └──────────────┘
┌──────────────┐          │    MemGQL    │
│ Memgraph Lab │──bolt───▶│              │
│         :3000│          │        :7688 │      ┌──────────────┐
└──────────────┘          │              │ sql  │              │
                          │              │─────▶│  PostgreSQL  │
┌──────────────┐          │              │      │         :5432│
│  MCP Server  │──bolt───▶│              │      └──────────────┘
│         :8000│          └──────────────┘
└──────────────┘
```

Clients (mgconsole, Bolt drivers, Lab) connect to MemGQL on port **7688**.
MemGQL translates GQL and routes queries to the configured backends.

## 1. Create the Docker network

All services communicate over a shared Docker network:

```bash
docker network create memgql-net
```

## 2. Create the PostgreSQL init files

MemGQL needs a graph mapping to translate graph patterns into SQL. Create
these two files next to your `docker-compose.yml`:

**`pg_init.sql`** creates the relational tables:

```sql
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    email TEXT
);

CREATE TABLE friend_of (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES users(id),
    friend_id INTEGER NOT NULL REFERENCES users(id),
    UNIQUE (user_id, friend_id)
);
```

**`pg_mapping.json`** is a graph mapping body (`vertices` + `edges`) that maps the
tables to graph labels on the `pg` connector:

```json
{
  "vertices": [
    {
      "label": "User",
      "mappedTableSource": {
        "connector": "pg",
        "table": "users",
        "metaFields": {
          "id": "id"
        }
      },
      "attributes": [
        {
          "name": "name"
        },
        {
          "name": "email"
        }
      ]
    }
  ],
  "edges": [
    {
      "label": "FRIEND_OF",
      "from": "User",
      "to": "User",
      "mappedTableSource": {
        "connector": "pg",
        "table": "friend_of",
        "metaFields": {
          "id": "id",
          "from": "user_id",
          "to": "friend_id"
        }
      }
    }
  ]
}
```

## 3. Docker Compose file

Save the following as `docker-compose.yml`:

```yaml
services:
  memgql:
    image: ${MEMGQL_IMAGE:-memgraph/memgql:0.12.0}
    container_name: memgql
    ports:
      - "7688:7688"
    environment:
      CONNECTOR_TYPE: ${CONNECTOR_TYPE:-multi}
      MEMGRAPH_URI: memgraph:7687
      BOLT_LISTEN_ADDR: 0.0.0.0:7688
      # To enable enterprise features, set these in a .env file or via CLI:
      #   MEMGQL_ENTERPRISE_LICENSE=mglk-...
      #   MEMGQL_ORGANIZATION_NAME=your-org
    volumes:
      - memgql-mappings:/mappings
      - ./pg_mapping.json:/mappings/pg_mapping.json
    healthcheck:
      test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/localhost/7688'"]
      interval: 2s
      timeout: 2s
      retries: 15
      start_period: 3s
    depends_on:
      memgraph:
        condition: service_healthy
    networks:
      - memgql-net

  memgql-init:
    image: memgraph/mgconsole:1.7.1
    container_name: memgql-init
    entrypoint:
      - sh
      - -c
      - |
        echo "ADD CONNECTOR mg TYPE memgraph URI 'memgraph:7687' GRAPH memgraph;" | mgconsole --host memgql --port 7688 &&
        echo "ADD CONNECTOR pg TYPE postgres URI 'host=postgres user=postgres password=postgres dbname=postgres';" | mgconsole --host memgql --port 7688 &&
        echo "CREATE GRAPH social FROM FILE '/mappings/pg_mapping.json';" | mgconsole --host memgql --port 7688 &&
        echo "MemGQL bootstrap complete."
    depends_on:
      memgql:
        condition: service_healthy
      postgres:
        condition: service_healthy
    networks:
      - memgql-net
    restart: "no"

  memgraph:
    image: memgraph/memgraph-mage:3.13.1
    container_name: memgraph
    ports:
      - "7687:7687"
    command: --log-level=TRACE --also-log-to-stderr
    environment:
      MEMGRAPH_ENTERPRISE_LICENSE: ${MEMGRAPH_ENTERPRISE_LICENSE:-}
      MEMGRAPH_ORGANIZATION_NAME: ${MEMGRAPH_ORGANIZATION_NAME:-}
    healthcheck:
      test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/localhost/7687'"]
      interval: 2s
      timeout: 2s
      retries: 15
      start_period: 3s
    networks:
      - memgql-net

  lab:
    image: memgraph/lab:3.13.1
    container_name: lab
    ports:
      - "3000:3000"
    environment:
      QUICK_CONNECT_MG_HOST: memgql
      QUICK_CONNECT_MG_PORT: 7688
    depends_on:
      - memgql
    networks:
      - memgql-net

  postgres:
    image: postgres:18
    container_name: postgres
    ports:
      - "5432:5432"
    environment:
      POSTGRES_PASSWORD: postgres
    volumes:
      - ./pg_init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 2s
      timeout: 2s
      retries: 15
      start_period: 3s
    networks:
      - memgql-net

  memgql-mcp:
    image: memgraph/memgql-mcp:0.2.0
    container_name: memgql-mcp
    ports:
      - "8000:8000"
    environment:
      MCP_TRANSPORT: streamable-http
      MEMGQL_URL: bolt://memgql:7688
    depends_on:
      - memgql
    networks:
      - memgql-net

  structured2graph:
    image: memgraph/structured2graph:0.2.2
    container_name: structured2graph
    entrypoint: ["sleep", "infinity"]
    volumes:
      - memgql-mappings:/mappings
    depends_on:
      memgraph:
        condition: service_healthy
    networks:
      - memgql-net

volumes:
  memgql-mappings:
    name: memgql-mappings

networks:
  memgql-net:
    name: memgql-net
    external: true
```

## 4. Start all services

```bash
docker compose up -d
```

Wait for all containers to become healthy:

```bash
docker compose ps
```

You should see all eight services running: `memgraph`, `memgql`, `memgql-init`,
`lab`, `postgres`, `memgql-mcp`, and `structured2graph`. The `memgql-init`
container registers both connectors and exits; this is expected.

## 5. Connect with mgconsole

```bash
mgconsole --port 7688
```

The `mg` and `pg` connectors and the `social` graph (over PostgreSQL) are
already registered by the `memgql-init` service. We add the native Memgraph
graph below, then query each by its labels: routing picks the graph, so no
`USE` is required.

### Seed Memgraph with developers

Register a native graph over the Memgraph connector, then insert developers (the
`Developer` label routes to `dev`):

```gql
CREATE GRAPH dev FROM '{
  "vertices": [ { "label": "Developer", "mappedGraphSource": { "connector": "mg" } } ],
  "edges":    [ { "label": "FOLLOWS", "from": "Developer", "to": "Developer", "mappedGraphSource": { "connector": "mg" } } ]
}';
```

```gql
INSERT
  (lana:Developer {name: "Lana", level: "senior", yoe: 12}),
  (marco:Developer {name: "Marco", level: "mid", yoe: 5}),
  (priya:Developer {name: "Priya", level: "senior", yoe: 9}),
  (tom:Developer {name: "Tom", level: "junior", yoe: 1}),
  (sara:Developer {name: "Sara", level: "mid", yoe: 4}),
  (lana)-[:FOLLOWS]->(priya),
  (marco)-[:FOLLOWS]->(sara),
  (sara)-[:FOLLOWS]->(lana),
  (tom)-[:FOLLOWS]->(marco),
  (priya)-[:FOLLOWS]->(lana);
```

```gql
MATCH (d:Developer) RETURN d.name, d.level, d.yoe;
```

```gql
MATCH (a:Developer)-[:FOLLOWS]->(b:Developer) RETURN a.name, b.name;
```

### Seed PostgreSQL with users

Insert users; the `User` label routes to the `social` graph (PostgreSQL):

```gql
INSERT (alice:User {name: "Alice", email: "alice@example.com"});
INSERT (bob:User {name: "Bob", email: "bob@example.com"});
INSERT (charlie:User {name: "Charlie", email: "charlie@example.com"});
INSERT (diana:User {name: "Diana", email: "diana@example.com"});
```

Add friendships:

```gql
MATCH (a:User {name: "Alice"}), (b:User {name: "Bob"}) INSERT (a)-[:FRIEND_OF]->(b);
MATCH (a:User {name: "Alice"}), (b:User {name: "Charlie"}) INSERT (a)-[:FRIEND_OF]->(b);
MATCH (a:User {name: "Bob"}), (b:User {name: "Diana"}) INSERT (a)-[:FRIEND_OF]->(b);
MATCH (a:User {name: "Charlie"}), (b:User {name: "Diana"}) INSERT (a)-[:FRIEND_OF]->(b);
```

```gql
MATCH (u:User) RETURN u.name, u.email;
```

```gql
MATCH (u:User)-[:FRIEND_OF]->(f:User) RETURN u.name, f.name;
```

### Query across both backends

```gql
MATCH (d:Developer)-[:FOLLOWS]->(f:Developer)
  RETURN d.name AS source, "FOLLOWS" AS rel, f.name AS target;
```

```gql
MATCH (u:User)-[:FRIEND_OF]->(f:User)
  RETURN u.name AS source, "FRIEND_OF" AS rel, f.name AS target;
```

## 6. Open Memgraph Lab

Open [http://localhost:3000](http://localhost:3000) in a browser.
Lab is pre-configured to connect to MemGQL on port 7688; click
**Quick Connect** and start exploring visually.

## 7. Create mappings with structured2graph

The `structured2graph` container generates JSON mapping files that tell MemGQL
how to translate graph patterns into relational queries. It runs with
`sleep infinity` so you can exec into it on demand.

Shell into the container:

```bash
docker exec -it structured2graph bash
```

Inside the container, configure and run:

```bash
# Copy the example config and edit it with your connection details
cp .env.example .env

# TODO: Adjust the .env file with the right values.

# Generate the mapping file (written to the shared /mappings volume)
structured2graph --mapping /mappings/social.json
```

Once the mapping is generated, it's available to MemGQL via the shared
`memgql-mappings` volume at `/mappings/social.json`. You can now load it
from a MemGQL session.

## 8. MCP server for AI agents

The MCP server exposes MemGQL over the Model Context Protocol on
`http://localhost:8000`. AI agents and tools that support MCP can connect
to run GQL queries against any backend wired into MemGQL.

## Port summary

| Service          | Port | Protocol          |
|------------------|------|-------------------|
| Memgraph         | 7687 | Bolt              |
| MemGQL           | 7688 | Bolt              |
| Memgraph Lab     | 3000 | HTTP              |
| PostgreSQL       | 5432 | PostgreSQL wire   |
| MemGQL MCP       | 8000 | HTTP (streamable) |

## Stopping everything

```bash
docker compose down
```

To also remove the shared volume:

```bash
docker compose down -v
```
