mcpgawk 0.1.1__tar.gz → 0.1.3__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 (153) hide show
  1. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/.github/workflows/ci.yml +15 -0
  2. mcpgawk-0.1.3/.github/workflows/mcpgawk-gate-selftest.yml +20 -0
  3. mcpgawk-0.1.3/.github/workflows/publish-openvsx.yml +38 -0
  4. mcpgawk-0.1.3/.github/workflows/publish-pypi.yml +51 -0
  5. mcpgawk-0.1.3/.gitignore +39 -0
  6. mcpgawk-0.1.3/CHANGELOG.md +54 -0
  7. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/PKG-INFO +68 -18
  8. mcpgawk-0.1.3/README.md +151 -0
  9. mcpgawk-0.1.3/action.yml +62 -0
  10. mcpgawk-0.1.3/assets/brand/social-preview.png +0 -0
  11. {mcpgawk-0.1.1/docs → mcpgawk-0.1.3}/assets/brand/social-preview.svg +2 -2
  12. mcpgawk-0.1.3/docs/.gitignore +1 -0
  13. mcpgawk-0.1.3/docs/CNAME +1 -0
  14. mcpgawk-0.1.3/docs/api/lead.js +69 -0
  15. mcpgawk-0.1.3/docs/assets/brand/social-preview.png +0 -0
  16. mcpgawk-0.1.3/docs/assets/logos/alibaba.svg +1 -0
  17. mcpgawk-0.1.3/docs/assets/logos/anthropic.svg +1 -0
  18. mcpgawk-0.1.3/docs/assets/logos/baidu.svg +1 -0
  19. mcpgawk-0.1.3/docs/assets/logos/cerebras.svg +4 -0
  20. mcpgawk-0.1.3/docs/assets/logos/cloudflare.svg +1 -0
  21. mcpgawk-0.1.3/docs/assets/logos/cohere.svg +1 -0
  22. mcpgawk-0.1.3/docs/assets/logos/copilot.svg +1 -0
  23. mcpgawk-0.1.3/docs/assets/logos/cursor.svg +12 -0
  24. mcpgawk-0.1.3/docs/assets/logos/deepseek.svg +1 -0
  25. mcpgawk-0.1.3/docs/assets/logos/discord.svg +1 -0
  26. mcpgawk-0.1.3/docs/assets/logos/docker.svg +3 -0
  27. mcpgawk-0.1.3/docs/assets/logos/figma.svg +14 -0
  28. mcpgawk-0.1.3/docs/assets/logos/framer.svg +1 -0
  29. mcpgawk-0.1.3/docs/assets/logos/gemini.svg +1 -0
  30. mcpgawk-0.1.3/docs/assets/logos/github.svg +1 -0
  31. mcpgawk-0.1.3/docs/assets/logos/gitlab.svg +6 -0
  32. mcpgawk-0.1.3/docs/assets/logos/gojek.svg +1 -0
  33. mcpgawk-0.1.3/docs/assets/logos/google.svg +1 -0
  34. mcpgawk-0.1.3/docs/assets/logos/grab.svg +1 -0
  35. mcpgawk-0.1.3/docs/assets/logos/grok.svg +4 -0
  36. mcpgawk-0.1.3/docs/assets/logos/huawei.svg +1 -0
  37. mcpgawk-0.1.3/docs/assets/logos/huggingface.svg +67 -0
  38. mcpgawk-0.1.3/docs/assets/logos/inflection.svg +1 -0
  39. mcpgawk-0.1.3/docs/assets/logos/infosys.svg +1 -0
  40. mcpgawk-0.1.3/docs/assets/logos/kakaotalk.svg +1 -0
  41. mcpgawk-0.1.3/docs/assets/logos/kimi.svg +1 -0
  42. mcpgawk-0.1.3/docs/assets/logos/klarna.svg +1 -0
  43. mcpgawk-0.1.3/docs/assets/logos/langchain.svg +1 -0
  44. mcpgawk-0.1.3/docs/assets/logos/line.svg +1 -0
  45. mcpgawk-0.1.3/docs/assets/logos/linear.svg +1 -0
  46. mcpgawk-0.1.3/docs/assets/logos/mercadolibre.svg +1 -0
  47. mcpgawk-0.1.3/docs/assets/logos/meta.svg +1 -0
  48. mcpgawk-0.1.3/docs/assets/logos/microsoft.svg +1 -0
  49. mcpgawk-0.1.3/docs/assets/logos/midjourney.svg +6 -0
  50. mcpgawk-0.1.3/docs/assets/logos/mistral.svg +1 -0
  51. mcpgawk-0.1.3/docs/assets/logos/naver.svg +1 -0
  52. mcpgawk-0.1.3/docs/assets/logos/netlify.svg +1 -0
  53. mcpgawk-0.1.3/docs/assets/logos/notion.svg +1 -0
  54. mcpgawk-0.1.3/docs/assets/logos/nubank.svg +1 -0
  55. mcpgawk-0.1.3/docs/assets/logos/nvidia.svg +1 -0
  56. mcpgawk-0.1.3/docs/assets/logos/ollama.svg +7 -0
  57. mcpgawk-0.1.3/docs/assets/logos/openai.svg +1 -0
  58. mcpgawk-0.1.3/docs/assets/logos/paytm.svg +1 -0
  59. mcpgawk-0.1.3/docs/assets/logos/perplexity.svg +24 -0
  60. mcpgawk-0.1.3/docs/assets/logos/postgresql.svg +1 -0
  61. mcpgawk-0.1.3/docs/assets/logos/python.svg +1 -0
  62. mcpgawk-0.1.3/docs/assets/logos/qwen.svg +1 -0
  63. mcpgawk-0.1.3/docs/assets/logos/rakuten.svg +1 -0
  64. mcpgawk-0.1.3/docs/assets/logos/replicate.svg +12 -0
  65. mcpgawk-0.1.3/docs/assets/logos/replit.svg +1 -0
  66. mcpgawk-0.1.3/docs/assets/logos/revolut.svg +1 -0
  67. mcpgawk-0.1.3/docs/assets/logos/runway.svg +14 -0
  68. mcpgawk-0.1.3/docs/assets/logos/sap.svg +1 -0
  69. mcpgawk-0.1.3/docs/assets/logos/sentry.svg +1 -0
  70. mcpgawk-0.1.3/docs/assets/logos/shopee.svg +1 -0
  71. mcpgawk-0.1.3/docs/assets/logos/slack.svg +24 -0
  72. mcpgawk-0.1.3/docs/assets/logos/sony.svg +1 -0
  73. mcpgawk-0.1.3/docs/assets/logos/spotify.svg +1 -0
  74. mcpgawk-0.1.3/docs/assets/logos/stability.svg +1 -0
  75. mcpgawk-0.1.3/docs/assets/logos/stripe.svg +1 -0
  76. mcpgawk-0.1.3/docs/assets/logos/suno.svg +1 -0
  77. mcpgawk-0.1.3/docs/assets/logos/supabase.svg +15 -0
  78. mcpgawk-0.1.3/docs/assets/logos/swiggy.svg +1 -0
  79. mcpgawk-0.1.3/docs/assets/logos/tiktok.svg +1 -0
  80. mcpgawk-0.1.3/docs/assets/logos/togetherai.svg +1 -0
  81. mcpgawk-0.1.3/docs/assets/logos/vercel.svg +1 -0
  82. mcpgawk-0.1.3/docs/assets/logos/wechat.svg +1 -0
  83. mcpgawk-0.1.3/docs/assets/logos/weibo.svg +1 -0
  84. mcpgawk-0.1.3/docs/assets/logos/wise.svg +1 -0
  85. mcpgawk-0.1.3/docs/assets/logos/xai.svg +1 -0
  86. mcpgawk-0.1.3/docs/assets/logos/xiaomi.svg +1 -0
  87. mcpgawk-0.1.3/docs/assets/logos/zoho.svg +1 -0
  88. mcpgawk-0.1.3/docs/assets/logos/zomato.svg +1 -0
  89. mcpgawk-0.1.3/docs/index.html +610 -0
  90. mcpgawk-0.1.3/docs/logofield.js +134 -0
  91. mcpgawk-0.1.3/docs/report.html +90 -0
  92. mcpgawk-0.1.3/editors/vscode/.vscodeignore +5 -0
  93. mcpgawk-0.1.3/editors/vscode/CHANGELOG.md +12 -0
  94. mcpgawk-0.1.3/editors/vscode/LICENSE +201 -0
  95. mcpgawk-0.1.3/editors/vscode/README.md +22 -0
  96. mcpgawk-0.1.3/editors/vscode/extension.js +177 -0
  97. mcpgawk-0.1.3/editors/vscode/media/icon.png +0 -0
  98. mcpgawk-0.1.3/editors/vscode/package.json +39 -0
  99. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/pyproject.toml +2 -2
  100. mcpgawk-0.1.3/scripts/ci_gate.py +105 -0
  101. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/src/mcpgawk/cli.py +37 -13
  102. mcpgawk-0.1.3/src/mcpgawk/grade.py +75 -0
  103. mcpgawk-0.1.3/src/mcpgawk/label.py +158 -0
  104. mcpgawk-0.1.3/src/mcpgawk/oauth_scopes.py +45 -0
  105. mcpgawk-0.1.3/src/mcpgawk/supplychain.py +100 -0
  106. mcpgawk-0.1.3/supabase/leads.sql +34 -0
  107. mcpgawk-0.1.3/supabase/lockdown.sql +12 -0
  108. mcpgawk-0.1.3/tests/test_cli_integration.py +66 -0
  109. mcpgawk-0.1.3/tests/test_grade.py +47 -0
  110. mcpgawk-0.1.3/tests/test_label_axes.py +107 -0
  111. mcpgawk-0.1.3/tests/test_oauth_scopes.py +61 -0
  112. mcpgawk-0.1.3/tests/test_supplychain.py +87 -0
  113. mcpgawk-0.1.1/.gitignore +0 -11
  114. mcpgawk-0.1.1/CHANGELOG.md +0 -21
  115. mcpgawk-0.1.1/README.md +0 -101
  116. mcpgawk-0.1.1/assets/brand/social-preview.png +0 -0
  117. mcpgawk-0.1.1/docs/CNAME +0 -1
  118. mcpgawk-0.1.1/docs/assets/brand/social-preview.png +0 -0
  119. mcpgawk-0.1.1/docs/index.html +0 -178
  120. mcpgawk-0.1.1/src/mcpgawk/label.py +0 -89
  121. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/BRAND.md +0 -0
  122. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/CONTRIBUTING.md +0 -0
  123. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/LICENSE +0 -0
  124. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/NOTICE +0 -0
  125. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/SECURITY.md +0 -0
  126. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/THREAT-MODEL.md +0 -0
  127. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/assets/brand/demo.gif +0 -0
  128. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/assets/brand/favicon.svg +0 -0
  129. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/assets/brand/identity-board.html +0 -0
  130. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/assets/brand/nativerse-mark.svg +0 -0
  131. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/assets/brand/wordmark-dark.png +0 -0
  132. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/assets/brand/wordmark-dark.svg +0 -0
  133. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/assets/brand/wordmark-light.png +0 -0
  134. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/assets/brand/wordmark-light.svg +0 -0
  135. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/docs/assets/brand/favicon.svg +0 -0
  136. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/docs/assets/brand/nativerse-mark.svg +0 -0
  137. {mcpgawk-0.1.1 → mcpgawk-0.1.3/docs}/assets/brand/social-preview.svg +0 -0
  138. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/docs/styles.css +0 -0
  139. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/examples/mcp.json +0 -0
  140. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/src/mcpgawk/__init__.py +0 -0
  141. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/src/mcpgawk/__main__.py +0 -0
  142. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/src/mcpgawk/drift.py +0 -0
  143. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/src/mcpgawk/history.py +0 -0
  144. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/src/mcpgawk/measure.py +0 -0
  145. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/src/mcpgawk/probe.py +0 -0
  146. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/src/mcpgawk/servercard.py +0 -0
  147. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/src/mcpgawk/signals.py +0 -0
  148. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/tests/test_drift.py +0 -0
  149. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/tests/test_measure.py +0 -0
  150. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/tests/test_no_egress.py +0 -0
  151. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/tests/test_servercard.py +0 -0
  152. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/tests/test_signals.py +0 -0
  153. {mcpgawk-0.1.1 → mcpgawk-0.1.3}/uv.lock +0 -0
@@ -36,3 +36,18 @@ jobs:
36
36
  python -m venv /tmp/smoke
37
37
  /tmp/smoke/bin/pip install dist/*.whl
38
38
  /tmp/smoke/bin/mcpgawk --help
39
+
40
+ version-consistency:
41
+ runs-on: ubuntu-latest
42
+ steps:
43
+ - uses: actions/checkout@v4
44
+ - name: CLI (pyproject.toml) and VS Code extension (package.json) versions must match
45
+ run: |
46
+ PY_VERSION=$(grep -m1 '^version = ' pyproject.toml | sed -E 's/version = "(.*)"/\1/')
47
+ EXT_VERSION=$(node -p "require('./editors/vscode/package.json').version")
48
+ echo "pyproject.toml: $PY_VERSION"
49
+ echo "editors/vscode/package.json: $EXT_VERSION"
50
+ if [ "$PY_VERSION" != "$EXT_VERSION" ]; then
51
+ echo "::error::Version mismatch — CLI is $PY_VERSION but the VS Code extension is $EXT_VERSION. Bump editors/vscode/package.json (and its CHANGELOG.md) alongside every pyproject.toml release."
52
+ exit 1
53
+ fi
@@ -0,0 +1,20 @@
1
+ name: MCP hygiene gate (self-test)
2
+
3
+ # Dogfoods the mcpgawk Action against a real open server, so the marketplace
4
+ # listing has a live, passing example.
5
+ on:
6
+ push:
7
+ branches: [main]
8
+ pull_request:
9
+
10
+ jobs:
11
+ gate:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - name: MCP hygiene gate
16
+ uses: ./
17
+ with:
18
+ stdio: 'npx -y @modelcontextprotocol/server-filesystem /tmp'
19
+ max-tokens: 5000
20
+ fail-on-flagged: true
@@ -0,0 +1,38 @@
1
+ name: Publish VS Code extension (Open VSX)
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - "editors/vscode/package.json"
8
+ workflow_dispatch: {}
9
+
10
+ jobs:
11
+ publish:
12
+ runs-on: ubuntu-latest
13
+ defaults:
14
+ run:
15
+ working-directory: editors/vscode
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: actions/setup-node@v4
20
+ with:
21
+ node-version: "20"
22
+
23
+ - name: Fail loudly if the Open VSX token isn't configured
24
+ run: |
25
+ if [ -z "${{ secrets.OVSX_PAT }}" ]; then
26
+ echo "::error::OVSX_PAT secret is not set — add it under repo Settings > Secrets before this can publish."
27
+ exit 1
28
+ fi
29
+
30
+ - run: npm install -g @vscode/vsce ovsx
31
+
32
+ - name: Package
33
+ run: vsce package --no-dependencies
34
+
35
+ - name: Publish to Open VSX
36
+ env:
37
+ OVSX_PAT: ${{ secrets.OVSX_PAT }}
38
+ run: ovsx publish *.vsix -p "$OVSX_PAT"
@@ -0,0 +1,51 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - "pyproject.toml"
8
+ workflow_dispatch: {}
9
+
10
+ jobs:
11
+ publish:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.12"
19
+
20
+ - name: Fail loudly if the PyPI token isn't configured
21
+ run: |
22
+ if [ -z "${{ secrets.PYPI_API_TOKEN }}" ]; then
23
+ echo "::error::PYPI_API_TOKEN secret is not set — add it under repo Settings > Secrets before this can publish."
24
+ exit 1
25
+ fi
26
+
27
+ - name: Skip if this version is already published (re-running main shouldn't re-publish)
28
+ run: |
29
+ LOCAL=$(grep -m1 '^version = ' pyproject.toml | sed -E 's/version = "(.*)"/\1/')
30
+ LIVE=$(python -c "import json,urllib.request; print(json.load(urllib.request.urlopen('https://pypi.org/pypi/mcpgawk/json'))['info']['version'])" 2>/dev/null || echo "none")
31
+ echo "local=$LOCAL live=$LIVE"
32
+ echo "LOCAL_VERSION=$LOCAL" >> "$GITHUB_ENV"
33
+ if [ "$LOCAL" = "$LIVE" ]; then
34
+ echo "Already published — skipping."
35
+ echo "SKIP=1" >> "$GITHUB_ENV"
36
+ fi
37
+
38
+ - run: python -m pip install --upgrade pip build
39
+ if: env.SKIP != '1'
40
+
41
+ - run: python -m build
42
+ if: env.SKIP != '1'
43
+
44
+ - name: Publish to PyPI
45
+ if: env.SKIP != '1'
46
+ env:
47
+ TWINE_USERNAME: __token__
48
+ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
49
+ run: |
50
+ python -m pip install twine
51
+ twine upload dist/*
@@ -0,0 +1,39 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ venv/
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ .pytest_cache/
9
+
10
+ # dev-only QA harness
11
+ assets/brand/_qa.html
12
+ editors/vscode/*.vsix
13
+ editors/vscode/node_modules/
14
+ .vercel
15
+
16
+ # ===== NEVER PUBLISH — private strategy, paid product, business/internal =====
17
+ # Belt-and-braces guard: even if one of these is accidentally copied into this
18
+ # public checkout, git will not track it. Primary protection is that these live
19
+ # only in the private repo (~/devtools/mcpgawk, which has NO remote).
20
+ HANDOFF.md
21
+ # private strategy / research / business docs
22
+ docs/spec/
23
+ docs/PLATFORM-AND-FACTORY.md
24
+ docs/foundational-decisions.md
25
+ docs/track-v-verdict-strategy.md
26
+ docs/platform-system-design.md
27
+ docs/architecture-convergence.md
28
+ docs/functional-spec.md
29
+ docs/research-*.md
30
+ docs/strategy-*.md
31
+ docs/*-audit*.md
32
+ docs/adversarial-review-prompt.md
33
+ docs/vendor-outreach-*.md
34
+ # the PAID platform code (verify / monitor / enforce / forge) — never in the free repo
35
+ src/gawk_platform/
36
+ tests/test_platform_smoke.py
37
+ tests/test_forge_smoke.py
38
+ # third-party study clones (Apache-2.0) — never vendored/published
39
+ reference/
@@ -0,0 +1,54 @@
1
+ # Changelog
2
+
3
+ All notable changes to mcpgawk. Format: [Keep a Changelog](https://keepachangelog.com/); versioning: [SemVer](https://semver.org/).
4
+
5
+ ## [0.1.3] — 2026-07-12
6
+
7
+ ### Added
8
+ - Report now covers 5 axes: cost (+ top-3 heaviest tools), trust surface (% write, % exfil-capable,
9
+ destructive-declared count), annotation completeness (score — was computed but never surfaced),
10
+ coverage (prompts/resources, previously `--json`-only), and bounded signals (unchanged).
11
+ - `--verbose` — full per-tool table in CLI text output (previously only the write/exfil-flagged subset
12
+ was shown; the full list existed only via `--json`).
13
+ - `--supply-chain` (opt-in) — checks the launched package against the public npm registry / PyPI JSON
14
+ API for deprecation (npm) / yanked (PyPI, PEP 592) status. Makes a real network call — only the package
15
+ name and version are sent, never the tool inventory. Off by default.
16
+ - `--oauth-scopes` (opt-in) — locally decodes a supplied `Authorization: Bearer <jwt>` header's `scope`/
17
+ `scp` claim. No network call; the signature is not verified (reading a declared claim, not
18
+ authenticating). Opaque (non-JWT) tokens are reported as not locally inspectable, never guessed at.
19
+
20
+ ### Changed
21
+ - `x-mcpgawk` label schema gains `top_heavy_tools`, `trust_surface`, `annotation_completeness`, and
22
+ (only when the corresponding flag is passed) `supply_chain`/`oauth_scopes`. All additive — no existing
23
+ key renamed or removed.
24
+
25
+ ## [0.1.2] — 2026-07-08
26
+
27
+ ### Changed
28
+ - Plain, reader-first README and package description.
29
+ - README images use absolute URLs so they render on PyPI (relative paths only work on GitHub).
30
+
31
+ ## [0.1.1] — 2026-07-08
32
+
33
+ ### Fixed
34
+ - A tool declaring `destructiveHint: true` is now counted as write/mutating even when its name isn't a
35
+ write-verb (e.g. a `pause_job` tool). Previously the verb heuristic could leave a declared-destructive
36
+ tool unflagged.
37
+
38
+ ## [0.1.0] — 2026-07-08
39
+
40
+ Initial release. Local-first MCP measurement.
41
+
42
+ ### Added
43
+ - `mcpgawk scan` over stdio, streamable-HTTP, and SSE via the official `mcp` SDK (protocol-version negotiated).
44
+ - Cost **index** (named tokenizer) + **EXACT** capability facts (write / exfil-capable / annotations) + **integrity pin**.
45
+ - **Bounded** heuristic signals (0-FP on the tested corpus, never verdicts): injection-shaped descriptions
46
+ (tools and prompts), cross-server name shadowing, Server-Card under-declaration.
47
+ - `--track` rug-pull / drift monitor with a local history store.
48
+ - Server Card reader (`/.well-known/mcp/server-card.json`) — reads the card when present, checks
49
+ declared-vs-measured, falls back to live-connect. Fetched with no auth and no redirect-following.
50
+ - Label output as a Server-Card extension (`x-mcpgawk`); `--json` for machine consumption.
51
+
52
+ ### Security
53
+ - Measurement layers import no network library — cannot egress by construction (enforced by test).
54
+ - Per-server timeout so a hung server degrades to one error row.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcpgawk
3
- Version: 0.1.1
4
- Summary: Local-first MCP measurement — gawk at an MCP server before you trust it. No inventory ever leaves your machine.
3
+ Version: 0.1.3
4
+ Summary: A local-first CLI that measures what an MCP server costs and what it can do. Nothing leaves your machine.
5
5
  Project-URL: Homepage, https://mcp.gawk.dev
6
6
  Project-URL: Documentation, https://mcp.gawk.dev
7
7
  Project-URL: Repository, https://github.com/gawk-dev/mcpgawk
@@ -29,11 +29,11 @@ Description-Content-Type: text/markdown
29
29
 
30
30
  <p align="center">
31
31
  <picture>
32
- <source media="(prefers-color-scheme: dark)" srcset="assets/brand/wordmark-dark.png">
33
- <img alt="mcpgawk by nativerse" src="assets/brand/wordmark-light.png" width="320">
32
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/gawk-dev/mcpgawk/main/assets/brand/wordmark-dark.png">
33
+ <img alt="mcpgawk by nativerse" src="https://raw.githubusercontent.com/gawk-dev/mcpgawk/main/assets/brand/wordmark-light.png" width="320">
34
34
  </picture>
35
35
  </p>
36
- <p align="center"><em>gawk at it before you trust it.</em></p>
36
+ <p align="center"><em>Make MCP lean and honest.</em></p>
37
37
 
38
38
  # mcpgawk
39
39
 
@@ -41,22 +41,22 @@ Description-Content-Type: text/markdown
41
41
  [![Python](https://img.shields.io/pypi/pyversions/mcpgawk.svg)](https://pypi.org/project/mcpgawk/)
42
42
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
43
43
  [![CI](https://github.com/gawk-dev/mcpgawk/actions/workflows/ci.yml/badge.svg)](https://github.com/gawk-dev/mcpgawk/actions/workflows/ci.yml)
44
+ [![Open VSX](https://img.shields.io/open-vsx/v/gawk-dev/mcpgawk?label=VS%20Code%20%2F%20Cursor)](https://open-vsx.org/extension/gawk-dev/mcpgawk)
45
+ [![GitHub Marketplace](https://img.shields.io/badge/GitHub%20Marketplace-Action-blue?logo=github)](https://github.com/marketplace/actions/mcpgawk-mcp-hygiene-gate)
44
46
  [![No egress](https://img.shields.io/badge/inventory-never%20uploaded-brightgreen.svg)](#guarantees)
45
47
 
46
- **gawk at an MCP server before you trust it.** A single, local-first command that connects to any
47
- [Model Context Protocol](https://modelcontextprotocol.io) server and measures what it will cost and
48
- expose — **without the server's inventory ever leaving your machine.**
48
+ A local-first command that measures what a [Model Context Protocol](https://modelcontextprotocol.io)
49
+ server costs and what it can do. It runs on your machine and uploads nothing.
49
50
 
50
51
  <p align="center">
51
- <img src="assets/brand/demo.gif" alt="mcpgawk scanning an MCP server — tools, token cost, and capability flags, locally" width="760">
52
+ <img src="https://raw.githubusercontent.com/gawk-dev/mcpgawk/main/assets/brand/demo.gif" alt="mcpgawk scanning an MCP server — tools, token cost, and capability flags, locally" width="760">
52
53
  </p>
53
54
  <p align="center"><sub>Real output. Reproducible on your machine — no account, nothing uploaded.</sub></p>
54
55
 
55
56
  ## Why
56
57
 
57
- Every MCP server you connect dumps *all* its tool definitions into your model's context at connect
58
- time — whether you use one tool or none. That's a hidden **token tax** and an unvetted **trust
59
- surface**. mcpgawk measures both, **locally**, and never phones home about what it saw.
58
+ Connect an MCP server and it loads all its tools into your AI's context. Every request. Used or not.
59
+ You pay for those tokens, and you haven't checked what the tools can do. mcpgawk shows you both, locally.
60
60
 
61
61
  ## How it's different
62
62
 
@@ -68,18 +68,39 @@ surface**. mcpgawk measures both, **locally**, and never phones home about what
68
68
  ## Features
69
69
 
70
70
  - 🔌 **Any transport** — stdio, streamable-HTTP, SSE, and OAuth remotes (via the `mcp-remote` bridge).
71
- - 💸 **Token cost index** — exactly what each tool adds to your context at connect.
72
- - 🧾 **Capability facts** — write / exfil-capable / declared annotations, straight from the schema.
71
+ - 💸 **Token cost index** — exactly what each tool adds to your context at connect, plus the 3 heaviest tools.
72
+ - 🧾 **Capability facts** — write / exfil-capable / declared annotations, straight from the schema, plus a
73
+ trust-surface summary (% write, % exfil-capable, destructive-declared count) and an annotation-completeness
74
+ score.
73
75
  - 📌 **Integrity pin + drift** — catch a server that silently rewrites its tools (`--track`).
74
76
  - 🚩 **Bounded signals** — injection-shaped descriptions, cross-server shadowing, under-declaring Server Cards — pointers for a human, never verdicts.
75
77
  - 🔒 **Zero egress, by construction** — the measurement layers import no network library. Enforced by a test.
78
+ Two checks are opt-in and make an explicit exception (see [Guarantees](#guarantees)): `--supply-chain` and
79
+ `--oauth-scopes`.
76
80
 
77
- ## Install
81
+ ## Get it — three ways
78
82
 
83
+ **CLI** (any terminal):
79
84
  ```bash
80
85
  pip install mcpgawk # or: uv tool install mcpgawk
86
+ mcpgawk scan mcp.json
81
87
  ```
82
88
 
89
+ **Editor** (VS Code / Cursor): install **mcpgawk** from the marketplace ([Open VSX](https://open-vsx.org/extension/gawk-dev/mcpgawk)). It scans your workspace `mcp.json` and shows cost + capability flags inline.
90
+
91
+ **CI** (GitHub Action): gate every PR on token budget / drift ([Marketplace](https://github.com/marketplace/actions/mcpgawk-mcp-hygiene-gate)):
92
+ ```yaml
93
+ - uses: gawk-dev/mcpgawk@v1
94
+ with: { config: mcp.json, max-tokens: 8000, fail-on-flagged: true }
95
+ ```
96
+
97
+ ## When to run it
98
+
99
+ - **Before you add a server** — see what it costs and what it can do, before you trust it.
100
+ - **When your agent feels slow or picks the wrong tool** — it's often MCP bloat (too many / too-heavy tools).
101
+ - **On every PR** — the CI gate catches drift and creeping token cost.
102
+ - **If you *publish* an MCP server** — see what it costs your users and how it reads to a client, and fix it (usually one line per tool). Lean + well-annotated is a differentiator.
103
+
83
104
  ## Use
84
105
 
85
106
  ```bash
@@ -89,28 +110,42 @@ mcpgawk scan --http https://host/mcp --header "Authorization: Bearer $TOKEN"
89
110
  mcpgawk scan --sse https://host/sse
90
111
  mcpgawk scan mcp.json --track # record + detect rug-pulls over time
91
112
  mcpgawk scan mcp.json --json # machine-readable labels
113
+ mcpgawk scan mcp.json --verbose # full per-tool table, not just flagged tools
114
+ mcpgawk scan mcp.json --supply-chain # opt-in: npm/PyPI deprecation check (network)
115
+ mcpgawk scan mcp.json --oauth-scopes # opt-in: decode a supplied Bearer JWT's scope
92
116
  ```
93
117
 
94
118
  ## What it reports
95
119
 
96
120
  - **Cost index** — tokens each tool adds at connect (named tokenizer; a comparable index, not an
97
- absolute Claude count).
98
- - **Capability facts** — write/mutating, exfil-capable, declared annotations.
121
+ absolute Claude count), plus the 3 heaviest tools.
122
+ - **Trust surface** — capability facts (write/mutating, exfil-capable, declared annotations) rolled up
123
+ into % write, % exfil-capable, and a destructive-declared count.
124
+ - **Annotation completeness** — a transparent composite (annotated ÷ total tools declaring read/write
125
+ intent), not a risk score.
126
+ - **Coverage** — tools, prompts, and resources counted (`--verbose` for the full per-tool table).
99
127
  - **Integrity pin** — a hash that changes if the server silently rewrites its tools; `--track`
100
128
  turns it into rug-pull detection over time.
101
129
  - **Bounded signals** — precise, low-false-positive pointers *for a human to review*, never verdicts:
102
130
  injection-shaped descriptions (tools **and** prompts), cross-server name shadowing, and public
103
131
  Server Cards that under-declare what the server actually exposes.
132
+ - **Supply-chain** (opt-in, `--supply-chain`) — checks the launched package against the public npm/PyPI
133
+ registry for deprecation/yank status.
134
+ - **OAuth scopes** (opt-in, `--oauth-scopes`) — locally decodes a supplied Bearer JWT's `scope` claim.
104
135
 
105
136
  ## Guarantees
106
137
 
107
138
  - **No inventory egress.** The only network is the protocol client talking to the server you point
108
139
  it at. The measurement layers import no network library — they *cannot* egress by construction
109
140
  (enforced by a test). Public Server Card discovery is fetched with no auth and no redirect-following.
141
+ Two flags are the explicit, opt-in exception: `--supply-chain` sends the launched package's name
142
+ (and pinned version, if any) — never your tool inventory — to the public npm registry or PyPI JSON
143
+ API. `--oauth-scopes` makes no network call at all; it locally decodes a Bearer JWT you already
144
+ supplied. Neither runs unless you pass the flag.
110
145
  - **Facts ≠ heuristics.** Exact capability facts and the token index never mix with the bounded
111
146
  heuristic signals — separate in code, separate in output.
112
147
  - **Reproducible.** One command, identical numbers.
113
- - **Rides protocol evolution.** Built on the official `mcp` SDK, which negotiates the protocol version.
148
+ - **Tracks the protocol.** Built on the official `mcp` SDK, which negotiates the protocol version.
114
149
 
115
150
  ## Develop
116
151
 
@@ -118,6 +153,21 @@ mcpgawk scan mcp.json --json # machine-read
118
153
  uv run --extra dev --with mcp --with tiktoken --with httpx python -m pytest -q
119
154
  ```
120
155
 
156
+ ## CI gate — GitHub Action
157
+
158
+ Scan your MCP servers on every pull request and fail the build if one gets too heavy or trips a signal.
159
+ It runs entirely in your runner — nothing is uploaded — and posts a per-server cost/flag table to the job summary.
160
+
161
+ ```yaml
162
+ - uses: gawk-dev/mcpgawk@v1
163
+ with:
164
+ config: mcp.json # or: stdio / http / sse — a single server
165
+ max-tokens: 8000 # fail if any server loads more than this at connect
166
+ fail-on-flagged: true # fail if any bounded signal fires
167
+ ```
168
+
169
+ Available on the [GitHub Marketplace](https://github.com/marketplace/actions/mcpgawk-mcp-hygiene-gate).
170
+
121
171
  ## Contributing
122
172
 
123
173
  Issues and PRs welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) first, and see the design
@@ -0,0 +1,151 @@
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/gawk-dev/mcpgawk/main/assets/brand/wordmark-dark.png">
4
+ <img alt="mcpgawk by nativerse" src="https://raw.githubusercontent.com/gawk-dev/mcpgawk/main/assets/brand/wordmark-light.png" width="320">
5
+ </picture>
6
+ </p>
7
+ <p align="center"><em>Make MCP lean and honest.</em></p>
8
+
9
+ # mcpgawk
10
+
11
+ [![PyPI](https://img.shields.io/pypi/v/mcpgawk.svg)](https://pypi.org/project/mcpgawk/)
12
+ [![Python](https://img.shields.io/pypi/pyversions/mcpgawk.svg)](https://pypi.org/project/mcpgawk/)
13
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
14
+ [![CI](https://github.com/gawk-dev/mcpgawk/actions/workflows/ci.yml/badge.svg)](https://github.com/gawk-dev/mcpgawk/actions/workflows/ci.yml)
15
+ [![Open VSX](https://img.shields.io/open-vsx/v/gawk-dev/mcpgawk?label=VS%20Code%20%2F%20Cursor)](https://open-vsx.org/extension/gawk-dev/mcpgawk)
16
+ [![GitHub Marketplace](https://img.shields.io/badge/GitHub%20Marketplace-Action-blue?logo=github)](https://github.com/marketplace/actions/mcpgawk-mcp-hygiene-gate)
17
+ [![No egress](https://img.shields.io/badge/inventory-never%20uploaded-brightgreen.svg)](#guarantees)
18
+
19
+ A local-first command that measures what a [Model Context Protocol](https://modelcontextprotocol.io)
20
+ server costs and what it can do. It runs on your machine and uploads nothing.
21
+
22
+ <p align="center">
23
+ <img src="https://raw.githubusercontent.com/gawk-dev/mcpgawk/main/assets/brand/demo.gif" alt="mcpgawk scanning an MCP server — tools, token cost, and capability flags, locally" width="760">
24
+ </p>
25
+ <p align="center"><sub>Real output. Reproducible on your machine — no account, nothing uploaded.</sub></p>
26
+
27
+ ## Why
28
+
29
+ Connect an MCP server and it loads all its tools into your AI's context. Every request. Used or not.
30
+ You pay for those tokens, and you haven't checked what the tools can do. mcpgawk shows you both, locally.
31
+
32
+ ## How it's different
33
+
34
+ - **vs. cloud scanners** (e.g. Snyk/Invariant `mcp-scan`) — they upload your inventory to a server and
35
+ gate the verdict. mcpgawk runs entirely on your machine; nothing is uploaded, ever.
36
+ - **vs. lazy-load gateways** — they cut tokens but tell you nothing about the *risk* surface.
37
+ - **mcpgawk does both** — cost **and** trust — locally, reproducibly, in one command.
38
+
39
+ ## Features
40
+
41
+ - 🔌 **Any transport** — stdio, streamable-HTTP, SSE, and OAuth remotes (via the `mcp-remote` bridge).
42
+ - 💸 **Token cost index** — exactly what each tool adds to your context at connect, plus the 3 heaviest tools.
43
+ - 🧾 **Capability facts** — write / exfil-capable / declared annotations, straight from the schema, plus a
44
+ trust-surface summary (% write, % exfil-capable, destructive-declared count) and an annotation-completeness
45
+ score.
46
+ - 📌 **Integrity pin + drift** — catch a server that silently rewrites its tools (`--track`).
47
+ - 🚩 **Bounded signals** — injection-shaped descriptions, cross-server shadowing, under-declaring Server Cards — pointers for a human, never verdicts.
48
+ - 🔒 **Zero egress, by construction** — the measurement layers import no network library. Enforced by a test.
49
+ Two checks are opt-in and make an explicit exception (see [Guarantees](#guarantees)): `--supply-chain` and
50
+ `--oauth-scopes`.
51
+
52
+ ## Get it — three ways
53
+
54
+ **CLI** (any terminal):
55
+ ```bash
56
+ pip install mcpgawk # or: uv tool install mcpgawk
57
+ mcpgawk scan mcp.json
58
+ ```
59
+
60
+ **Editor** (VS Code / Cursor): install **mcpgawk** from the marketplace ([Open VSX](https://open-vsx.org/extension/gawk-dev/mcpgawk)). It scans your workspace `mcp.json` and shows cost + capability flags inline.
61
+
62
+ **CI** (GitHub Action): gate every PR on token budget / drift ([Marketplace](https://github.com/marketplace/actions/mcpgawk-mcp-hygiene-gate)):
63
+ ```yaml
64
+ - uses: gawk-dev/mcpgawk@v1
65
+ with: { config: mcp.json, max-tokens: 8000, fail-on-flagged: true }
66
+ ```
67
+
68
+ ## When to run it
69
+
70
+ - **Before you add a server** — see what it costs and what it can do, before you trust it.
71
+ - **When your agent feels slow or picks the wrong tool** — it's often MCP bloat (too many / too-heavy tools).
72
+ - **On every PR** — the CI gate catches drift and creeping token cost.
73
+ - **If you *publish* an MCP server** — see what it costs your users and how it reads to a client, and fix it (usually one line per tool). Lean + well-annotated is a differentiator.
74
+
75
+ ## Use
76
+
77
+ ```bash
78
+ mcpgawk scan mcp.json # a whole config
79
+ mcpgawk scan --stdio "npx -y @modelcontextprotocol/server-filesystem /tmp"
80
+ mcpgawk scan --http https://host/mcp --header "Authorization: Bearer $TOKEN"
81
+ mcpgawk scan --sse https://host/sse
82
+ mcpgawk scan mcp.json --track # record + detect rug-pulls over time
83
+ mcpgawk scan mcp.json --json # machine-readable labels
84
+ mcpgawk scan mcp.json --verbose # full per-tool table, not just flagged tools
85
+ mcpgawk scan mcp.json --supply-chain # opt-in: npm/PyPI deprecation check (network)
86
+ mcpgawk scan mcp.json --oauth-scopes # opt-in: decode a supplied Bearer JWT's scope
87
+ ```
88
+
89
+ ## What it reports
90
+
91
+ - **Cost index** — tokens each tool adds at connect (named tokenizer; a comparable index, not an
92
+ absolute Claude count), plus the 3 heaviest tools.
93
+ - **Trust surface** — capability facts (write/mutating, exfil-capable, declared annotations) rolled up
94
+ into % write, % exfil-capable, and a destructive-declared count.
95
+ - **Annotation completeness** — a transparent composite (annotated ÷ total tools declaring read/write
96
+ intent), not a risk score.
97
+ - **Coverage** — tools, prompts, and resources counted (`--verbose` for the full per-tool table).
98
+ - **Integrity pin** — a hash that changes if the server silently rewrites its tools; `--track`
99
+ turns it into rug-pull detection over time.
100
+ - **Bounded signals** — precise, low-false-positive pointers *for a human to review*, never verdicts:
101
+ injection-shaped descriptions (tools **and** prompts), cross-server name shadowing, and public
102
+ Server Cards that under-declare what the server actually exposes.
103
+ - **Supply-chain** (opt-in, `--supply-chain`) — checks the launched package against the public npm/PyPI
104
+ registry for deprecation/yank status.
105
+ - **OAuth scopes** (opt-in, `--oauth-scopes`) — locally decodes a supplied Bearer JWT's `scope` claim.
106
+
107
+ ## Guarantees
108
+
109
+ - **No inventory egress.** The only network is the protocol client talking to the server you point
110
+ it at. The measurement layers import no network library — they *cannot* egress by construction
111
+ (enforced by a test). Public Server Card discovery is fetched with no auth and no redirect-following.
112
+ Two flags are the explicit, opt-in exception: `--supply-chain` sends the launched package's name
113
+ (and pinned version, if any) — never your tool inventory — to the public npm registry or PyPI JSON
114
+ API. `--oauth-scopes` makes no network call at all; it locally decodes a Bearer JWT you already
115
+ supplied. Neither runs unless you pass the flag.
116
+ - **Facts ≠ heuristics.** Exact capability facts and the token index never mix with the bounded
117
+ heuristic signals — separate in code, separate in output.
118
+ - **Reproducible.** One command, identical numbers.
119
+ - **Tracks the protocol.** Built on the official `mcp` SDK, which negotiates the protocol version.
120
+
121
+ ## Develop
122
+
123
+ ```bash
124
+ uv run --extra dev --with mcp --with tiktoken --with httpx python -m pytest -q
125
+ ```
126
+
127
+ ## CI gate — GitHub Action
128
+
129
+ Scan your MCP servers on every pull request and fail the build if one gets too heavy or trips a signal.
130
+ It runs entirely in your runner — nothing is uploaded — and posts a per-server cost/flag table to the job summary.
131
+
132
+ ```yaml
133
+ - uses: gawk-dev/mcpgawk@v1
134
+ with:
135
+ config: mcp.json # or: stdio / http / sse — a single server
136
+ max-tokens: 8000 # fail if any server loads more than this at connect
137
+ fail-on-flagged: true # fail if any bounded signal fires
138
+ ```
139
+
140
+ Available on the [GitHub Marketplace](https://github.com/marketplace/actions/mcpgawk-mcp-hygiene-gate).
141
+
142
+ ## Contributing
143
+
144
+ Issues and PRs welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) first, and see the design
145
+ boundaries in [THREAT-MODEL.md](THREAT-MODEL.md). Security reports go through [SECURITY.md](SECURITY.md)
146
+ (privately, not a public issue).
147
+
148
+ ## License
149
+
150
+ **Apache-2.0** — see [LICENSE](LICENSE). Part of the **nativerse** · gawk.dev family. The value is in the
151
+ repo, not a cloud.
@@ -0,0 +1,62 @@
1
+ name: 'mcpgawk MCP hygiene gate'
2
+ description: 'Scan your MCP servers in CI and fail the build if one is too heavy or trips a signal. Local, nothing uploaded.'
3
+ author: 'nativerse'
4
+ branding:
5
+ icon: 'shield'
6
+ color: 'blue'
7
+
8
+ inputs:
9
+ config:
10
+ description: 'Path to an mcp.json config to scan.'
11
+ required: false
12
+ default: 'mcp.json'
13
+ stdio:
14
+ description: 'A single stdio server command to scan instead of a config (e.g. "npx -y @modelcontextprotocol/server-filesystem /tmp").'
15
+ required: false
16
+ default: ''
17
+ http:
18
+ description: 'A single streamable-HTTP MCP server URL to scan.'
19
+ required: false
20
+ default: ''
21
+ sse:
22
+ description: 'A single SSE MCP server URL to scan.'
23
+ required: false
24
+ default: ''
25
+ max-tokens:
26
+ description: 'Fail the build if any server loads more than this many tokens at connect. 0 = no budget.'
27
+ required: false
28
+ default: '0'
29
+ fail-on-flagged:
30
+ description: 'Fail the build if any server trips a bounded signal (injection-shaped / shadowing / undeclared).'
31
+ required: false
32
+ default: 'false'
33
+ version:
34
+ description: 'mcpgawk version to install from PyPI ("latest" or e.g. "0.1.2").'
35
+ required: false
36
+ default: 'latest'
37
+
38
+ runs:
39
+ using: 'composite'
40
+ steps:
41
+ - name: Set up Python
42
+ uses: actions/setup-python@v5
43
+ with:
44
+ python-version: '3.12'
45
+ - name: Install mcpgawk
46
+ shell: bash
47
+ run: |
48
+ if [ "${{ inputs.version }}" = "latest" ]; then
49
+ pip install --quiet --disable-pip-version-check mcpgawk
50
+ else
51
+ pip install --quiet --disable-pip-version-check "mcpgawk==${{ inputs.version }}"
52
+ fi
53
+ - name: Scan and gate
54
+ shell: bash
55
+ env:
56
+ MCPGAWK_CONFIG: ${{ inputs.config }}
57
+ MCPGAWK_STDIO: ${{ inputs.stdio }}
58
+ MCPGAWK_HTTP: ${{ inputs.http }}
59
+ MCPGAWK_SSE: ${{ inputs.sse }}
60
+ MCPGAWK_MAX_TOKENS: ${{ inputs.max-tokens }}
61
+ MCPGAWK_FAIL_ON_FLAGGED: ${{ inputs.fail-on-flagged }}
62
+ run: python "${{ github.action_path }}/scripts/ci_gate.py"
@@ -8,8 +8,8 @@
8
8
  <text x="256" y="196" dominant-baseline="central" font-family="Sentient, Georgia, serif" font-weight="500" font-size="104" letter-spacing="-3" fill="#16160F">mcpgawk</text>
9
9
  <text x="258" y="270" font-family="Supreme, -apple-system, sans-serif" font-size="30" letter-spacing="0.5" fill="#6B6B5E">by <tspan fill="#2A33C2" font-weight="500">nativerse</tspan></text>
10
10
  <line x1="96" y1="352" x2="1184" y2="352" stroke="#E7E6E0" stroke-width="1.5"/>
11
- <text x="96" y="438" font-family="Sentient, Georgia, serif" font-size="42" fill="#3A3A30">gawk at it before you trust it.</text>
11
+ <text x="96" y="438" font-family="Sentient, Georgia, serif" font-size="42" fill="#3A3A30">Make it lean. Make it honest.</text>
12
12
  <text x="96" y="524" font-family="Tabular, ui-monospace, Menlo, monospace" font-size="25" fill="#717166"><tspan fill="#2A9d6b">●</tspan> cli-stdio 14 tools 2061 tok@connect 4 flagged</text>
13
13
  <circle cx="102" cy="576" r="6" fill="#2A9d6b"/>
14
- <text x="120" y="576" dominant-baseline="central" font-family="Tabular, ui-monospace, Menlo, monospace" font-size="24" letter-spacing="1" fill="#6B6B5E">local · no inventory ever leaves your machine</text>
14
+ <text x="120" y="576" dominant-baseline="central" font-family="Tabular, ui-monospace, Menlo, monospace" font-size="24" letter-spacing="1" fill="#6B6B5E">local · nothing leaves your machine</text>
15
15
  </svg>
@@ -0,0 +1 @@
1
+ .vercel
@@ -0,0 +1 @@
1
+ mcp.gawk.dev