tabulus 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tabulus-0.0.1/.github/workflows/ci.yml +75 -0
- tabulus-0.0.1/.github/workflows/publish.yml +51 -0
- tabulus-0.0.1/.gitignore +17 -0
- tabulus-0.0.1/.mcp.json +14 -0
- tabulus-0.0.1/LICENSE +21 -0
- tabulus-0.0.1/PKG-INFO +144 -0
- tabulus-0.0.1/README.md +118 -0
- tabulus-0.0.1/pyproject.toml +51 -0
- tabulus-0.0.1/src/vigil/__init__.py +3 -0
- tabulus-0.0.1/src/vigil/cli.py +69 -0
- tabulus-0.0.1/src/vigil/config.py +29 -0
- tabulus-0.0.1/src/vigil/db.py +196 -0
- tabulus-0.0.1/src/vigil/redactor.py +96 -0
- tabulus-0.0.1/src/vigil/safety.py +95 -0
- tabulus-0.0.1/src/vigil/server.py +155 -0
- tabulus-0.0.1/tests/__init__.py +0 -0
- tabulus-0.0.1/tests/test_redactor.py +138 -0
- tabulus-0.0.1/tests/test_safety.py +113 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, "pivot/**"]
|
|
6
|
+
tags: ["v*.*.*"]
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
test:
|
|
18
|
+
name: Python ${{ matrix.python }}
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
strategy:
|
|
21
|
+
fail-fast: false
|
|
22
|
+
matrix:
|
|
23
|
+
python: ["3.11", "3.12"]
|
|
24
|
+
|
|
25
|
+
services:
|
|
26
|
+
postgres:
|
|
27
|
+
image: postgres:16
|
|
28
|
+
env:
|
|
29
|
+
POSTGRES_PASSWORD: test
|
|
30
|
+
ports:
|
|
31
|
+
- 5432:5432
|
|
32
|
+
options: >-
|
|
33
|
+
--health-cmd pg_isready
|
|
34
|
+
--health-interval 5s
|
|
35
|
+
--health-timeout 3s
|
|
36
|
+
--health-retries 5
|
|
37
|
+
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
|
|
41
|
+
- uses: actions/setup-python@v5
|
|
42
|
+
with:
|
|
43
|
+
python-version: ${{ matrix.python }}
|
|
44
|
+
cache: pip
|
|
45
|
+
cache-dependency-path: pyproject.toml
|
|
46
|
+
|
|
47
|
+
- name: Install
|
|
48
|
+
run: pip install -e ".[dev]"
|
|
49
|
+
|
|
50
|
+
- name: Lint
|
|
51
|
+
run: ruff check .
|
|
52
|
+
|
|
53
|
+
- name: Format check
|
|
54
|
+
run: ruff format --check .
|
|
55
|
+
|
|
56
|
+
- name: Unit tests
|
|
57
|
+
run: pytest tests/ -v --tb=short
|
|
58
|
+
|
|
59
|
+
- name: Integration smoke (live Postgres)
|
|
60
|
+
env:
|
|
61
|
+
DATABASE_URL: postgres://postgres:test@localhost:5432/postgres
|
|
62
|
+
run: |
|
|
63
|
+
python -c "
|
|
64
|
+
import asyncio
|
|
65
|
+
from vigil.config import load
|
|
66
|
+
from vigil.db import get_pool, list_tables, close_pool
|
|
67
|
+
async def main():
|
|
68
|
+
pool = await get_pool(load())
|
|
69
|
+
await pool.execute('CREATE TABLE smoke (id int)')
|
|
70
|
+
tables = await list_tables(pool)
|
|
71
|
+
assert any(t['name'] == 'smoke' for t in tables), 'smoke table missing'
|
|
72
|
+
print('Integration OK')
|
|
73
|
+
await close_pool()
|
|
74
|
+
asyncio.run(main())
|
|
75
|
+
"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*.*.*"]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
id-token: write # required for PyPI trusted publishing
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
name: Build wheel + sdist
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
|
|
23
|
+
- name: Install build tools
|
|
24
|
+
run: pip install build
|
|
25
|
+
|
|
26
|
+
- name: Build
|
|
27
|
+
run: python -m build
|
|
28
|
+
|
|
29
|
+
- name: Upload artifacts
|
|
30
|
+
uses: actions/upload-artifact@v4
|
|
31
|
+
with:
|
|
32
|
+
name: dist
|
|
33
|
+
path: dist/
|
|
34
|
+
|
|
35
|
+
publish:
|
|
36
|
+
name: Publish to PyPI
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
needs: build
|
|
39
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
40
|
+
environment:
|
|
41
|
+
name: pypi
|
|
42
|
+
url: https://pypi.org/p/tabulus
|
|
43
|
+
steps:
|
|
44
|
+
- name: Download artifacts
|
|
45
|
+
uses: actions/download-artifact@v4
|
|
46
|
+
with:
|
|
47
|
+
name: dist
|
|
48
|
+
path: dist/
|
|
49
|
+
|
|
50
|
+
- name: Publish via OIDC (no API token)
|
|
51
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
tabulus-0.0.1/.gitignore
ADDED
tabulus-0.0.1/.mcp.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"vigil": {
|
|
4
|
+
"command": ".venv/bin/vigil",
|
|
5
|
+
"args": [],
|
|
6
|
+
"env": {
|
|
7
|
+
"DATABASE_URL": "postgres://postgres:dev@localhost:5433/postgres",
|
|
8
|
+
"VIGIL_MAX_ROWS": "100",
|
|
9
|
+
"VIGIL_SAMPLE_SIZE": "3",
|
|
10
|
+
"VIGIL_STATEMENT_TIMEOUT_MS": "5000"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
tabulus-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 WalkingMountain
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
tabulus-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tabulus
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Postgres MCP server — agent-first database workbench
|
|
5
|
+
Project-URL: Repository, https://github.com/WalkingMountain/vigilmcp
|
|
6
|
+
Project-URL: Issues, https://github.com/WalkingMountain/vigilmcp/issues
|
|
7
|
+
Author: WalkingMountain
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agent,claude,cursor,database,mcp,postgres,sql
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Database
|
|
17
|
+
Requires-Python: >=3.11
|
|
18
|
+
Requires-Dist: asyncpg>=0.30
|
|
19
|
+
Requires-Dist: mcp>=1.0.0
|
|
20
|
+
Requires-Dist: pydantic>=2.0
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: ruff>=0.7; extra == 'dev'
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# Vigil
|
|
28
|
+
|
|
29
|
+
**A Postgres MCP server built for AI agents.**
|
|
30
|
+
|
|
31
|
+
Vigil is the database workbench for the AI-augmented developer. Connect Claude
|
|
32
|
+
Code, Cursor, or any MCP-compatible client to your Postgres database and let
|
|
33
|
+
the agent introspect the schema, sample data, and write safe queries — without
|
|
34
|
+
copy-pasting schemas into chat windows.
|
|
35
|
+
|
|
36
|
+
## Why
|
|
37
|
+
|
|
38
|
+
Every modern dev workflow now includes an AI agent. Every DB GUI was designed
|
|
39
|
+
before that was true. Vigil flips the model: **the agent is a first-class user,
|
|
40
|
+
not a sidebar feature.**
|
|
41
|
+
|
|
42
|
+
What that means in practice:
|
|
43
|
+
|
|
44
|
+
- Schema introspection optimized for LLM context windows (compact JSON, foreign
|
|
45
|
+
keys flattened, sample rows inline).
|
|
46
|
+
- Read-only by default — `INSERT`/`UPDATE`/`DELETE`/`DDL` are rejected at the
|
|
47
|
+
gateway. Agent can't drop your tables.
|
|
48
|
+
- `EXPLAIN` exposed as a tool so the agent can reason about query plans before
|
|
49
|
+
proposing optimizations.
|
|
50
|
+
- Statement timeout + row cap enforced server-side. No agent can DOS your
|
|
51
|
+
database by accident.
|
|
52
|
+
|
|
53
|
+
## Status
|
|
54
|
+
|
|
55
|
+
**v0.0.1 — alpha.** Postgres only. Stdio MCP transport only. No GUI yet.
|
|
56
|
+
|
|
57
|
+
## Install
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install tabulus
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Run
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
export DATABASE_URL=postgres://user:pass@host:5432/dbname
|
|
67
|
+
vigil
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Then point your MCP client at the `vigil` command.
|
|
71
|
+
|
|
72
|
+
### Claude Code (project-level)
|
|
73
|
+
|
|
74
|
+
Create `.mcp.json` in your project root:
|
|
75
|
+
|
|
76
|
+
```jsonc
|
|
77
|
+
{
|
|
78
|
+
"mcpServers": {
|
|
79
|
+
"vigil": {
|
|
80
|
+
"command": "vigil",
|
|
81
|
+
"args": [],
|
|
82
|
+
"env": {
|
|
83
|
+
"DATABASE_URL": "postgres://user:pass@host:5432/dbname"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Restart Claude Code in that directory and approve the trust prompt.
|
|
91
|
+
|
|
92
|
+
### Claude Code (user-level via CLI)
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
claude mcp add vigil "$(which vigil)" --env DATABASE_URL=postgres://user:pass@host:5432/dbname
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Cursor
|
|
99
|
+
|
|
100
|
+
Add to `~/.cursor/mcp_servers.json`:
|
|
101
|
+
|
|
102
|
+
```jsonc
|
|
103
|
+
{
|
|
104
|
+
"mcpServers": {
|
|
105
|
+
"vigil": {
|
|
106
|
+
"command": "vigil",
|
|
107
|
+
"env": { "DATABASE_URL": "postgres://user:pass@host:5432/dbname" }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Tools
|
|
114
|
+
|
|
115
|
+
| Tool | Description |
|
|
116
|
+
|---|---|
|
|
117
|
+
| `list_tables` | All tables with row count estimates + sizes |
|
|
118
|
+
| `describe_schema` | Columns, PK, FKs, indexes, sample rows for a table |
|
|
119
|
+
| `sample_rows` | Random sample from a table |
|
|
120
|
+
| `safe_select` | Run a read-only SELECT (write keywords rejected) |
|
|
121
|
+
| `explain` | Get query plan (EXPLAIN FORMAT JSON) |
|
|
122
|
+
|
|
123
|
+
## Configuration
|
|
124
|
+
|
|
125
|
+
| Variable | Default | Purpose |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| `DATABASE_URL` | — (required) | Postgres connection URL |
|
|
128
|
+
| `VIGIL_MAX_ROWS` | `100` | Hard cap on rows returned by any tool |
|
|
129
|
+
| `VIGIL_SAMPLE_SIZE` | `3` | Sample rows included in `describe_schema` |
|
|
130
|
+
| `VIGIL_STATEMENT_TIMEOUT_MS` | `5000` | Server-side query timeout |
|
|
131
|
+
| `VIGIL_REDACT` | `off` | Set `on` to scrub PII (emails, API keys, JWTs, credit cards, phones, IPs) from `sample_rows`, `safe_select`, and `describe_schema` output before the agent sees it. Recommended for production. |
|
|
132
|
+
| `VIGIL_ALLOW_WRITES` | `false` | Set `true` to disable the write block (NOT recommended) |
|
|
133
|
+
|
|
134
|
+
## Roadmap
|
|
135
|
+
|
|
136
|
+
- v0.1 — Postgres parity, polished install
|
|
137
|
+
- v0.2 — SQLite adapter
|
|
138
|
+
- v0.3 — MySQL / MariaDB adapter
|
|
139
|
+
- v0.x — Tauri desktop GUI shell on top of the same core
|
|
140
|
+
- v1.0 — Stable, cross-platform, multi-DB
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT. See [LICENSE](./LICENSE).
|
tabulus-0.0.1/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Vigil
|
|
2
|
+
|
|
3
|
+
**A Postgres MCP server built for AI agents.**
|
|
4
|
+
|
|
5
|
+
Vigil is the database workbench for the AI-augmented developer. Connect Claude
|
|
6
|
+
Code, Cursor, or any MCP-compatible client to your Postgres database and let
|
|
7
|
+
the agent introspect the schema, sample data, and write safe queries — without
|
|
8
|
+
copy-pasting schemas into chat windows.
|
|
9
|
+
|
|
10
|
+
## Why
|
|
11
|
+
|
|
12
|
+
Every modern dev workflow now includes an AI agent. Every DB GUI was designed
|
|
13
|
+
before that was true. Vigil flips the model: **the agent is a first-class user,
|
|
14
|
+
not a sidebar feature.**
|
|
15
|
+
|
|
16
|
+
What that means in practice:
|
|
17
|
+
|
|
18
|
+
- Schema introspection optimized for LLM context windows (compact JSON, foreign
|
|
19
|
+
keys flattened, sample rows inline).
|
|
20
|
+
- Read-only by default — `INSERT`/`UPDATE`/`DELETE`/`DDL` are rejected at the
|
|
21
|
+
gateway. Agent can't drop your tables.
|
|
22
|
+
- `EXPLAIN` exposed as a tool so the agent can reason about query plans before
|
|
23
|
+
proposing optimizations.
|
|
24
|
+
- Statement timeout + row cap enforced server-side. No agent can DOS your
|
|
25
|
+
database by accident.
|
|
26
|
+
|
|
27
|
+
## Status
|
|
28
|
+
|
|
29
|
+
**v0.0.1 — alpha.** Postgres only. Stdio MCP transport only. No GUI yet.
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install tabulus
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Run
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
export DATABASE_URL=postgres://user:pass@host:5432/dbname
|
|
41
|
+
vigil
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Then point your MCP client at the `vigil` command.
|
|
45
|
+
|
|
46
|
+
### Claude Code (project-level)
|
|
47
|
+
|
|
48
|
+
Create `.mcp.json` in your project root:
|
|
49
|
+
|
|
50
|
+
```jsonc
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"vigil": {
|
|
54
|
+
"command": "vigil",
|
|
55
|
+
"args": [],
|
|
56
|
+
"env": {
|
|
57
|
+
"DATABASE_URL": "postgres://user:pass@host:5432/dbname"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Restart Claude Code in that directory and approve the trust prompt.
|
|
65
|
+
|
|
66
|
+
### Claude Code (user-level via CLI)
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
claude mcp add vigil "$(which vigil)" --env DATABASE_URL=postgres://user:pass@host:5432/dbname
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Cursor
|
|
73
|
+
|
|
74
|
+
Add to `~/.cursor/mcp_servers.json`:
|
|
75
|
+
|
|
76
|
+
```jsonc
|
|
77
|
+
{
|
|
78
|
+
"mcpServers": {
|
|
79
|
+
"vigil": {
|
|
80
|
+
"command": "vigil",
|
|
81
|
+
"env": { "DATABASE_URL": "postgres://user:pass@host:5432/dbname" }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Tools
|
|
88
|
+
|
|
89
|
+
| Tool | Description |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `list_tables` | All tables with row count estimates + sizes |
|
|
92
|
+
| `describe_schema` | Columns, PK, FKs, indexes, sample rows for a table |
|
|
93
|
+
| `sample_rows` | Random sample from a table |
|
|
94
|
+
| `safe_select` | Run a read-only SELECT (write keywords rejected) |
|
|
95
|
+
| `explain` | Get query plan (EXPLAIN FORMAT JSON) |
|
|
96
|
+
|
|
97
|
+
## Configuration
|
|
98
|
+
|
|
99
|
+
| Variable | Default | Purpose |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| `DATABASE_URL` | — (required) | Postgres connection URL |
|
|
102
|
+
| `VIGIL_MAX_ROWS` | `100` | Hard cap on rows returned by any tool |
|
|
103
|
+
| `VIGIL_SAMPLE_SIZE` | `3` | Sample rows included in `describe_schema` |
|
|
104
|
+
| `VIGIL_STATEMENT_TIMEOUT_MS` | `5000` | Server-side query timeout |
|
|
105
|
+
| `VIGIL_REDACT` | `off` | Set `on` to scrub PII (emails, API keys, JWTs, credit cards, phones, IPs) from `sample_rows`, `safe_select`, and `describe_schema` output before the agent sees it. Recommended for production. |
|
|
106
|
+
| `VIGIL_ALLOW_WRITES` | `false` | Set `true` to disable the write block (NOT recommended) |
|
|
107
|
+
|
|
108
|
+
## Roadmap
|
|
109
|
+
|
|
110
|
+
- v0.1 — Postgres parity, polished install
|
|
111
|
+
- v0.2 — SQLite adapter
|
|
112
|
+
- v0.3 — MySQL / MariaDB adapter
|
|
113
|
+
- v0.x — Tauri desktop GUI shell on top of the same core
|
|
114
|
+
- v1.0 — Stable, cross-platform, multi-DB
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
MIT. See [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tabulus"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "Postgres MCP server — agent-first database workbench"
|
|
5
|
+
authors = [{name = "WalkingMountain"}]
|
|
6
|
+
license = {text = "MIT"}
|
|
7
|
+
requires-python = ">=3.11"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
keywords = ["postgres", "mcp", "claude", "cursor", "database", "agent", "sql"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 3 - Alpha",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Programming Language :: Python :: 3.11",
|
|
15
|
+
"Programming Language :: Python :: 3.12",
|
|
16
|
+
"Topic :: Database",
|
|
17
|
+
]
|
|
18
|
+
dependencies = [
|
|
19
|
+
"mcp>=1.0.0",
|
|
20
|
+
"asyncpg>=0.30",
|
|
21
|
+
"pydantic>=2.0",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.optional-dependencies]
|
|
25
|
+
dev = [
|
|
26
|
+
"pytest>=8.0",
|
|
27
|
+
"pytest-asyncio>=0.24",
|
|
28
|
+
"ruff>=0.7",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
vigil = "vigil.cli:main"
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Repository = "https://github.com/WalkingMountain/vigilmcp"
|
|
36
|
+
Issues = "https://github.com/WalkingMountain/vigilmcp/issues"
|
|
37
|
+
|
|
38
|
+
[build-system]
|
|
39
|
+
requires = ["hatchling"]
|
|
40
|
+
build-backend = "hatchling.build"
|
|
41
|
+
|
|
42
|
+
[tool.hatch.build.targets.wheel]
|
|
43
|
+
packages = ["src/vigil"]
|
|
44
|
+
|
|
45
|
+
[tool.ruff]
|
|
46
|
+
line-length = 100
|
|
47
|
+
target-version = "py311"
|
|
48
|
+
|
|
49
|
+
[tool.pytest.ini_options]
|
|
50
|
+
asyncio_mode = "auto"
|
|
51
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""CLI entry point — `vigil` command.
|
|
2
|
+
|
|
3
|
+
Wraps startup errors in friendly messages so the agent / user sees actionable
|
|
4
|
+
hints instead of stack traces.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from vigil import __version__
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main() -> None:
|
|
13
|
+
if "--version" in sys.argv or "-V" in sys.argv:
|
|
14
|
+
print(f"vigil {__version__}")
|
|
15
|
+
return
|
|
16
|
+
|
|
17
|
+
if "--help" in sys.argv or "-h" in sys.argv:
|
|
18
|
+
print(
|
|
19
|
+
"vigil — Postgres MCP server for AI agents\n"
|
|
20
|
+
"\n"
|
|
21
|
+
"Usage:\n"
|
|
22
|
+
" DATABASE_URL=postgres://user:pass@host:5432/dbname vigil\n"
|
|
23
|
+
"\n"
|
|
24
|
+
"Environment variables:\n"
|
|
25
|
+
" DATABASE_URL required — Postgres connection string\n"
|
|
26
|
+
" VIGIL_MAX_ROWS default 100 — cap on rows returned\n"
|
|
27
|
+
" VIGIL_SAMPLE_SIZE default 3 — rows in describe_schema sample\n"
|
|
28
|
+
" VIGIL_STATEMENT_TIMEOUT_MS default 5000 — server-side query timeout\n"
|
|
29
|
+
" VIGIL_REDACT default off — set 'on' to scrub PII from output\n"
|
|
30
|
+
" VIGIL_ALLOW_WRITES default false — keep false (read-only)\n"
|
|
31
|
+
"\n"
|
|
32
|
+
"Repo: https://github.com/WalkingMountain/vigilmcp"
|
|
33
|
+
)
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
# Defer import so --version/--help don't pay the asyncio + mcp cost
|
|
38
|
+
from vigil.config import load
|
|
39
|
+
from vigil.server import main as run_server
|
|
40
|
+
|
|
41
|
+
# Fast-fail config validation BEFORE we open the stdio MCP loop —
|
|
42
|
+
# otherwise the agent waits until first tool call to learn DATABASE_URL
|
|
43
|
+
# is missing, which makes the failure mode confusing.
|
|
44
|
+
load()
|
|
45
|
+
run_server()
|
|
46
|
+
except RuntimeError as e:
|
|
47
|
+
# Config errors (missing DATABASE_URL, etc.) — already friendly
|
|
48
|
+
print(f"vigil: {e}", file=sys.stderr)
|
|
49
|
+
sys.exit(2)
|
|
50
|
+
except KeyboardInterrupt:
|
|
51
|
+
sys.exit(0)
|
|
52
|
+
except Exception as e:
|
|
53
|
+
# Last resort — show error class + message, hint at common causes
|
|
54
|
+
print(
|
|
55
|
+
f"vigil: unexpected error: {type(e).__name__}: {e}\n"
|
|
56
|
+
f"\n"
|
|
57
|
+
f"Common causes:\n"
|
|
58
|
+
f" - DATABASE_URL points at an unreachable host\n"
|
|
59
|
+
f" - Postgres requires SSL but the URL lacks ?sslmode=require\n"
|
|
60
|
+
f" - User in DATABASE_URL lacks CONNECT or USAGE privileges\n"
|
|
61
|
+
f"\n"
|
|
62
|
+
f"File an issue: https://github.com/WalkingMountain/vigilmcp/issues",
|
|
63
|
+
file=sys.stderr,
|
|
64
|
+
)
|
|
65
|
+
sys.exit(1)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
main()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Runtime config from environment variables."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class Config:
|
|
9
|
+
database_url: str
|
|
10
|
+
max_rows: int # cap on rows returned by any tool
|
|
11
|
+
sample_size: int # rows per describe_schema sample
|
|
12
|
+
statement_timeout_ms: int
|
|
13
|
+
allow_writes: bool # default False — agent gets read-only
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load() -> Config:
|
|
17
|
+
url = os.environ.get("DATABASE_URL")
|
|
18
|
+
if not url:
|
|
19
|
+
raise RuntimeError(
|
|
20
|
+
"DATABASE_URL is required. Set to a Postgres connection string "
|
|
21
|
+
"(postgres://user:pass@host:5432/dbname)."
|
|
22
|
+
)
|
|
23
|
+
return Config(
|
|
24
|
+
database_url=url,
|
|
25
|
+
max_rows=int(os.environ.get("VIGIL_MAX_ROWS", "100")),
|
|
26
|
+
sample_size=int(os.environ.get("VIGIL_SAMPLE_SIZE", "3")),
|
|
27
|
+
statement_timeout_ms=int(os.environ.get("VIGIL_STATEMENT_TIMEOUT_MS", "5000")),
|
|
28
|
+
allow_writes=os.environ.get("VIGIL_ALLOW_WRITES", "false").lower() == "true",
|
|
29
|
+
)
|