Skip to main content
Glama
simo21-ss

vechemoga-mcp-server

by simo21-ss

vechemoga-mcp-server

An MCP server that lets an AI assistant read VecheMoga's logs, query its database read-only, and inspect what the API actually sent to Loops and Stripe — without leaving the editor.

One server, two deployments, identical tool names. The only difference is where the data comes from:

local

dev AWS

URL

http://localhost:8417/mcp

https://mcp.dev.vechemoga.bg/mcp

Logs from

the Docker socket

CloudWatch Logs

Database

the local Postgres container

RDS, as vechemoga_mcp_reader

Auth

none (binds to localhost)

Authorization: Bearer … behind a security-group IP allowlist

Runs on

VecheMogaLocal's compose stack

the dev-tools EC2 box

That is MCP_LOG_BACKEND=docker|cloudwatch, one environment variable. It is deliberately one codebase: Sesame — the system this is ported from — has a local server.py and an AWS server.py that have drifted into ~1400 and ~1800 lines of largely duplicated tool code. Do not fork this to add an environment. Add a backend.

Dev only. There is no prod MCP server, on purpose. A bearer token that can SELECT from the production database and read every production log stream is a materially different risk decision, and not one that should arrive as a side effect of this repo.

Tools

Fifteen, all read-only. Tools whose source is not configured in a given deployment are not registered at all — an assistant that cannot see deploy_status locally will pick another route, whereas one that calls it and gets an error will not.

PostgreSQLpg_list_schemas, pg_list_tables, pg_describe_table, pg_query, pg_migration_status

pg_query takes a single SELECT / WITH … SELECT / EXPLAIN SELECT, adds a LIMIT when there is none, caps at 200 rows, and runs under SET TRANSACTION READ ONLY with a 10s statement timeout. That is the second lock, not the first — see Read-only below. pg_migration_status reads Liquibase's databasechangelog, which answers "did this environment actually run the migration I merged?"

Logsapi_logs, api_liquibase_logs, web_logs, wiremock_logs, postgres_logs, pipeline_logs, automation_logs

All take the same four arguments: tail, since, until, grep. grep is applied after retrieval, so narrowing with since/until beats a large tail. automation_logs earns its place: a green Allure report can hide a failed Before/After hook, and the CodeBuild log is the only place that failure is visible.

WireMockwiremock_list_mappings, wiremock_find_requests

wiremock_find_requests answers did the API actually call Loops, and with what body? — which CloudWatch cannot, because WireMock's request logging is deliberately switched off so that verification links never reach a log group. Strictly the read-only subset of the admin API: no mapping registration, and never /__admin/reset or a DELETE. Parallel Cucumber workers and manual developers share that service and a global reset takes their work with it.

Deliverydeploy_status

codepipeline:GetPipelineState across the pipelines, including vechemoga-infra. Answers "is dev running the commit I think it is?" and "is an infra change sitting at the approval gate?" It cannot start, approve or retry anything.

Related MCP server: KVMFleet MCP Server

Read-only

Worth being precise about, because "the server only sends SELECTs" is not a security property — it is a hope about a program.

  1. The PostgreSQL role is the guarantee. vechemoga_mcp_reader holds pg_read_all_data — read on every schema and table including ones created later, and no write grant of any kind — with default_transaction_read_only = on. A bug in this repo cannot write to that database, because the credential it holds cannot. Verified against the real database: writes are refused with "cannot execute … in a read-only transaction", and a schema created after the grant is readable without one.

  2. The security group is the second. It permits a TCP connection from the dev-tools box and the API box. What that connection may do is decided in (1).

  3. The SQL guard in pg_query is the third, and its job is to turn a mistake into a clear error rather than a permission denial.

The build refuses to push if (3) regresses — buildspec-build.yml drives DELETE, UPDATE, DROP, INSERT and a stacked SELECT 1; DROP TABLE through it and fails if any is accepted.

Why no port 80

The dev-tools security group allows 443 from a handful of named operator addresses and nothing else. An HTTP-01 or TLS-ALPN-01 ACME challenge must be answerable from Let's Encrypt's own validation addresses, which are not knowable in advance — either would force a port open to 0.0.0.0/0 and demote that allowlist from a security-group boundary to an application-layer matcher.

So Caddy proves the certificate over a Route 53 DNS-01 challenge, which needs no inbound reachability at all. That is what caddy/Dockerfile is for (xcaddy with caddy-dns/route53), and the build fails if the plugin is missing rather than letting the box fall back to a challenge that cannot work.

If certificate issuance fails, fix the Route 53 grant — do not open port 80.

What the server logs

Which tool ran and with which argument names. Never results. A pg_query answer or a WireMock journal entry would put database rows and verification links into /vechemoga/dev/mcp-server, where they would then live for 30 days — the exact hazard WireMock's own request logging is kept off to avoid.

Local development

The image is pulled from ECR by VecheMogaLocal's compose stack. To work on the server itself:

pip install -r requirements.txt
MCP_LOG_BACKEND=docker \
MCP_DOCKER_CONTAINERS='{"api":"api","web":"web","postgres":"postgres","wiremock":"provider-proxy"}' \
POSTGRES_HOST=localhost POSTGRES_USER=vechemoga POSTGRES_PASSWORD=vechemoga POSTGRES_SSLMODE=disable \
WIREMOCK_ADMIN_URL=http://localhost:1080 \
python server.py

Then point your editor at http://localhost:8417/mcp. Those are compose service names: the server tries an exact container name first and falls back to the com.docker.compose.service label, so service names work and survive a project rename or a replica-index change — which vechemoga-local-api-1 would not.

Do not test the endpoint with curl. It speaks MCP, not REST; a curl against /mcp tells you nothing except that TLS and auth work. Validate by asking your assistant to call a tool, e.g. "list the schemas in the dev database".

Deployment

Two pipelines write to the dev-tools box, and this repo owns the compose file both of them deploy into — exactly as VecheMogaApi/deploy owns the file the provider-mock pipeline deploys into today:

Pipeline

Deploys

vechemoga-mcp-server

mcp-server + caddy

vechemoga-provider-proxy

provider-proxy (WireMock)

Source (GitHub main, CodeConnections)
  └─▶ Build   CodeBuild ARM · buildspec-build.yml
        docker build ×2 (server + caddy, native arm64) → smoke checks
        → ECR :<sha12>  (only if the checks passed)
  └─▶ Deploy  CodeBuild · buildspec-deploy.yml → infra/deploy-to-instance.sh
        SSM Run Command on the dev-tools box: pull the pinned tags, up, health-check

Deploys are pinned to the git SHA. Rollback is Release change on an older execution, or IMAGE_TAG=<old-sha> ./infra/deploy-to-instance.sh from a laptop.

The Deploy stage skips green when the box is absent or stopped — it sleeps nightly 23:30–07:45 Europe/Sofia. A pipeline that goes red every evening for a working reason teaches everyone to stop reading it.

One-time, on the box

Both pipelines run docker compose against a checkout of this repo on the box — they deploy images, they do not copy files. So the checkout has to exist before the first deploy, exactly as vechemoga-api is cloned onto the API box. Via SSM Session Manager (no SSH):

sudo git clone https://github.com/simo21-ss/vechemoga-mcp-server.git /opt/vechemoga-devtools
sudo chown -R ec2-user:ec2-user /opt/vechemoga-devtools

Since 2026-08-09 both deploy scripts git pull --ff-only this checkout before running docker compose, so a merged compose change reaches the box on the next deploy of either pipeline. Nothing did that before, and the gap was invisible: the checkout sat at a 2026-08-07 commit with no FETCH_HEAD at all, and a raised memory limit stayed unapplied while the repo, the pipeline and the deploy log all reported success. Anything shipped inside an image was always current — only the file drifted, which is exactly why it went unnoticed.

The pull is fatal on failure, and the deploy scripts refuse to pull a checkout whose origin is not this repo. --ff-only can fail only on a dirty tree or a diverged branch, both of which mean somebody edited the box by hand — composing over a file in that state is the thing being prevented. deploy/.env is gitignored and untouched.

COMPOSE_DIR is therefore /opt/vechemoga-devtools/deploy — the clone root plus this directory. It is set by Terraform on both deploy projects rather than left to the buildspecs, because CodeBuild resolves an environment variable from the build project definition ahead of the buildspec, and the target box and its compose path have to move together.

deploy/.env holds the non-secret wiring (the file is not committed; secrets are read from SSM on the box at deploy time, by the instance role):

cat >> /opt/vechemoga-devtools/.env <<'EOF'
DB_HOST=veche-moga-db-dev.<...>.eu-central-1.rds.amazonaws.com
MCP_HOST=mcp.dev.vechemoga.bg
MCP_ALLOWED_IPS=0.0.0.0/0
MCP_LOG_GROUPS='{"api":"/vechemoga/dev/api","wiremock":"/vechemoga/dev/provider-proxy","web":"/aws/amplify/<app-id>","pipeline":"/vechemoga/cicd/dev/deploy","automation":"/vechemoga/cicd/automation/test"}'
MCP_PIPELINES=vechemoga-api-dev,vechemoga-web-dev,vechemoga-provider-proxy,vechemoga-automation,vechemoga-mcp-server,vechemoga-infra
PROVIDER_PROXY_IMAGE=<account>.dkr.ecr.eu-central-1.amazonaws.com/vechemoga/provider-proxy
EOF

The single quotes around MCP_LOG_GROUPS are load-bearing. infra/deploy-to-instance.sh sources this file with set -a; . ./.env, and the shell performs quote removal — so an unquoted {"api":"…"} reaches the container as {api:…}, which is not JSON, and the server exits at import. Observed on the first real deploy, as a crash loop.

And two SecureStrings, created by hand so their values never enter Terraform state — /vechemoga/dev/MCP_AUTH_TOKEN and /vechemoga/dev/MCP_DB_PASSWORD, plus the vechemoga_mcp_reader role. Runbook: VecheMogaInfra README → "Bring up the dev-tools box".

Infrastructure

The box, its security group, its IAM role, the ECR repositories and the pipeline are Terraform-managed in VecheMogaInfra (modules/dev-tools, modules/cicd-mcp, global/ecr.tf). This repo owns only what runs on the box. The design and its rollout are in VecheMogaInfra/docs/mcp-server-plan.md.

Routing: which server to ask

Both servers expose the same tool names. Only the target differs, which is what makes a routing rule necessary rather than obvious.

server

URL

reads

vechemoga-local

http://127.0.0.1:8417/mcp

the local compose stack (VecheMogaLocal)

vechemoga-dev

https://mcp.dev.vechemoga.bg/mcp

the dev environment — CloudWatch, RDS, pipelines

Default to local. Reach for vechemoga-dev only when the question is explicitly about dev, AWS, CloudWatch, a pipeline or the deployed environment — or when local genuinely cannot answer it. Say which one you are using, in one short sentence, before the first tool call, so the answer can be read in context.

Don't query both in one response unless the request is a comparison. If the intent is ambiguous, ask one short question rather than guessing.

Never test an MCP server with curl. It speaks MCP, not REST: a curl tells you TLS and auth work and nothing else. Validate by calling a tool.

Things that save a wrong turn

  • pg_query is read-only at the databasevechemoga_mcp_reader holds pg_read_all_data and no write grant. A single SELECT, capped at 200 rows, 10s statement timeout.

  • On dev, api_logs reads CloudWatch. docker logs on that box returns nothing at all — every container there uses the awslogs driver.

  • Locally, the log tools read containers. A service run outside Docker (./run.sh no-api) has none, and its logs are not reachable from the server.

  • automation_logs (dev only) is where a failed Before/After hook shows up when the Allure report is green.

  • wiremock_find_requests answers "did the API actually call Loops, and with what body?" — CloudWatch cannot, because WireMock's request logging is deliberately off so that verification links never reach a log group.

  • deploy_status answers "is dev running the commit I think it is?" without leaving the editor. It cannot start, approve or retry anything.

Adding the servers to your editor

claude mcp add --transport http vechemoga-local http://127.0.0.1:8417/mcp
claude mcp add --transport http vechemoga-dev https://mcp.dev.vechemoga.bg/mcp --header "Authorization: Bearer $(aws ssm get-parameter --profile vechemoga-terraform --region eu-central-1 --name /vechemoga/dev/MCP_AUTH_TOKEN --with-decryption --query Parameter.Value --output text)"

Deliberately not a committed .mcp.json. The dev entry carries a bearer token, which must not enter a repo; and a committed local entry would show as a failed server for every developer who is not currently running the local stack. User-scoped registration keeps both problems away.

The token is the only lock on the dev one, since 2026-08-09. It used to sit behind a per-operator /32 in mcp_allowed_ips (VecheMogaInfra envs/dev/terraform.tfvars) and a matching MCP_ALLOWED_IPS on the box; that pair was pinned to a residential address that moved on a DHCP lease, in two places nothing kept in sync, and it failed silently every time — so it was opened rather than maintained.

Treat the token accordingly: it is now complete read access to the dev database and every dev log stream, with nothing behind it. Rotate it on any exposure —

aws ssm put-parameter --profile vechemoga-terraform --region eu-central-1 \
  --name /vechemoga/dev/MCP_AUTH_TOKEN --type SecureString --overwrite \
  --value "$(openssl rand -hex 32)"
aws codepipeline start-pipeline-execution --profile vechemoga-terraform \
  --region eu-central-1 --name vechemoga-mcp-server

then re-register the client with the new value. Narrowing back to an allowlist means editing both places together — see deploy/Caddyfile, which keeps the matcher for exactly that.

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    -
    quality
    C
    maintenance
    A read-only PostgreSQL MCP server that enables AI agents to perform schema introspection and execute SELECT-only queries. It supports secure database connections through SSL and SSH tunnels while offering a structure-only mode to restrict query access.
    36
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Read-only MCP server that allows AI assistants to query and monitor KVM Fleet devices, audit logs, and console sessions through the official REST API.
    5
    11
    1
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Read-only MCP server for on-prem Linux VMs and PostgreSQL over SSH. Check service health, retrieve bounded logs, inspect DB state, and explore table schemas — without terminal access.
    10
    1
    MIT
  • A
    license
    -
    quality
    B
    maintenance
    Read-only MCP server for MOJAQ: give any AI assistant natural-language access to your EU-hosted app's deploys, errors, logs, uptime and incidents.
    9
    MIT

View all related MCP servers

Related MCP Connectors

  • Read-only MCP server for ClassQuill, a tutoring-business-management platform.

  • MCP server for managing Prisma Postgres.

  • MCP server for interacting with the Supabase platform

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/simo21-ss/vechemoga-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server