Skip to content

Releases: sassyconsultingllc/SassyMCP

v1.10.2 — Full-stack cockpit + concurrency fix

Choose a tag to compare

@sassyconsultingllc sassyconsultingllc released this 01 Jul 02:15

Rolls up the two features from this line: the concurrency fix (1.10.1) and the new Control Panel cockpit (1.10.2).

Control Panel cockpit — read-only tool visualizers

Five new tabs turn the operational tools an LLM rarely calls into a live dashboard, all in the server-served panel (works in Claude Desktop and any browser):

  • Server — health, live metrics, tool usage/stats, recent calls (every tier)
  • Network — netstat, listening ports, ARP
  • Processes — system info, process table, autostart entries
  • Security — Defender, firewall, event log
  • Screen — live screen glance (image), windows, OCR

A generic renderer auto-detects each tool's output shape — table, image, key/value card, or text — so new read-only views are a one-line entry. Hard allowlist: the panel can invoke only read-only tools (no shell, no writes, no selfmod). Enable with sassy_panel start.

Concurrency fix (from 1.10.1)

Two chats calling tools at once no longer wedge each other. Blocking tool bodies (SQLite, file I/O, screenshots/OCR) are offloaded to worker threads instead of stalling the single stdio event loop. See CHANGELOG for detail.

Assets

  • sassymcp-v1.10.2.mcpb — Claude Desktop bundle (install this)
  • sassymcp-v1.10.2.dxt — byte-identical, for older clients
  • sassymcp.exe — Windows standalone
  • sassymcp-1.10.2.vsix — VS Code extension

No macOS binary in this release (GitHub Intel runner unavailable); Windows + bundle carry the features.

v1.10.1 — Concurrency fix: multi-client tool calls no longer wedge

Choose a tag to compare

@sassyconsultingllc sassyconsultingllc released this 30 Jun 20:47

Concurrency fix — two chats calling tools at once no longer freeze each other

Claude Desktop multiplexes every chat onto one stdio process / one asyncio event loop. Previously, synchronous blocking tool bodies (SQLite, file I/O, screenshots/OCR) ran inline on that loop, so one chat's in-flight call starved every other client's call until it timed out — the "two chats wedge each other" symptom.

Fix: the audit wrapper now offloads synchronous tools to a worker thread, and is_async is forced so FastMCP awaits the (always-async) wrapper even for def-declared tools. Any blocking tool written as a plain def is now auto-threaded and can never block the loop. Confirmed loop-blockers (state, memory, fileops, vision, crosslink, editor, audit) were converted; SQLite modules use fresh per-call connections.

Verified: 142 pytest + 151 script tests; memory & crosslink smoke-tested under 40–50 concurrent cross-thread calls. Full details in CHANGELOG.md.

Assets

  • sassymcp-v1.10.1.mcpb — Claude Desktop bundle (install this)
  • sassymcp-v1.10.1.dxt — byte-identical to the .mcpb, for older clients that key on the old name
  • sassymcp.exe — Windows standalone binary
  • sassymcp-1.10.1.vsix — VS Code extension

Note: No macOS binary in this release — GitHub's Intel macOS CI runner was unavailable. Windows + the bundle carry the fix; a macOS build can follow when the runner frees up.

v1.9.0 — Permission engine (modes + sandbox jail + rules)

Choose a tag to compare

@sassyconsultingllc sassyconsultingllc released this 23 Jun 10:00

SassyMCP v1.9.0 — Permission engine (modes + sandbox jail + rules)

A new safety/control layer plus a long-standing interceptor bug fix. Existing installs are unchanged until they opt in — with no permission config set, behavior is derived from your current interceptor.destructiveAction.

Added

Permission policy engine (sassymcp.policy). One decision point for "may this operation proceed?", folding the destructive-command classifier, the protected-path guard, and runtime config into four modes:

  • strict — block destructive patterns everywhere (the prior default)
  • confirm — destructive patterns return a confirm token
  • sandbox — relaxed gating inside configured project roots; any path resolving outside the jail is refused (including .. / symlink escapes). The "run an ungated model, but confined to the project folder" mode.
  • bypass — allow everything except protected paths (explicit, audited)

A Claude-style allow / ask / deny rules layer (tool-glob + path-glob + command-regex; first match wins) overrides the mode default. The catastrophic block-list (format/mkfs/…) and the protected-path invariant (the SassyMCP source tree + ~/.sassymcp) hold in every mode, including bypass.

sassy_permission tool — drive it all from chat: status, set_mode, add_root, remove_root, add_rule, clear_rules.

Fixed

The shell interceptor treated piped/compound deletes' command names as files. The delete-target parser ignored pipeline and statement boundaries, so a piped or chained delete (e.g. enumerate-then-delete) scooped up the command name and the | / && operators as "files to move" — and sometimes moved the wrong files. Now only a bare leading delete auto-stages (parsing targets from its own statement); embedded deletes route to the normal block/confirm path.

Build

build-mcpb.ps1 now emits a .dxt copy alongside the .mcpb (identical format) so older Claude Desktop builds — and any client still keyed to the old extension — can install the same bundle.


Tests: 122 pytest + 151 interceptor + 15 policy, all green.

v1.8.1 — Dependency maintenance (Dependabot alerts cleared)

Choose a tag to compare

@sassyconsultingllc sassyconsultingllc released this 18 Jun 17:45

Patch release: all open Dependabot alerts implemented and the binary rebuilt.

Python (uv.lock): cryptography 48.0.0→49.0.0, starlette 1.0.1→1.3.1, python-multipart 0.0.29→0.0.32, pyjwt 2.12.1→2.13.0.
VS Code extension (build deps): @vscode/vsce 2.27→3.9.2, markdown-it 14.2.0, undici→7.28.0, form-data→4.0.6 — 2 high-severity advisories cleared, npm audit clean.

Closes #15 #16 #17 #18 #19 #20 #21. No tool-surface or config changes — drop-in over v1.8.0. Verified: full pytest suite green; frozen-exe supervise + stdio init pass against the upgraded tree.

sassymcp-v1.8.1.mcpb attached.

v1.8.0 — Process supervisor (sassymcp supervise)

Choose a tag to compare

@sassyconsultingllc sassyconsultingllc released this 18 Jun 17:09

v1.8.0 — Process supervisor (sassymcp supervise)

What changed

SassyMCP can now supervise its own runtime. sassymcp supervise start
runs the HTTP bridge (and, optionally, the cloudflared tunnel) as managed
children, keeps them alive with health-checked restart-with-backoff, and
guarantees no orphaned child survives the supervisor's death — even a
hard kill -9 / TerminateProcess. That removes the two long-standing
failure modes: an orphaned bridge holding a wedged SQLite/WAL lock (the
old launcher taskkill /f'd the bridge by PID), and a hung-but-alive
bridge that Windows Task Scheduler can never detect.

The bug / motivation

Nothing in the package owned the runtime tree. The bridge + tunnel were
launched by .bat files; shutdown was a netstat-parsed taskkill /f
(no graceful stop → wedged WAL locks); the only "restart" was Task
Scheduler, which fires on exit but never on a hung process. Terminal
sessions and scrcpy were orphaned on any hard exit. See the lifecycle
audit in the v1.8 design brief.

The fix / approach

  • sassymcp/_jobctl.py — the orphan-proof primitive. Windows: a Job
    Object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE via ctypes/kernel32
    (deliberately not pywin32, which is only transitive and not in the
    PyInstaller spec — so the guarantee holds in the frozen exe). POSIX: a
    new session per child + killpg, plus PR_SET_PDEATHSIG on Linux.
    terminate_tree() does a process-group-aware terminate→grace→kill.
  • sassymcp/supervisor.py — the Supervisor loop: single-instance
    pidfile (O_CREAT|O_EXCL + create_time guard vs PID recycling), on-disk
    child registry, HTTP readiness probe (any response = not hung), and
    exponential backoff (cap 60s, give up after 5 consecutive restarts,
    reset after 30s stable uptime). File command channel for stop/
    restart. CLI main() dispatched from server.py:_dispatch_subcommand.
  • SASSYMCP_SUPERVISED=1 on the bridge child → selfmod._do_restart
    exits and lets the supervisor respawn it instead of racing for the port.
  • tests/conftest.py — autouse reaper of leaked test-child processes
    (scoped to pytest's descendants) so a failed test can't wedge later ones.
  • sassymcp.specsassymcp.supervisor + sassymcp._jobctl added to
    hiddenimports (lazy-imported, so PyInstaller needs them declared).

Test coverage

tests/test_supervisor_lifecycle.py (10 tests): start→running→graceful
stop with no orphan; command-channel stop/restart; crash-loop backoff to
failed; --no-restart; pidfile single-instance + stale reclaim;
shutdown does not kill unmanaged neighbors; orphan-proof on hard parent
kill
(the headline guarantee — Job Object on Windows, PDEATHSIG on
Linux); and Job-Object construction on the host. Validated end-to-end
against a real bridge child (boot → ready → graceful stop → no orphan)
and in the frozen sassymcp.exe.

Verification

python -m pytest tests/test_supervisor_lifecycle.py -q

Frozen-exe / runtime checks (by hand):

  • dist\sassymcp.exe supervise start --tunnel-mode none then, in another
    shell, dist\sassymcp.exe supervise statusrunning:true, bridge
    ready; dist\sassymcp.exe supervise stop → pidfile gone, bridge dead.
  • Hard-kill the supervisor (taskkill /f) → the bridge child also dies
    (Job Object), leaving no wedged lock.

Compatibility

  • Purely additive. Existing launchers (start-tunnel.bat, stdio mode,
    the DXT/.mcpb mcp_config) are unchanged and unsupervised as before.
    start-supervised.bat is the new recommended launcher.
  • stdio mode is intentionally not supervised — the MCP client owns
    that pipe.
  • Not yet wired (fast-follow): server.py:_graceful_shutdown does not yet
    reap in-bridge children (sessions/scrcpy); the personal autostart task
    still launches the bare bridge. Documented in the design brief.

Files touched

  • sassymcp/_jobctl.py, sassymcp/supervisor.py — new (core).
  • sassymcp/_paths.py — supervisor pidfile/registry/cmd constants.
  • sassymcp/server.pysupervise subcommand dispatch.
  • sassymcp/modules/selfmod.py — supervised-restart handoff.
  • sassymcp.spec — hiddenimports for the lazy-imported supervisor modules.
  • tests/conftest.py, tests/test_supervisor_lifecycle.py — new.
  • start-supervised.bat — new recommended launcher.

v1.7.2 — .mcpb bundle + first built release of 1.7.x

Choose a tag to compare

@sassyconsultingllc sassyconsultingllc released this 18 Jun 17:09

v1.7.2 — .mcpb bundle + first built release of the 1.7.x line

What changed

The desktop bundle is now an Anthropic MCP Bundle (.mcpb) instead of
a .dxt. Drag-drop install into Claude Desktop is unchanged for the user;
the difference is the manifest format (manifest_version: "0.2", the
deprecated dxt_version removed) and that the bundle is packed and schema-
validated with the official @anthropic-ai/mcpb CLI. The shipped
sassymcp.exe was rebuilt from current main, so the binary now carries
the v1.7.1 install --client auto/all fix.

The bug / motivation

1.7.1 fixed the install --client auto exit-2 crash but was a source-only
tag — no binary was ever published, so a user installing from the last
distributed artifact still hit the crash. 1.7.2 is the first built
release of the 1.7.x line and closes that gap. The .dxt.mcpb rename
also brings the bundle in line with Anthropic's current MCPB tooling.

The fix / approach

  • mcpb/manifest.json (was dxt/manifest.json): dxt_version: "0.1"
    manifest_version: "0.2"; server.{type,entry_point,mcp_config}
    unchanged and schema-valid.
  • scripts/build-mcpb.ps1 (replaces build-dxt.ps1): stages
    server/sassymcp.exe + manifest.json + icon/README, syncs the
    manifest version to sassymcp/__init__.py, then mcpb validate
    mcpb packmcpb info. Packing via the CLI removes the manual
    forward-slash zip workaround the old .dxt script needed.
  • scripts/gen-icons.py now writes mcpb/icon.png.

Test coverage

  • tests/test_install.py — the auto/all/AUTO → all-clients and
    bogus → exit-2 regression added in 1.7.1, re-run against this build.
  • Full pytest suite re-run for no regressions from the 1.7.0 mesh removal.
  • Frozen-exe smoke checks run against the rebuilt dist/sassymcp.exe
    (not just the source): the install fix in the actual shipped binary.

Verification

The fenced block below is executed by scripts/verify-release.ps1.

# Regression test for the install fix carried into this build
python -m pytest tests/test_install.py -q

Frozen-exe checks (run by hand against dist/sassymcp.exe):

  • dist\sassymcp.exe install --client auto --dry-run → exit 0, lists clients.
  • dist\sassymcp.exe install --client bogus → exit 2 with the valid-name hint.
  • stdio initialize handshake → returns serverInfo.
  • dist\sassymcp.exe --http then scripts/smoke-test.ps1 → local /mcp HTTP 200.
  • mcpb info dist/sassymcp-v1.7.2.mcpb → manifest valid, server/sassymcp.exe present.

Compatibility

  • No breaking changes for users. The .mcpb installs into Claude
    Desktop exactly like the old .dxt; tool surfaces, env, and the
    mcp_config command are identical.
  • The bundle artifact extension changed .dxt.mcpb. Any external
    link to the old sassymcp-v*.dxt asset should point at the new
    sassymcp-v1.7.2.mcpb.

Files touched

  • mcpb/manifest.jsonmanifest_version: "0.2", version 1.7.2 (moved from dxt/).
  • scripts/build-mcpb.ps1 — new CLI-based packer; scripts/build-dxt.ps1 removed.
  • scripts/gen-icons.py — icon output path dxt/mcpb/.
  • sassymcp/__init__.py, README.md, CHANGELOG.md — version bump.

v1.7.1

Choose a tag to compare

@github-actions github-actions released this 15 Jun 11:08

Full Changelog: v1.7.0...v1.7.1

v1.7.0

Choose a tag to compare

@github-actions github-actions released this 15 Jun 08:59

What's Changed

  • build(deps): bump starlette from 0.52.1 to 1.0.1 by @dependabot[bot] in #14
  • build(deps-dev): bump tmp from 0.2.5 to 0.2.7 in /sassymcp-vscode by @dependabot[bot] in #13
  • build(deps-dev): bump qs from 6.15.1 to 6.15.2 in /sassymcp-vscode by @dependabot[bot] in #12

New Contributors

Full Changelog: v1.6.0...v1.7.0

v1.6.0

Choose a tag to compare

@github-actions github-actions released this 15 Jun 08:58

Full Changelog: v1.5.0...v1.6.0

v1.5.0

Choose a tag to compare

@github-actions github-actions released this 20 May 18:12

v1.5.0 — Frozen-exe completeness + Madame memory wiring

What changed

The shipped sassymcp.exe now actually contains the modules the source repo
claims it does. The PyInstaller spec was missing sassymcp.modules.combos
and sassymcp.modules.prompts (added in v1.4.0). Both modules are loaded
dynamically through __import__ at server startup, so PyInstaller's static
analyzer could not see them. The frozen binary booted, logged
Failed to register combos / prompts: No module named ... at WARNING, and
kept running with three combo tools and six slash-menu prompts silently
absent from the registered tool list.

v1.5.0 fixes that. Same source, same start-lan.bat / start-tunnel.bat,
same DXT + VSIX packaging. The exe is just whole again.

The bug

sassymcp/server.py:_load_modules iterates TOOL_GROUPS and calls
_import_module(name) which is a thin wrapper around
__import__(f"sassymcp.modules.{name}", fromlist=[name]). PyInstaller can
only freeze what it sees in the static AST; dynamic imports must be listed
as hiddenimports in the .spec. The combos and prompts groups were
added in v1.4.0 but never added to sassymcp.spec.

Empirical proof against the pre-fix frozen exe:

[INFO] sassymcp: SASSYMCP_LOAD_ALL=1 — loading allowed modules: [..., 'combos', 'prompts']
[WARNING] sassymcp: Failed to register combos: No module named 'sassymcp.modules.combos'
[WARNING] sassymcp: Failed to register prompts: No module named 'sassymcp.modules.prompts'

Tools missing from the registered set in the v1.4.x exes:

  • sassy_combo_pr_review, sassy_combo_phone_observe, sassy_combo_codebase_grep
  • Slash-menu prompts: pr-review, phone-status, resume, codebase-grep, brain-status, setup-sassy

The fix

sassymcp.spec now lists three additional hidden imports:

'sassymcp.modules.combos',
'sassymcp.modules.prompts',
'sassymcp.modules._confirm',

_confirm is reached statically via from sassymcp.modules import _confirm
inside shell.py, so PyInstaller already discovered it — listing it
explicitly is a belt-and-braces guard against future refactors that move
that import behind a lazy lookup.

Packaging surface (unchanged shape, version-stamped)

All five distribution channels SaS uses on a typical install are wired
through the unified release pipeline at .github/workflows/release.yml:

Channel Artifact Pipeline job Source of truth for version
EXE sassymcp.exe build-exe sassymcp/__init__.py:__version__
DXT sassymcp-v1.5.0.dxt build-dxt dxt/manifest.json (auto-synced)
VSIX sassymcp-1.5.0.vsix build-vsix sassymcp-vscode/package.json (auto)
HTTP start-lan.batsassymcp --http (script) EXE
Tunnel start-tunnel.batcloudflared (script) EXE + cloudflared config

build-exe refuses to build if the git tag (vX.Y.Z) does not match
__version__. build-dxt auto-rewrites dxt/manifest.json to match
__version__ before packaging. build-vsix does the same to
sassymcp-vscode/package.json. One source of truth, three artifacts.

The HTTP and Tunnel modes are not separate binaries — they are launch
scripts that invoke the same sassymcp.exe with different transport
flags. start-lan.bat asks the operator whether to bind 127.0.0.1 or
0.0.0.0 (LAN mode prompts for or auto-generates an auth token).
start-tunnel.bat launches the bridge on 127.0.0.1:21001 and runs
cloudflared tunnel run <name> to expose it; the tunnel name is taken
from %1 or %SASSYMCP_TUNNEL_NAME%, no hostname is baked in.

Generalized for distribution (no vendor-specific defaults)

This release strips the production-deployment hostnames out of the
defaults. v1.4.x shipped with the vendor's own canonical hostname as a
default-allowed Host and as a default smoke-test target — fine for the
maintainer, awkward for a paying buyer running the same code under
their own domain.

  • sassymcp/server.py default allowed_hosts is now localhost, 127.0.0.1. Tunnel + LAN operators set
    SASSYMCP_ALLOWED_HOSTS=mcp.<your-domain>.tld,localhost,127.0.0.1 to
    add their hostname. DNS-rebinding protection stays on by default; you
    just have to declare what you're allowing.
  • scripts/smoke-test.ps1 no longer carries a default -RemoteUrl.
    Without one it pings only the local bridge; pass -RemoteUrl https://mcp.<your-domain>.tld/mcp to verify your tunnel.
  • sassymcp-oauth/wrangler.toml was committed with a real hostname,
    KV namespace id, and upstream URL. It is now wrangler.toml.example
    with placeholder values, and the working wrangler.toml is
    .gitignored. Deployers cp the example, edit four fields, run
    wrangler kv:namespace create OAUTH_KV, set the two secrets, and
    wrangler deploy.
  • docs/TUNNEL.md (new) walks a fresh operator through the full
    Cloudflare Tunnel setup: cloudflared install, login, create, route
    dns, ingress config, allowed-hosts env var, and an optional OAuth
    Worker on top for hosted-Claude clients that require DCR/PKCE.

Test coverage

No new tests; the fix is a packaging change that is exercised at exe boot.
Existing test suites still pass. The verification block below re-runs the
high-signal suites and adds a direct boot-time check that the previously
missing modules now register.

Verification

# Existing high-signal suites
python tests/test_intercept.py
python tests/test_shell_auto_promote.py
python tests/test_tool_loader_boost.py
python tests/test_install.py
python tests/test_atomic_write.py
python tests/test_audit_io.py
python tests/test_db_helper.py

Runtime verification against a fresh build (run manually after CI
produces the artifact, or after a local pyinstaller --clean --noconfirm sassymcp.spec):

  1. dist\sassymcp.exe --help → exits 0, header reads SassyMCP Server v1.5.0.
  2. $env:SASSYMCP_LOAD_ALL = "1"; .\dist\sassymcp.exe --stdio (Ctrl-C after a
    second) — scan stderr for Registered module: combos and
    Registered module: prompts. There must be no
    Failed to register combos / Failed to register prompts warnings.
  3. scripts\build-dxt.ps1 produces dist\sassymcp-v1.5.0.dxt and reports
    the manifest version already matches __version__ (no auto-rewrite).
  4. From sassymcp-vscode/: npx vsce package --out ../dist/ produces
    dist\sassymcp-1.5.0.vsix.
  5. Cloudflare Tunnel end-to-end: start-tunnel.bat against the configured
    named tunnel → curl https://<your-hostname>/mcp -H "Authorization: Bearer <token>" returns the MCP capabilities handshake, not a 421 or
    403. Then call sassy_combo_pr_review over the tunnel — it should
    resolve, which it could not in v1.4.x against a frozen exe.

Compatibility

  • Any caller that already used the always-available v1.4.x tool set is
    unaffected.
  • Callers that tried to invoke sassy_combo_* or the slash-menu prompts
    against the v1.4.x frozen exe got a "tool not found" error from the
    server. v1.5.0 simply registers those tools as the source already
    claimed. Source-mode (uv run python -m sassymcp.server) was never
    affected; only the frozen exe needed this fix.
  • DNS-rebinding allowlist behaviour is the same as v1.4.2; the entry was
    promoted from "tunnel-host gotcha" to "default allowlist" already in
    c5efa6f.
  • No schema changes, no config migrations, no breaking changes.

Files touched

  • sassymcp.spec — three hidden imports added.
  • sassymcp/__init__.py__version__ = "1.5.0".
  • dxt/manifest.jsonversion: "1.5.0".
  • sassymcp-vscode/package.jsonversion: "1.5.0".
  • sassymcp-vscode/CHANGELOG.md — 1.5.0 entry.
  • installer.wxsVersion="1.5.0" (UpgradeCode unchanged).
  • build-msi.ps1 — reads __version__ from sassymcp/__init__.py,
    stable UpgradeCode for MajorUpgrade, deterministic per-file Component
    GUIDs, parameterized -SourceDir (defaults to deploy/).
  • sassymcp/server.py — default allowed_hosts reduced to loopback.
  • sassymcp-oauth/wrangler.tomlwrangler.toml.example; working file
    gitignored.
  • sassymcp-oauth/src/index.js — vendor hostname removed from comments.
  • scripts/smoke-test.ps1-RemoteUrl defaults to empty (skip).
  • deploy/start-tunnel.bat — synced with root copy.
  • docs/TUNNEL.md — new operator setup guide.
  • docs/releases/v1.5.0.md — this file.
  • .gitignoresassymcp-oauth/wrangler.toml added.