diff --git a/.cursor/mcp.json b/.cursor/mcp.json index 18536e1..c690441 100644 --- a/.cursor/mcp.json +++ b/.cursor/mcp.json @@ -2,6 +2,9 @@ "mcpServers": { "intai-mariadb": { "url": "http://127.0.0.1:8765/sse" + }, + "intai-postgres": { + "url": "http://127.0.0.1:8766/sse" } } } diff --git a/.env.example b/.env.example index 659bcb3..51ee988 100644 --- a/.env.example +++ b/.env.example @@ -43,3 +43,7 @@ INTAI_DOCKER_NETWORK=intai-docker_default MCP_MARIADB_PORT=8765 # Опционально: зафиксировать ревизию MariaDB/mcp при сборке образа (ветка или тег). # MARIADB_MCP_GIT_REF=main + +### MCP PostgreSQL (Cursor, Claude Code) ################## +# Host port for SSE; the same port must be in .cursor/mcp.json and .mcp.json of the project (url .../sse). +MCP_POSTGRES_PORT=8766 diff --git a/README.md b/README.md index b0e7443..6e5e1c3 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,24 @@ Optional MCP server so Cursor can query the `db` container over the Docker netwo First image build can take a while (upstream MariaDB MCP dependencies). +### PostgreSQL, pgAdmin, Postgres MCP + +Services `pgsql`, `pgadmin`, `mcp-postgres` are described in `docker-compose.base.yml`; copy them from +`docker-compose.postgres.yml.example` into your `docker-compose.yml` (volumes `database-pgsql` and `pgadmin` too). + +`dc up -d pgsql pgadmin mcp-postgres` + +- `pgsql` — official `postgres:18` image. Port `5432`, user, password and database `intai`. + Since 18 the data lives in `/var/lib/postgresql//docker`, so the volume is mounted at `/var/lib/postgresql`. + Another major version does not start on the same volume — dump and restore. +- `pgadmin` — pgAdmin 4 in desktop mode, no login: http://pgadmin.intai.localhost (or the port from the example). The `intai` server comes from `config/pgadmin/servers.json` on every start; the password (`intai`) is asked once, tick "Save password". + Register the server once: host `pgsql`, port `5432`, user `intai`, password `intai`. +- `mcp-postgres` — [Postgres MCP Pro](https://github.com/crystaldba/postgres-mcp), SSE on + `http://127.0.0.1:${MCP_POSTGRES_PORT:-8766}/sse`. +- `./bash/psql.sh [database] [user]` — psql inside the container. + +Transfer of the intai database from MariaDB and its verification: `docs/PostgreSQL.md` in the intai project. + ### Workspace For execute composer update|install or nodejs operations, also yarn, npm and all node-builds. diff --git a/bash/psql.sh b/bash/psql.sh new file mode 100755 index 0000000..66488c9 --- /dev/null +++ b/bash/psql.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# psql in the pgsql container. Usage: ./psql.sh [database] [user] — defaults: intai intai +SCRIPT_DIR="$(realpath $(dirname "$(readlink -f "$0")"))" + +. $SCRIPT_DIR/_docker-cmd.sh || { + echo "no docker cmd is presented" && exit 1 +} + +CONTAINER=$(docker ps --filter "label=com.docker.compose.service=pgsql" --format '{{.ID}}' | head -n1) + +if [[ -z "${CONTAINER}" ]]; then + echo "Unable to find container: pgsql" + exit 1 +fi + +$DOCKER_CMD exec -ti ${CONTAINER} psql -U "${2:-intai}" -d "${1:-intai}" diff --git a/config/pgadmin/servers.json b/config/pgadmin/servers.json new file mode 100644 index 0000000..5c6a966 --- /dev/null +++ b/config/pgadmin/servers.json @@ -0,0 +1,13 @@ +{ + "Servers": { + "1": { + "Name": "intai", + "Group": "Servers", + "Host": "pgsql", + "Port": 5432, + "MaintenanceDB": "intai", + "Username": "intai", + "SSLMode": "prefer" + } + } +} diff --git a/docker-compose.base.yml b/docker-compose.base.yml index 2a6368d..8fe10ae 100755 --- a/docker-compose.base.yml +++ b/docker-compose.base.yml @@ -93,6 +93,33 @@ services: PMA_HOST: db PMA_USER: root PMA_PASSWORD: 123456 + # PostgreSQL 18, official image. Since 18 the data lives in /var/lib/postgresql/18/docker, + # so the volume (declared in the compose file that extends this service) is mounted at /var/lib/postgresql. + pgsql: + image: postgres:18 + restart: always + environment: + POSTGRES_USER: intai + POSTGRES_PASSWORD: intai + POSTGRES_DB: intai + volumes: + - database-pgsql:/var/lib/postgresql + - ./hostfiles:/hostfiles + pgadmin: + image: dpage/pgadmin4:9 + restart: always + environment: + PGADMIN_DEFAULT_EMAIL: info@wpstudio.ru + PGADMIN_DEFAULT_PASSWORD: postgres + # desktop mode: no login page, a single local user + PGADMIN_CONFIG_SERVER_MODE: 'False' + PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: 'False' + # the intai server is registered from servers.json on every start + PGADMIN_SERVER_JSON_FILE: /pgadmin4/servers.json + PGADMIN_REPLACE_SERVERS_ON_STARTUP: 'True' + volumes: + - pgadmin:/var/lib/pgadmin + - ./config/pgadmin/servers.json:/pgadmin4/servers.json:ro inbucket: image: inbucket/inbucket restart: always @@ -154,3 +181,12 @@ services: LOG_FILE: /tmp/mcp_server.log ports: - "127.0.0.1:${MCP_MARIADB_PORT:-8765}:9001" + # Postgres MCP Pro (https://github.com/crystaldba/postgres-mcp), SSE like mcp-mariadb. + mcp-postgres: + image: crystaldba/postgres-mcp:0.3.0 + restart: unless-stopped + environment: + DATABASE_URI: postgresql://intai:intai@pgsql:5432/intai + command: [ "--transport=sse", "--sse-host=0.0.0.0" ] + ports: + - "127.0.0.1:${MCP_POSTGRES_PORT:-8766}:8000" diff --git a/docker-compose.postgres.yml.example b/docker-compose.postgres.yml.example index fda5e70..6705b90 100755 --- a/docker-compose.postgres.yml.example +++ b/docker-compose.postgres.yml.example @@ -1,27 +1,29 @@ +# PostgreSQL + pgAdmin 4 + Postgres MCP. Services are described in docker-compose.base.yml. +# +# Standalone: docker compose -f docker-compose.postgres.yml.example up -d +# Or copy the services into your docker-compose.yml next to db/pma (as intai does). services: - dbpg: - image: postgres - restart: always - environment: - POSTGRES_PASSWORD: postgres - volumes: - - databasepg:/var/lib/postgresql/data - - ./hostfiles:/hostfiles + pgsql: + extends: + file: docker-compose.base.yml + service: pgsql ports: - "5432:5432" - db-project: - image: postgis/postgis:14-3.3 - environment: - - POSTGRES_DB=project_db - - POSTGRES_USER=project_db_user - - POSTGRES_PASSWORD=project_db_password + pgadmin: + extends: + file: docker-compose.base.yml + service: pgadmin + depends_on: + - pgsql ports: - - "5434:5432" - healthcheck: - test: [ "CMD-SHELL", "pg_isready" ] - interval: 10s - timeout: 5s - retries: 5 + - "83:80" + mcp-postgres: + extends: + file: docker-compose.base.yml + service: mcp-postgres + depends_on: + - pgsql volumes: - databasepg: + database-pgsql: + pgadmin: