mcp-latchpoint 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 (31) hide show
  1. mcp_latchpoint-0.1.0/.github/workflows/ci.yml +41 -0
  2. mcp_latchpoint-0.1.0/.github/workflows/publish.yml +68 -0
  3. mcp_latchpoint-0.1.0/.gitignore +11 -0
  4. mcp_latchpoint-0.1.0/CHANGELOG.md +8 -0
  5. mcp_latchpoint-0.1.0/CONTRIBUTING.md +15 -0
  6. mcp_latchpoint-0.1.0/LICENSE +21 -0
  7. mcp_latchpoint-0.1.0/PKG-INFO +190 -0
  8. mcp_latchpoint-0.1.0/README.md +140 -0
  9. mcp_latchpoint-0.1.0/SECURITY.md +17 -0
  10. mcp_latchpoint-0.1.0/examples/codex-config.toml +7 -0
  11. mcp_latchpoint-0.1.0/examples/risky.json +18 -0
  12. mcp_latchpoint-0.1.0/examples/safe.json +19 -0
  13. mcp_latchpoint-0.1.0/glama.json +4 -0
  14. mcp_latchpoint-0.1.0/pyproject.toml +64 -0
  15. mcp_latchpoint-0.1.0/src/mcp_latchpoint/__init__.py +6 -0
  16. mcp_latchpoint-0.1.0/src/mcp_latchpoint/cli.py +103 -0
  17. mcp_latchpoint-0.1.0/src/mcp_latchpoint/discovery.py +67 -0
  18. mcp_latchpoint-0.1.0/src/mcp_latchpoint/jsonc.py +73 -0
  19. mcp_latchpoint-0.1.0/src/mcp_latchpoint/mcp_server.py +78 -0
  20. mcp_latchpoint-0.1.0/src/mcp_latchpoint/model.py +147 -0
  21. mcp_latchpoint-0.1.0/src/mcp_latchpoint/output.py +163 -0
  22. mcp_latchpoint-0.1.0/src/mcp_latchpoint/parser.py +289 -0
  23. mcp_latchpoint-0.1.0/src/mcp_latchpoint/py.typed +1 -0
  24. mcp_latchpoint-0.1.0/src/mcp_latchpoint/rules.py +501 -0
  25. mcp_latchpoint-0.1.0/src/mcp_latchpoint/scanner.py +130 -0
  26. mcp_latchpoint-0.1.0/tests/conftest.py +22 -0
  27. mcp_latchpoint-0.1.0/tests/test_mcp_server.py +93 -0
  28. mcp_latchpoint-0.1.0/tests/test_output_cli.py +92 -0
  29. mcp_latchpoint-0.1.0/tests/test_parser.py +140 -0
  30. mcp_latchpoint-0.1.0/tests/test_paths.py +75 -0
  31. mcp_latchpoint-0.1.0/tests/test_rules.py +165 -0
@@ -0,0 +1,41 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ test:
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [ubuntu-latest, windows-latest, macos-latest]
16
+ python-version: ["3.11", "3.13"]
17
+ runs-on: ${{ matrix.os }}
18
+ steps:
19
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
20
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+ cache: pip
24
+ - run: python -m pip install --upgrade pip
25
+ - run: python -m pip install -e ".[dev]"
26
+ - run: pytest --cov=mcp_latchpoint --cov-report=term --cov-fail-under=80
27
+
28
+ quality:
29
+ runs-on: ubuntu-latest
30
+ steps:
31
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
32
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
33
+ with:
34
+ python-version: "3.13"
35
+ cache: pip
36
+ - run: python -m pip install --upgrade pip
37
+ - run: python -m pip install -e ".[dev]"
38
+ - run: ruff check .
39
+ - run: mypy
40
+ - run: python -m pip check
41
+ - run: python -m pip wheel . --no-deps --wheel-dir dist
@@ -0,0 +1,68 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ concurrency:
11
+ group: pypi-${{ github.event.release.tag_name }}
12
+ cancel-in-progress: false
13
+
14
+ jobs:
15
+ build:
16
+ if: ${{ !github.event.release.prerelease }}
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
20
+ with:
21
+ fetch-depth: 0
22
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
23
+ with:
24
+ python-version: "3.13"
25
+ - name: Check release tag and branch
26
+ env:
27
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
28
+ run: |
29
+ python - <<'PY'
30
+ import os
31
+ import tomllib
32
+ from pathlib import Path
33
+
34
+ with Path("pyproject.toml").open("rb") as source:
35
+ version = tomllib.load(source)["project"]["version"]
36
+ expected = f"v{version}"
37
+ if os.environ["RELEASE_TAG"] != expected:
38
+ raise SystemExit(f"Release tag must be {expected}")
39
+ PY
40
+ git fetch --no-tags origin main
41
+ git merge-base --is-ancestor "$GITHUB_SHA" origin/main
42
+ - name: Test and build distributions
43
+ run: |
44
+ python -m pip install -e ".[dev]" build twine
45
+ python -m pytest -q
46
+ python -m build
47
+ python -m twine check dist/*
48
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
49
+ with:
50
+ name: python-distributions
51
+ path: dist/
52
+ if-no-files-found: error
53
+
54
+ publish:
55
+ needs: build
56
+ runs-on: ubuntu-latest
57
+ environment:
58
+ name: pypi
59
+ url: https://pypi.org/project/mcp-latchpoint/
60
+ permissions:
61
+ id-token: write
62
+ steps:
63
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
64
+ with:
65
+ name: python-distributions
66
+ path: dist/
67
+ - name: Publish distributions to PyPI
68
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
@@ -0,0 +1,11 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .coverage
5
+ .mypy_cache/
6
+ .pytest_cache/
7
+ .ruff_cache/
8
+ .venv/
9
+ build/
10
+ dist/
11
+ htmlcov/
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - Add bounded JSON, JSONC, and Codex TOML parsing for documented MCP client layouts.
6
+ - Add seven deterministic configuration rules with redacted evidence.
7
+ - Add text, JSON, and SARIF output with severity-based CI exits.
8
+ - Add a root-confined, read-only MCP stdio server.
@@ -0,0 +1,15 @@
1
+ # Contributing
2
+
3
+ Keep changes small enough to review and add tests for parser, rule, or containment behavior. Rule evidence must be deterministic and must not include credential values.
4
+
5
+ Before opening a pull request, run:
6
+
7
+ ```console
8
+ pytest
9
+ ruff check .
10
+ mypy
11
+ ```
12
+
13
+ New rules need a stable ID, a concrete risk, a remediation, positive and negative fixtures, and a clear statement of uncertainty. Avoid rules that infer server behavior from a package name alone.
14
+
15
+ Use synthetic configurations in tests and examples. Follow `SECURITY.md` for anything that could expose private data.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robert Vind-Gardoș
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.
@@ -0,0 +1,190 @@
1
+ Metadata-Version: 2.5
2
+ Name: mcp-latchpoint
3
+ Version: 0.1.0
4
+ Summary: Offline-first auditor for MCP client configuration files
5
+ Project-URL: Repository, https://github.com/robyroro/mcp-latchpoint
6
+ Project-URL: Issues, https://github.com/robyroro/mcp-latchpoint/issues
7
+ Project-URL: Changelog, https://github.com/robyroro/mcp-latchpoint/blob/main/CHANGELOG.md
8
+ Author: Robert Vind-Gardoș
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 Robert Vind-Gardoș
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: audit,configuration,mcp,security
32
+ Classifier: Development Status :: 3 - Alpha
33
+ Classifier: Environment :: Console
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Programming Language :: Python :: 3.13
39
+ Classifier: Programming Language :: Python :: 3.14
40
+ Classifier: Topic :: Security
41
+ Requires-Python: >=3.11
42
+ Requires-Dist: mcp<3,>=2.3
43
+ Provides-Extra: dev
44
+ Requires-Dist: jsonschema<5,>=4.23; extra == 'dev'
45
+ Requires-Dist: mypy<2,>=1.15; extra == 'dev'
46
+ Requires-Dist: pytest-cov<8,>=6; extra == 'dev'
47
+ Requires-Dist: pytest<10,>=8.3; extra == 'dev'
48
+ Requires-Dist: ruff<1,>=0.11; extra == 'dev'
49
+ Description-Content-Type: text/markdown
50
+
51
+ # mcp-latchpoint
52
+
53
+ `mcp-latchpoint` audits MCP client configuration files without running the configured servers. It works offline, reads only local files you select, and produces text, JSON, or SARIF results.
54
+
55
+ This is an early defensive tool. Review findings in context before changing a working configuration.
56
+
57
+ ## What it checks
58
+
59
+ The v0.1 rules cover:
60
+
61
+ - plain HTTP for non-loopback remote endpoints
62
+ - shell wrappers and inline shell control syntax
63
+ - identifiable `npx` and `uvx` packages without exact versions
64
+ - literal credentials in environment values, headers, arguments, or URLs
65
+ - filesystem roots and home roots passed as recognizable access scopes
66
+ - wildcard hosts and recognizable wildcard scopes
67
+ - conflicting, missing, invalid, or unsupported transport settings
68
+
69
+ Every finding has a stable rule ID, severity, location, remediation, redacted evidence, and a confidence note when interpretation depends on the launched server.
70
+
71
+ ## Install
72
+
73
+ Python 3.11 or newer is required.
74
+
75
+ ```console
76
+ python -m venv .venv
77
+ # Linux or macOS
78
+ . .venv/bin/activate
79
+ # Windows PowerShell
80
+ .venv\Scripts\Activate.ps1
81
+ python -m pip install .
82
+ ```
83
+
84
+ For development:
85
+
86
+ ```console
87
+ python -m pip install -e ".[dev]"
88
+ pytest
89
+ ruff check .
90
+ mypy
91
+ ```
92
+
93
+ The MCP server uses the official Python SDK v2 and the dependency is constrained to `mcp>=2.3,<3`.
94
+
95
+ ## CLI
96
+
97
+ Scan one or more explicit files:
98
+
99
+ ```console
100
+ mcp-latchpoint scan ~/.config/Code/User/mcp.json
101
+ mcp-latchpoint scan examples/risky.json --format json
102
+ mcp-latchpoint scan examples/risky.json --format sarif --fail-on high > results.sarif
103
+ ```
104
+
105
+ Restrict every explicit path to an approved directory:
106
+
107
+ ```console
108
+ mcp-latchpoint scan ./configs --allowed-root ./configs
109
+ ```
110
+
111
+ Directories are searched only for recognized MCP config filenames, up to 256 files. A file is limited to 1 MiB by default. Change these bounds with `--max-files` and `--max-bytes`.
112
+
113
+ Exit codes are `0` for a completed scan below the chosen threshold, `1` when a finding meets `--fail-on`, and `2` for input, containment, or parse errors. The default `--fail-on none` reports findings without failing a build.
114
+
115
+ List and explain rules:
116
+
117
+ ```console
118
+ mcp-latchpoint rules
119
+ mcp-latchpoint explain MCP004
120
+ ```
121
+
122
+ ### Recognized layouts
123
+
124
+ Explicit files may use these structures:
125
+
126
+ | Client layout | Container | Accepted file syntax |
127
+ | --- | --- | --- |
128
+ | Claude Desktop, Cursor, portable `.mcp.json`, generic MCP JSON | top-level `mcpServers` object | JSON |
129
+ | Claude Code user/local settings | top-level `mcpServers`, plus `projects.<path>.mcpServers` in `~/.claude.json` | JSON |
130
+ | VS Code | top-level `servers` object | JSONC for `.vscode/mcp.json` |
131
+ | Codex | `[mcp_servers.<name>]` tables | TOML |
132
+
133
+ Files ending in `.jsonc` are also parsed as JSONC. Other `.json` files remain strict JSON so malformed input is not silently accepted.
134
+
135
+ `--discover` checks only the following paths when they exist. It does not search the rest of the home directory.
136
+
137
+ - All systems: `~/.claude.json`, `~/.cursor/mcp.json`, `~/.codex/config.toml`, `$COPILOT_HOME/mcp-config.json` with `~/.copilot/mcp-config.json` as the fallback
138
+ - Current project: `.mcp.json`, `.codex/config.toml`, `.cursor/mcp.json`, `.vscode/mcp.json`
139
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`, `%APPDATA%\Code\User\mcp.json`
140
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`, `~/Library/Application Support/Code/User/mcp.json`
141
+ - Linux: `$XDG_CONFIG_HOME/Code/User/mcp.json`, falling back to `~/.config/Code/User/mcp.json`
142
+
143
+ ## Read-only MCP server
144
+
145
+ The stdio server exposes two tools: `list_rules` and `scan`. It requires an allowed root at startup. Relative scan paths are resolved below that root; absolute paths, `..` traversal, and symlinks cannot escape it.
146
+
147
+ ```console
148
+ mcp-latchpoint-server --root /absolute/path/to/reviewed-configs
149
+ ```
150
+
151
+ Example client entry:
152
+
153
+ ```json
154
+ {
155
+ "mcpServers": {
156
+ "latchpoint": {
157
+ "command": "/absolute/path/to/mcp-latchpoint-server",
158
+ "args": ["--root", "/absolute/path/to/reviewed-configs"]
159
+ }
160
+ }
161
+ }
162
+ ```
163
+
164
+ The server returns findings and scan metadata, never raw configuration content. Stdio is the only server transport exposed by the entry point, and stdout is reserved for MCP protocol messages.
165
+
166
+ ### Glama build
167
+
168
+ The [Glama listing](https://glama.ai/mcp/servers/robyroro/mcp-latchpoint) builds a container from the repository. In its Dockerfile configuration, use Python 3.13, these build steps and command arguments:
169
+
170
+ ```json
171
+ ["uv sync --no-dev"]
172
+ ```
173
+
174
+ ```json
175
+ ["mcp-proxy", "--", "/app/.venv/bin/mcp-latchpoint-server", "--root", "/app/examples"]
176
+ ```
177
+
178
+ The root is an existing directory with synthetic sample configurations. It lets Glama start and inspect the tools without giving the server access to a user's files. The command uses the executable inside the virtual environment created by `uv sync`. For this demo, the environment-variable schema can be `{"type":"object","properties":{}}` and placeholder parameters can be `{}`.
179
+
180
+ To scan your own configurations, run the server locally with `--root` pointing to a directory you explicitly trust. Glama's demo root is only for the sample files in `examples/`.
181
+
182
+ ## Safety and limitations
183
+
184
+ The scanner never executes commands, installs packages, resolves referenced environment variables, or connects to endpoints. It does not follow configuration includes or inspect an MCP server's code or runtime behavior. Argument-based rules are intentionally limited to recognizable patterns, so custom flags can be missed. A clean report is not proof that a server is safe.
185
+
186
+ Secret detection is designed to emit field names and `<redacted>` markers rather than values. If you find a leak or a path-containment problem, follow [SECURITY.md](SECURITY.md) and do not attach a real configuration to a public issue.
187
+
188
+ ## License
189
+
190
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,140 @@
1
+ # mcp-latchpoint
2
+
3
+ `mcp-latchpoint` audits MCP client configuration files without running the configured servers. It works offline, reads only local files you select, and produces text, JSON, or SARIF results.
4
+
5
+ This is an early defensive tool. Review findings in context before changing a working configuration.
6
+
7
+ ## What it checks
8
+
9
+ The v0.1 rules cover:
10
+
11
+ - plain HTTP for non-loopback remote endpoints
12
+ - shell wrappers and inline shell control syntax
13
+ - identifiable `npx` and `uvx` packages without exact versions
14
+ - literal credentials in environment values, headers, arguments, or URLs
15
+ - filesystem roots and home roots passed as recognizable access scopes
16
+ - wildcard hosts and recognizable wildcard scopes
17
+ - conflicting, missing, invalid, or unsupported transport settings
18
+
19
+ Every finding has a stable rule ID, severity, location, remediation, redacted evidence, and a confidence note when interpretation depends on the launched server.
20
+
21
+ ## Install
22
+
23
+ Python 3.11 or newer is required.
24
+
25
+ ```console
26
+ python -m venv .venv
27
+ # Linux or macOS
28
+ . .venv/bin/activate
29
+ # Windows PowerShell
30
+ .venv\Scripts\Activate.ps1
31
+ python -m pip install .
32
+ ```
33
+
34
+ For development:
35
+
36
+ ```console
37
+ python -m pip install -e ".[dev]"
38
+ pytest
39
+ ruff check .
40
+ mypy
41
+ ```
42
+
43
+ The MCP server uses the official Python SDK v2 and the dependency is constrained to `mcp>=2.3,<3`.
44
+
45
+ ## CLI
46
+
47
+ Scan one or more explicit files:
48
+
49
+ ```console
50
+ mcp-latchpoint scan ~/.config/Code/User/mcp.json
51
+ mcp-latchpoint scan examples/risky.json --format json
52
+ mcp-latchpoint scan examples/risky.json --format sarif --fail-on high > results.sarif
53
+ ```
54
+
55
+ Restrict every explicit path to an approved directory:
56
+
57
+ ```console
58
+ mcp-latchpoint scan ./configs --allowed-root ./configs
59
+ ```
60
+
61
+ Directories are searched only for recognized MCP config filenames, up to 256 files. A file is limited to 1 MiB by default. Change these bounds with `--max-files` and `--max-bytes`.
62
+
63
+ Exit codes are `0` for a completed scan below the chosen threshold, `1` when a finding meets `--fail-on`, and `2` for input, containment, or parse errors. The default `--fail-on none` reports findings without failing a build.
64
+
65
+ List and explain rules:
66
+
67
+ ```console
68
+ mcp-latchpoint rules
69
+ mcp-latchpoint explain MCP004
70
+ ```
71
+
72
+ ### Recognized layouts
73
+
74
+ Explicit files may use these structures:
75
+
76
+ | Client layout | Container | Accepted file syntax |
77
+ | --- | --- | --- |
78
+ | Claude Desktop, Cursor, portable `.mcp.json`, generic MCP JSON | top-level `mcpServers` object | JSON |
79
+ | Claude Code user/local settings | top-level `mcpServers`, plus `projects.<path>.mcpServers` in `~/.claude.json` | JSON |
80
+ | VS Code | top-level `servers` object | JSONC for `.vscode/mcp.json` |
81
+ | Codex | `[mcp_servers.<name>]` tables | TOML |
82
+
83
+ Files ending in `.jsonc` are also parsed as JSONC. Other `.json` files remain strict JSON so malformed input is not silently accepted.
84
+
85
+ `--discover` checks only the following paths when they exist. It does not search the rest of the home directory.
86
+
87
+ - All systems: `~/.claude.json`, `~/.cursor/mcp.json`, `~/.codex/config.toml`, `$COPILOT_HOME/mcp-config.json` with `~/.copilot/mcp-config.json` as the fallback
88
+ - Current project: `.mcp.json`, `.codex/config.toml`, `.cursor/mcp.json`, `.vscode/mcp.json`
89
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`, `%APPDATA%\Code\User\mcp.json`
90
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`, `~/Library/Application Support/Code/User/mcp.json`
91
+ - Linux: `$XDG_CONFIG_HOME/Code/User/mcp.json`, falling back to `~/.config/Code/User/mcp.json`
92
+
93
+ ## Read-only MCP server
94
+
95
+ The stdio server exposes two tools: `list_rules` and `scan`. It requires an allowed root at startup. Relative scan paths are resolved below that root; absolute paths, `..` traversal, and symlinks cannot escape it.
96
+
97
+ ```console
98
+ mcp-latchpoint-server --root /absolute/path/to/reviewed-configs
99
+ ```
100
+
101
+ Example client entry:
102
+
103
+ ```json
104
+ {
105
+ "mcpServers": {
106
+ "latchpoint": {
107
+ "command": "/absolute/path/to/mcp-latchpoint-server",
108
+ "args": ["--root", "/absolute/path/to/reviewed-configs"]
109
+ }
110
+ }
111
+ }
112
+ ```
113
+
114
+ The server returns findings and scan metadata, never raw configuration content. Stdio is the only server transport exposed by the entry point, and stdout is reserved for MCP protocol messages.
115
+
116
+ ### Glama build
117
+
118
+ The [Glama listing](https://glama.ai/mcp/servers/robyroro/mcp-latchpoint) builds a container from the repository. In its Dockerfile configuration, use Python 3.13, these build steps and command arguments:
119
+
120
+ ```json
121
+ ["uv sync --no-dev"]
122
+ ```
123
+
124
+ ```json
125
+ ["mcp-proxy", "--", "/app/.venv/bin/mcp-latchpoint-server", "--root", "/app/examples"]
126
+ ```
127
+
128
+ The root is an existing directory with synthetic sample configurations. It lets Glama start and inspect the tools without giving the server access to a user's files. The command uses the executable inside the virtual environment created by `uv sync`. For this demo, the environment-variable schema can be `{"type":"object","properties":{}}` and placeholder parameters can be `{}`.
129
+
130
+ To scan your own configurations, run the server locally with `--root` pointing to a directory you explicitly trust. Glama's demo root is only for the sample files in `examples/`.
131
+
132
+ ## Safety and limitations
133
+
134
+ The scanner never executes commands, installs packages, resolves referenced environment variables, or connects to endpoints. It does not follow configuration includes or inspect an MCP server's code or runtime behavior. Argument-based rules are intentionally limited to recognizable patterns, so custom flags can be missed. A clean report is not proof that a server is safe.
135
+
136
+ Secret detection is designed to emit field names and `<redacted>` markers rather than values. If you find a leak or a path-containment problem, follow [SECURITY.md](SECURITY.md) and do not attach a real configuration to a public issue.
137
+
138
+ ## License
139
+
140
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,17 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ Until the first stable release, security fixes are made on the latest `0.x` release and the default branch.
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ Do not open a public issue for a vulnerability that could expose configuration data, credentials, or files outside an allowed root. Use GitHub's private vulnerability reporting feature on the eventual public repository. If that feature is not available, contact the repository owner privately before sharing details.
10
+
11
+ Include a minimal reproduction built from synthetic data, the affected version, and the operating system. Do not send real MCP configurations, tokens, home-directory listings, or other private files.
12
+
13
+ Reasonable reports will be acknowledged when the maintainer is available. A public disclosure timeline should be agreed only after the impact and fix have been checked independently.
14
+
15
+ ## Security boundaries
16
+
17
+ `mcp-latchpoint` is a static configuration auditor. It must not execute configured commands, install packages, connect to configured endpoints, or return raw configuration through MCP tools. The stdio server's allowed root is a security boundary, including for traversal and symlink resolution.
@@ -0,0 +1,7 @@
1
+ [mcp_servers.reviewed_local]
2
+ command = "uvx"
3
+ args = ["example-mcp-server==1.4.2", "--workspace", "/srv/mcp/project"]
4
+
5
+ [mcp_servers.reviewed_remote]
6
+ url = "https://mcp.example.com/api"
7
+ bearer_token_env_var = "EXAMPLE_MCP_TOKEN"
@@ -0,0 +1,18 @@
1
+ {
2
+ "mcpServers": {
3
+ "shell-launch": {
4
+ "command": "sh",
5
+ "args": ["-c", "npx @example/mcp-server --root /"],
6
+ "env": {
7
+ "API_TOKEN": "synthetic-example-value"
8
+ }
9
+ },
10
+ "remote": {
11
+ "type": "http",
12
+ "url": "http://mcp.example.com/connect?api_key=synthetic-example-value",
13
+ "headers": {
14
+ "Authorization": "Bearer synthetic-example-value"
15
+ }
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "mcpServers": {
3
+ "reviewed-files": {
4
+ "command": "npx",
5
+ "args": [
6
+ "--yes",
7
+ "@modelcontextprotocol/server-filesystem@1.2.3",
8
+ "/srv/mcp/shared-documents"
9
+ ],
10
+ "env": {
11
+ "SERVICE_TOKEN": "${SERVICE_TOKEN}"
12
+ }
13
+ },
14
+ "internal-api": {
15
+ "type": "http",
16
+ "url": "https://mcp.example.com/api"
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://glama.ai/mcp/schemas/server.json",
3
+ "maintainers": ["robyroro"]
4
+ }
@@ -0,0 +1,64 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "mcp-latchpoint"
7
+ version = "0.1.0"
8
+ description = "Offline-first auditor for MCP client configuration files"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = { file = "LICENSE" }
12
+ authors = [{ name = "Robert Vind-Gardoș" }]
13
+ keywords = ["mcp", "security", "configuration", "audit"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Environment :: Console",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Programming Language :: Python :: 3.14",
23
+ "Topic :: Security",
24
+ ]
25
+ dependencies = [
26
+ "mcp>=2.3,<3",
27
+ ]
28
+
29
+ [project.optional-dependencies]
30
+ dev = [
31
+ "jsonschema>=4.23,<5",
32
+ "mypy>=1.15,<2",
33
+ "pytest>=8.3,<10",
34
+ "pytest-cov>=6,<8",
35
+ "ruff>=0.11,<1",
36
+ ]
37
+
38
+ [project.urls]
39
+ Repository = "https://github.com/robyroro/mcp-latchpoint"
40
+ Issues = "https://github.com/robyroro/mcp-latchpoint/issues"
41
+ Changelog = "https://github.com/robyroro/mcp-latchpoint/blob/main/CHANGELOG.md"
42
+
43
+ [project.scripts]
44
+ mcp-latchpoint = "mcp_latchpoint.cli:main"
45
+ mcp-latchpoint-server = "mcp_latchpoint.mcp_server:main"
46
+
47
+ [tool.hatch.build.targets.wheel]
48
+ packages = ["src/mcp_latchpoint"]
49
+
50
+ [tool.pytest.ini_options]
51
+ addopts = "-ra --strict-markers --strict-config"
52
+ testpaths = ["tests"]
53
+
54
+ [tool.ruff]
55
+ line-length = 100
56
+ target-version = "py311"
57
+
58
+ [tool.ruff.lint]
59
+ select = ["E", "F", "I", "UP", "B", "SIM"]
60
+
61
+ [tool.mypy]
62
+ python_version = "3.11"
63
+ strict = true
64
+ packages = ["mcp_latchpoint"]
@@ -0,0 +1,6 @@
1
+ """Offline-first MCP configuration auditing."""
2
+
3
+ from mcp_latchpoint.scanner import ScanOptions, scan_paths
4
+
5
+ __all__ = ["ScanOptions", "scan_paths"]
6
+ __version__ = "0.1.0"