mcp-read-only-sql 0.1.0__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.
Files changed (89) hide show
  1. mcp_read_only_sql-0.1.0/.github/workflows/publish.yml +201 -0
  2. mcp_read_only_sql-0.1.0/.github/workflows/test.yml +174 -0
  3. mcp_read_only_sql-0.1.0/.gitignore +43 -0
  4. mcp_read_only_sql-0.1.0/.mcp.json +9 -0
  5. mcp_read_only_sql-0.1.0/AGENTS.md +25 -0
  6. mcp_read_only_sql-0.1.0/LICENSE +21 -0
  7. mcp_read_only_sql-0.1.0/PKG-INFO +343 -0
  8. mcp_read_only_sql-0.1.0/README.md +310 -0
  9. mcp_read_only_sql-0.1.0/READ_ONLY_ENFORCEMENT_MATRIX.md +135 -0
  10. mcp_read_only_sql-0.1.0/RELEASING.md +94 -0
  11. mcp_read_only_sql-0.1.0/conftest.py +3 -0
  12. mcp_read_only_sql-0.1.0/connections.yaml.sample +256 -0
  13. mcp_read_only_sql-0.1.0/docker/clickhouse/init/01_init.sql +169 -0
  14. mcp_read_only_sql-0.1.0/docker/postgres/init/01_schema.sql +54 -0
  15. mcp_read_only_sql-0.1.0/docker/postgres/init/02_data.sql +104 -0
  16. mcp_read_only_sql-0.1.0/docker/ssh/Dockerfile +41 -0
  17. mcp_read_only_sql-0.1.0/docker-compose.yml +172 -0
  18. mcp_read_only_sql-0.1.0/justfile +70 -0
  19. mcp_read_only_sql-0.1.0/pyproject.toml +52 -0
  20. mcp_read_only_sql-0.1.0/pytest.ini +40 -0
  21. mcp_read_only_sql-0.1.0/run_tests.sh +252 -0
  22. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/__init__.py +9 -0
  23. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/config/__init__.py +8 -0
  24. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/config/connection.py +392 -0
  25. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/config/dbeaver_import.py +767 -0
  26. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/config/loader.py +64 -0
  27. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/config/parser.py +103 -0
  28. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/connections.yaml.sample +256 -0
  29. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/connectors/__init__.py +1 -0
  30. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/connectors/base.py +231 -0
  31. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/connectors/base_cli.py +48 -0
  32. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/connectors/clickhouse/__init__.py +1 -0
  33. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/connectors/clickhouse/cli.py +218 -0
  34. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/connectors/clickhouse/python.py +246 -0
  35. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/connectors/postgresql/__init__.py +1 -0
  36. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/connectors/postgresql/cli.py +197 -0
  37. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/connectors/postgresql/python.py +163 -0
  38. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/runtime_paths.py +74 -0
  39. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/server.py +392 -0
  40. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/tools/__init__.py +1 -0
  41. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/tools/test_connection.py +263 -0
  42. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/tools/test_ssh_tunnel.py +231 -0
  43. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/tools/validate_config.py +374 -0
  44. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/utils/__init__.py +1 -0
  45. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/utils/connection_utils.py +88 -0
  46. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/utils/json_serializer.py +37 -0
  47. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/utils/sql_guard.py +189 -0
  48. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/utils/ssh_tunnel.py +304 -0
  49. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/utils/ssh_tunnel_cli.py +178 -0
  50. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/utils/timeout_wrapper.py +127 -0
  51. mcp_read_only_sql-0.1.0/src/mcp_read_only_sql/utils/tsv_formatter.py +53 -0
  52. mcp_read_only_sql-0.1.0/tests/KNOWN_ISSUES.md +66 -0
  53. mcp_read_only_sql-0.1.0/tests/README.md +73 -0
  54. mcp_read_only_sql-0.1.0/tests/__init__.py +1 -0
  55. mcp_read_only_sql-0.1.0/tests/conftest.py +365 -0
  56. mcp_read_only_sql-0.1.0/tests/conftest_new.py +116 -0
  57. mcp_read_only_sql-0.1.0/tests/connections-test.yaml +27 -0
  58. mcp_read_only_sql-0.1.0/tests/docker_test_config.py +140 -0
  59. mcp_read_only_sql-0.1.0/tests/pytest_plugins.py +28 -0
  60. mcp_read_only_sql-0.1.0/tests/sql_statement_lists.py +375 -0
  61. mcp_read_only_sql-0.1.0/tests/test_cli_ssh_tunnels.py +204 -0
  62. mcp_read_only_sql-0.1.0/tests/test_cli_system_ssh.py +137 -0
  63. mcp_read_only_sql-0.1.0/tests/test_cli_versions.py +31 -0
  64. mcp_read_only_sql-0.1.0/tests/test_clickhouse_cli_fallback.py +75 -0
  65. mcp_read_only_sql-0.1.0/tests/test_config_connection.py +610 -0
  66. mcp_read_only_sql-0.1.0/tests/test_config_parser.py +132 -0
  67. mcp_read_only_sql-0.1.0/tests/test_connection_utils.py +258 -0
  68. mcp_read_only_sql-0.1.0/tests/test_connector_implementations.py +127 -0
  69. mcp_read_only_sql-0.1.0/tests/test_dbeaver_import.py +212 -0
  70. mcp_read_only_sql-0.1.0/tests/test_docker_connectivity.py +145 -0
  71. mcp_read_only_sql-0.1.0/tests/test_docker_test_config.py +101 -0
  72. mcp_read_only_sql-0.1.0/tests/test_error_handling.py +303 -0
  73. mcp_read_only_sql-0.1.0/tests/test_host_mapping_flow.py +70 -0
  74. mcp_read_only_sql-0.1.0/tests/test_limits.py +289 -0
  75. mcp_read_only_sql-0.1.0/tests/test_mcp_protocol.py +61 -0
  76. mcp_read_only_sql-0.1.0/tests/test_mcp_server.py +410 -0
  77. mcp_read_only_sql-0.1.0/tests/test_postgresql_cli_fallback.py +77 -0
  78. mcp_read_only_sql-0.1.0/tests/test_process_cleanup.py +128 -0
  79. mcp_read_only_sql-0.1.0/tests/test_result_serialization.py +519 -0
  80. mcp_read_only_sql-0.1.0/tests/test_run_query_file_output.py +174 -0
  81. mcp_read_only_sql-0.1.0/tests/test_runtime_paths.py +18 -0
  82. mcp_read_only_sql-0.1.0/tests/test_security_layers.py +133 -0
  83. mcp_read_only_sql-0.1.0/tests/test_security_readonly.py +819 -0
  84. mcp_read_only_sql-0.1.0/tests/test_security_readonly_integration.py +148 -0
  85. mcp_read_only_sql-0.1.0/tests/test_serialization_fallback.py +140 -0
  86. mcp_read_only_sql-0.1.0/tests/test_server.py +225 -0
  87. mcp_read_only_sql-0.1.0/tests/test_server_selection.py +286 -0
  88. mcp_read_only_sql-0.1.0/tests/test_ssh_timeout.py +118 -0
  89. mcp_read_only_sql-0.1.0/tests/test_ssh_tunnels.py +415 -0
@@ -0,0 +1,201 @@
1
+ name: Publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
14
+
15
+ steps:
16
+ - name: Checkout code
17
+ uses: actions/checkout@v5
18
+
19
+ - name: Set up Python ${{ matrix.python-version }}
20
+ uses: actions/setup-python@v6
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+
24
+ - name: Install uv
25
+ uses: astral-sh/setup-uv@v7
26
+ with:
27
+ version: "latest"
28
+
29
+ - name: Cache uv environment
30
+ uses: actions/cache@v5
31
+ with:
32
+ path: |
33
+ ~/.cache/uv
34
+ .venv
35
+ key: ${{ runner.os }}-uv-publish-py${{ matrix.python-version }}-${{ hashFiles('uv.lock') }}
36
+ restore-keys: |
37
+ ${{ runner.os }}-uv-publish-py${{ matrix.python-version }}-
38
+
39
+ - name: Install dependencies
40
+ run: |
41
+ uv sync --extra dev
42
+
43
+ - name: Run linter
44
+ run: |
45
+ uv run ruff check src/mcp_read_only_sql/ tests/
46
+
47
+ - name: Install system dependencies for CLI connectors
48
+ run: |
49
+ sudo apt-get update
50
+ sudo apt-get install -y postgresql-client
51
+
52
+ sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
53
+ curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' | sudo gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg
54
+ echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg] https://packages.clickhouse.com/deb stable main" | sudo tee /etc/apt/sources.list.d/clickhouse.list
55
+ sudo apt-get update
56
+ sudo apt-get install -y clickhouse-client
57
+
58
+ sudo apt-get install -y sshpass
59
+
60
+ - name: Run tests
61
+ run: |
62
+ ./run_tests.sh
63
+ env:
64
+ PYTHONUNBUFFERED: 1
65
+
66
+ package-smoke:
67
+ runs-on: ubuntu-latest
68
+ needs: test
69
+
70
+ steps:
71
+ - name: Checkout code
72
+ uses: actions/checkout@v5
73
+
74
+ - name: Set up Python 3.12
75
+ uses: actions/setup-python@v6
76
+ with:
77
+ python-version: "3.12"
78
+
79
+ - name: Install uv
80
+ uses: astral-sh/setup-uv@v7
81
+ with:
82
+ version: "latest"
83
+
84
+ - name: Validate tag matches package version
85
+ run: |
86
+ package_version="$(python -c 'import tomllib; from pathlib import Path; print(tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))["project"]["version"])')"
87
+ tag_version="${GITHUB_REF_NAME#v}"
88
+
89
+ if [ "$package_version" != "$tag_version" ]; then
90
+ echo "Tag version $tag_version does not match pyproject.toml version $package_version" >&2
91
+ exit 1
92
+ fi
93
+
94
+ - name: Build package artifacts
95
+ run: |
96
+ uv build
97
+
98
+ - name: Smoke test wheel
99
+ run: |
100
+ tmp_dir="$(mktemp -d)"
101
+ trap 'rm -rf "$tmp_dir"' EXIT
102
+ uvx --from dist/*.whl mcp-read-only-sql \
103
+ --config-dir "$tmp_dir/config" \
104
+ --state-dir "$tmp_dir/state" \
105
+ --cache-dir "$tmp_dir/cache" \
106
+ --write-sample-config
107
+ test -f "$tmp_dir/config/connections.yaml"
108
+ uvx --from dist/*.whl mcp-read-only-sql \
109
+ --config-dir "$tmp_dir/config" \
110
+ --state-dir "$tmp_dir/state" \
111
+ --cache-dir "$tmp_dir/cache" \
112
+ --print-paths
113
+ uvx --from dist/*.whl mcp-read-only-sql import-dbeaver \
114
+ --config-dir "$tmp_dir/config" \
115
+ --state-dir "$tmp_dir/state" \
116
+ --cache-dir "$tmp_dir/cache" \
117
+ --print-paths
118
+ uvx --from dist/*.whl mcp-read-only-sql validate-config \
119
+ --config-dir "$tmp_dir/config" \
120
+ --state-dir "$tmp_dir/state" \
121
+ --cache-dir "$tmp_dir/cache" \
122
+ --print-paths
123
+ uvx --from dist/*.whl mcp-read-only-sql test-connection \
124
+ --config-dir "$tmp_dir/config" \
125
+ --state-dir "$tmp_dir/state" \
126
+ --cache-dir "$tmp_dir/cache" \
127
+ --print-paths
128
+ uvx --from dist/*.whl mcp-read-only-sql test-ssh-tunnel \
129
+ --config-dir "$tmp_dir/config" \
130
+ --state-dir "$tmp_dir/state" \
131
+ --cache-dir "$tmp_dir/cache" \
132
+ --print-paths
133
+
134
+ - name: Smoke test sdist
135
+ run: |
136
+ tmp_dir="$(mktemp -d)"
137
+ trap 'rm -rf "$tmp_dir"' EXIT
138
+ uvx --from dist/*.tar.gz mcp-read-only-sql \
139
+ --config-dir "$tmp_dir/config" \
140
+ --state-dir "$tmp_dir/state" \
141
+ --cache-dir "$tmp_dir/cache" \
142
+ --write-sample-config
143
+ test -f "$tmp_dir/config/connections.yaml"
144
+ uvx --from dist/*.tar.gz mcp-read-only-sql \
145
+ --config-dir "$tmp_dir/config" \
146
+ --state-dir "$tmp_dir/state" \
147
+ --cache-dir "$tmp_dir/cache" \
148
+ --print-paths
149
+ uvx --from dist/*.tar.gz mcp-read-only-sql import-dbeaver \
150
+ --config-dir "$tmp_dir/config" \
151
+ --state-dir "$tmp_dir/state" \
152
+ --cache-dir "$tmp_dir/cache" \
153
+ --print-paths
154
+ uvx --from dist/*.tar.gz mcp-read-only-sql validate-config \
155
+ --config-dir "$tmp_dir/config" \
156
+ --state-dir "$tmp_dir/state" \
157
+ --cache-dir "$tmp_dir/cache" \
158
+ --print-paths
159
+ uvx --from dist/*.tar.gz mcp-read-only-sql test-connection \
160
+ --config-dir "$tmp_dir/config" \
161
+ --state-dir "$tmp_dir/state" \
162
+ --cache-dir "$tmp_dir/cache" \
163
+ --print-paths
164
+ uvx --from dist/*.tar.gz mcp-read-only-sql test-ssh-tunnel \
165
+ --config-dir "$tmp_dir/config" \
166
+ --state-dir "$tmp_dir/state" \
167
+ --cache-dir "$tmp_dir/cache" \
168
+ --print-paths
169
+
170
+ publish:
171
+ runs-on: ubuntu-latest
172
+ needs:
173
+ - test
174
+ - package-smoke
175
+ permissions:
176
+ contents: read
177
+ id-token: write
178
+ environment:
179
+ name: pypi
180
+ url: https://pypi.org/p/mcp-read-only-sql
181
+
182
+ steps:
183
+ - name: Checkout code
184
+ uses: actions/checkout@v5
185
+
186
+ - name: Set up Python 3.12
187
+ uses: actions/setup-python@v6
188
+ with:
189
+ python-version: "3.12"
190
+
191
+ - name: Install uv
192
+ uses: astral-sh/setup-uv@v7
193
+ with:
194
+ version: "latest"
195
+
196
+ - name: Build package artifacts
197
+ run: |
198
+ uv build
199
+
200
+ - name: Publish to PyPI
201
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,174 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
16
+
17
+ steps:
18
+ - name: Checkout code
19
+ uses: actions/checkout@v5
20
+
21
+ - name: Set up Python ${{ matrix.python-version }}
22
+ uses: actions/setup-python@v6
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+
26
+ - name: Install uv
27
+ uses: astral-sh/setup-uv@v7
28
+ with:
29
+ version: "latest"
30
+
31
+ - name: Cache uv environment
32
+ uses: actions/cache@v5
33
+ with:
34
+ path: |
35
+ ~/.cache/uv
36
+ .venv
37
+ key: ${{ runner.os }}-uv-py${{ matrix.python-version }}-${{ hashFiles('uv.lock') }}
38
+ restore-keys: |
39
+ ${{ runner.os }}-uv-py${{ matrix.python-version }}-
40
+
41
+ - name: Install dependencies
42
+ run: |
43
+ uv sync --extra dev
44
+
45
+ - name: Run linter
46
+ run: |
47
+ uv run ruff check src/mcp_read_only_sql/ tests/
48
+
49
+ - name: Install system dependencies for CLI connectors
50
+ run: |
51
+ sudo apt-get update
52
+ sudo apt-get install -y postgresql-client
53
+
54
+ sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
55
+ curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' | sudo gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg
56
+ echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg] https://packages.clickhouse.com/deb stable main" | sudo tee /etc/apt/sources.list.d/clickhouse.list
57
+ sudo apt-get update
58
+ sudo apt-get install -y clickhouse-client
59
+
60
+ sudo apt-get install -y sshpass
61
+
62
+ - name: Run tests
63
+ run: |
64
+ ./run_tests.sh
65
+ env:
66
+ PYTHONUNBUFFERED: 1
67
+
68
+ - name: Upload test results
69
+ if: always()
70
+ uses: actions/upload-artifact@v7
71
+ with:
72
+ name: test-results-py${{ matrix.python-version }}
73
+ path: |
74
+ test-results/
75
+ if-no-files-found: ignore
76
+
77
+ - name: Clean up
78
+ if: always()
79
+ run: |
80
+ docker compose --profile test down || true
81
+
82
+ package-smoke:
83
+ runs-on: ubuntu-latest
84
+ needs: test
85
+
86
+ steps:
87
+ - name: Checkout code
88
+ uses: actions/checkout@v5
89
+
90
+ - name: Set up Python 3.12
91
+ uses: actions/setup-python@v6
92
+ with:
93
+ python-version: "3.12"
94
+
95
+ - name: Install uv
96
+ uses: astral-sh/setup-uv@v7
97
+ with:
98
+ version: "latest"
99
+
100
+ - name: Build package artifacts
101
+ run: |
102
+ uv build
103
+
104
+ - name: Smoke test wheel
105
+ run: |
106
+ tmp_dir="$(mktemp -d)"
107
+ trap 'rm -rf "$tmp_dir"' EXIT
108
+ uvx --from dist/*.whl mcp-read-only-sql \
109
+ --config-dir "$tmp_dir/config" \
110
+ --state-dir "$tmp_dir/state" \
111
+ --cache-dir "$tmp_dir/cache" \
112
+ --write-sample-config
113
+ test -f "$tmp_dir/config/connections.yaml"
114
+ uvx --from dist/*.whl mcp-read-only-sql \
115
+ --config-dir "$tmp_dir/config" \
116
+ --state-dir "$tmp_dir/state" \
117
+ --cache-dir "$tmp_dir/cache" \
118
+ --print-paths
119
+ uvx --from dist/*.whl mcp-read-only-sql import-dbeaver \
120
+ --config-dir "$tmp_dir/config" \
121
+ --state-dir "$tmp_dir/state" \
122
+ --cache-dir "$tmp_dir/cache" \
123
+ --print-paths
124
+ uvx --from dist/*.whl mcp-read-only-sql validate-config \
125
+ --config-dir "$tmp_dir/config" \
126
+ --state-dir "$tmp_dir/state" \
127
+ --cache-dir "$tmp_dir/cache" \
128
+ --print-paths
129
+ uvx --from dist/*.whl mcp-read-only-sql test-connection \
130
+ --config-dir "$tmp_dir/config" \
131
+ --state-dir "$tmp_dir/state" \
132
+ --cache-dir "$tmp_dir/cache" \
133
+ --print-paths
134
+ uvx --from dist/*.whl mcp-read-only-sql test-ssh-tunnel \
135
+ --config-dir "$tmp_dir/config" \
136
+ --state-dir "$tmp_dir/state" \
137
+ --cache-dir "$tmp_dir/cache" \
138
+ --print-paths
139
+
140
+ - name: Smoke test sdist
141
+ run: |
142
+ tmp_dir="$(mktemp -d)"
143
+ trap 'rm -rf "$tmp_dir"' EXIT
144
+ uvx --from dist/*.tar.gz mcp-read-only-sql \
145
+ --config-dir "$tmp_dir/config" \
146
+ --state-dir "$tmp_dir/state" \
147
+ --cache-dir "$tmp_dir/cache" \
148
+ --write-sample-config
149
+ test -f "$tmp_dir/config/connections.yaml"
150
+ uvx --from dist/*.tar.gz mcp-read-only-sql \
151
+ --config-dir "$tmp_dir/config" \
152
+ --state-dir "$tmp_dir/state" \
153
+ --cache-dir "$tmp_dir/cache" \
154
+ --print-paths
155
+ uvx --from dist/*.tar.gz mcp-read-only-sql import-dbeaver \
156
+ --config-dir "$tmp_dir/config" \
157
+ --state-dir "$tmp_dir/state" \
158
+ --cache-dir "$tmp_dir/cache" \
159
+ --print-paths
160
+ uvx --from dist/*.tar.gz mcp-read-only-sql validate-config \
161
+ --config-dir "$tmp_dir/config" \
162
+ --state-dir "$tmp_dir/state" \
163
+ --cache-dir "$tmp_dir/cache" \
164
+ --print-paths
165
+ uvx --from dist/*.tar.gz mcp-read-only-sql test-connection \
166
+ --config-dir "$tmp_dir/config" \
167
+ --state-dir "$tmp_dir/state" \
168
+ --cache-dir "$tmp_dir/cache" \
169
+ --print-paths
170
+ uvx --from dist/*.tar.gz mcp-read-only-sql test-ssh-tunnel \
171
+ --config-dir "$tmp_dir/config" \
172
+ --state-dir "$tmp_dir/state" \
173
+ --cache-dir "$tmp_dir/cache" \
174
+ --print-paths
@@ -0,0 +1,43 @@
1
+ # Environment variables
2
+ .env
3
+ .env.local
4
+ .env.bak*
5
+
6
+ # Python
7
+ __pycache__/
8
+ *.py[cod]
9
+ *$py.class
10
+ *.so
11
+ .venv/
12
+ .cache/
13
+
14
+ # uv
15
+ uv.lock
16
+ .uv-cache/
17
+
18
+ # IDE
19
+ .vscode/
20
+ .idea/
21
+ *.swp
22
+ *.swo
23
+ *~
24
+
25
+ # Local Claude settings
26
+ .claude/
27
+
28
+ # Testing
29
+ .pytest_cache/
30
+ .coverage
31
+ htmlcov/
32
+ test-results/
33
+
34
+ # Connections
35
+ connections.yaml
36
+ connections.yaml.bak*
37
+ connections.yaml.bak.*
38
+
39
+ # Logs
40
+ *.log
41
+
42
+ # OS
43
+ .DS_Store
@@ -0,0 +1,9 @@
1
+ {
2
+ "mcpServers": {
3
+ "mcp-read-only-sql": {
4
+ "command": "uvx",
5
+ "args": ["--from", ".", "mcp-read-only-sql"],
6
+ "env": {}
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,25 @@
1
+ # Repository Guidelines
2
+
3
+ ## Project Structure & Module Organization
4
+ `src/mcp_read_only_sql/server.py` exposes the MCP entry point, while `src/mcp_read_only_sql/connectors/` hosts the PostgreSQL and ClickHouse adapters. Cross-cutting helpers (`ssh_tunnel.py`, `sql_guard.py`, TSV formatting) live in `src/mcp_read_only_sql/utils/`. Configuration tooling, including DBeaver import and manifest validation, sits in `src/mcp_read_only_sql/config/` and `src/mcp_read_only_sql/tools/`. Tests are grouped in `tests/`, and Docker fixtures for integration runs reside in `docker/`. The package ships a sample `connections.yaml`, and runtime config lives under `~/.config/lukleh/mcp-read-only-sql/`.
5
+
6
+ ## Build, Test, and Development Commands
7
+ - `uv sync --extra dev` — install runtime and development dependencies.
8
+ - `uv run mcp-read-only-sql` or `just run` — start the MCP server with the resolved runtime config directory.
9
+ - `uv run mcp-read-only-sql --write-sample-config` or `just write-sample-config` — bootstrap `connections.yaml` without cloning-path assumptions.
10
+ - `uv run mcp-read-only-sql import-dbeaver ...` or `just import-dbeaver` — convert a DBeaver workspace into `connections.yaml`.
11
+ - `just validate` — lint `connections.yaml` against the schema and safety checks.
12
+ - `just test` — spin up Dockerized fixtures and execute the full pytest suite via `./run_tests.sh`.
13
+ - `uv run python -m pytest tests/test_sql_guard.py` — run an individual module when iterating quickly.
14
+
15
+ ## Coding Style & Naming Conventions
16
+ Target Python 3.11+, four-space indentation, and Unix newlines. Format with `uv run black .` and lint via `uv run ruff check .`; CI mirrors these checks. Modules and callables use snake_case, classes PascalCase (e.g., `TestReadOnlyGuards`), and immutable settings uppercase (`DEFAULT_QUERY_TIMEOUT`). Apply type hints on public surfaces and keep docstrings brief, emphasising read-only guarantees.
17
+
18
+ ## Testing Guidelines
19
+ Pytest discovers `test_*.py` modules, `Test*` classes, and `test_*` functions per `pytest.ini`. Use the built-in markers (`security`, `cli`, `python`, `ssh`, `slow`) to scope runs, e.g. `pytest -m "security and not slow"`. A 30s default timeout applies, so tear down tunnels and subprocesses explicitly. `just test` emits JUnit XML at `test-results/pytest.xml` for CI uploads.
20
+
21
+ ## Commit & Pull Request Guidelines
22
+ Recent commits favour imperative, concise subjects (“Refactor PostgreSQL read-only guard into shared utility”). Keep changes focused and explain security or connector impacts in the body when needed. Pull requests should describe motivation, list affected modules or scripts, link issues, and attach logs or screenshots for operational updates.
23
+
24
+ ## Security & Configuration Tips
25
+ Do not relax safeguards in `src/mcp_read_only_sql/utils/sql_guard.py` or connector factories without matching tests. Treat `connections.yaml` as sensitive; the server stores database and SSH passwords directly in that file, so keep it private and user-readable only. Use the SSH tunnel helpers instead of bespoke subprocesses to preserve timeout and read-only enforcement.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Lukas Lehner
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.