DEV Community

jackymenCZ (jackymenCZ)
jackymenCZ (jackymenCZ)

Posted on

sentinel-ir 0.5.9 / sentinel-ir-mcp 0.5.9: ordinary-user test, round 3 (macOS)

Machine: macOS 26.6.2 (Darwin 25.6.0), Apple Silicon arm64
Node: 20.20.2 (npm 10.8.2), 22.23.5 (npm 10.9.9), 24.22.3 (npm 11.19.1). The desktop-client runs used Homebrew Node 24.21.0 (npm 10.8.3).

Source (GitLab, Apache-2.0): https://gitlab.com/jakubrojicek11/sentinel-ir
npm: https://www.npmjs.com/package/sentinel-ir
Playground (runs in your browser): https://sentinel-ir-playground-dc30c8.gitlab.io/

Packages: everything came from the npm registry (sentinel-ir@0.5.9, sentinel-ir-mcp@0.5.9, stable-0.5 = latest = 0.5.9). I read the version of the copy that actually ran from its package.json in ~/.npm/_npx/<key>/node_modules/... each time. No repo checkouts, no code changes, no MRs.
MCP client: a real @modelcontextprotocol/sdk Client + StdioClientTransport that starts npx -y sentinel-ir-mcp@... <folder>. I also used VS Code 1.146.0, Cursor 3.30.14 and Claude Desktop 5.11492.5.

Summary

There are no blockers. Every 0.5.9 fix in scope works at runtime on macOS. The remaining problems are in doctor's output, a gap between the library README and its behaviour, and some smaller papercuts.

# Severity Issue
1 bug doctor --client vscode / claude-code prints [ok] Excluded: nothing and [ok] Audit log: off even when the real client entry has --exclude=secrets --audit-log
2 bug doctor's stale-npx-cache check misses a pinned @0.5.8 copy, and it labels every stale copy sentinel-ir-mcp@^0.5.8, whatever the user actually wrote (@0.5, @latest)
3 bug (docs) Library: an explicit unsupported language ("ruby") returns language: "ruby" with the message under facts.error. The README promises language: "unknown" and facts.reason
4 docs Library README "Field reference" shows world.risk / mission.objective, but analyze() returns flat risk / objective, so ir.world.risk throws a TypeError
5 docs Library README "Why send IR" size table and the "about 400 characters" claim are out of date for 0.5.9
6 papercut doctor prints [ok] analyze_directory works ... (0 file(s) checked) when nothing was checked
7 papercut Fix-it hints from doctor and setup leave out --client (and --global), so copying them fails outside a TTY or changes the wrong config
8 papercut MCP analyze_code.language is case-sensitive ("JS" gives a -32602 error); the library accepts "JS"
9 papercut mailto:... / data:... are treated as relative file names (Not found), not refused as URLs
10 papercut URL refusal text is formatted differently from every other refusal
11 papercut The folder summary line in log leaves out the skipped-symlink and incomplete counts
12 papercut Different per-file shapes in analyze_directory (riskSignals without forbidden for parsed files, forbidden with empty riskSignals for broken ones)
13 papercut Rust: idiomatic use std::process; process::exit(0) in a broken file is critical with forbidden: ["child_process"]. A parsed process::exit is low but still has forbidden: ["process.exit"] (a JS-style name)
14 papercut examples/basic.js on a missing file prints a raw Node ENOENT stack trace
15 papercut Cosmetic: ragged line wrap in guide step 2, uneven sub-line indentation in doctor
16 docs MCP README: the audit-log reason list leaves out not-a-folder; "What the server can and cannot do" leaves out the URL / UNC refusals; the minimum sentinel-ir version appears only in the changelog
17 docs MCP README says npx range copies stay stale "incl. npm 11.21.2"; on npm 11.19.1 the @0.5 copy was refreshed
18 docs Library README alias column lists py / rs only; js / ts (and upper case) also work

Results of the 8 regression checks

# Check Result
1 UNC / remote file:// refused before any FS/network access PASS (macOS semantics). //server/share/x.js → Access denied: ... is outside the allowed folders. file://server/share/x.js, file://192.168.1.50/share/x.js and smb://192.168.1.50/s/x.js → path must be a file path, not a URL. file:////192.168.1.50/s/x.js → outside. \\server\share\x.js → Not found, which is correct on POSIX because \ is an ordinary file-name character. tcpdump -i any on ports 445/139/137/53/5353 during the calls: zero SMB packets and no DNS lookup for server or the IP (only unrelated Apple DNS).
2 file:src/x.js, http(s)://, ftp:// refused as URLs; local file:/// works PASS. file:src/x.js, file:src/app.js (the file exists), http://, https://, HTTP:// and ftp:// all give path must be a file path, not a URL. file:///<root>/src/app.js (raw and percent-encoded, with spaces and ž) and file://localhost/... analyse fine. On another volume the local file:// URL also works. Side note: mailto: / data: are not covered (#9).
3 Broken Python/Rust is critical only when forbidden names the capability PASS. Broken files with subprocess, os.system, runpy, spec_from_file_location(...).loader.exec_module, from ctypes import * and std::process::Command (short and full path) → critical, with the capability in forbidden. Harmless ones (importlib.reload, from ctypes import c_int, std::process::exit, std::process::id, std::io::stdin, plain code) → low, forbidden: []. Same results on Node 20/22/24 and through MCP. Bare import pickle / import ctypes / use std::process → critical as documented (see #13).
4 analyze_directory summaries list forbidden for dangerous broken files PASS. In a folder of 11 dangerous and 7 harmless broken files, the 11 are critical with forbidden and the 7 are low without forbidden.
5 analyze_code.language accepts js, ts, py, rs PASS. All four work, and the enum is in the tool schema. Upper-case "JS" is rejected (#8).
6 log wording PASS. x.rb → "incomplete: unsupported language". Remote URL → "not a local file path". Outside → "outside the allowed folders". Hard link → "file has several hard links". In a folder, "3 not read (several hard links)" and "1 not read (too large or unreadable)" are separate. "not a folder" / "not a file" are correct. Symlink and incomplete counts are missing from the folder line (#11).
7 doctor: unmatched exclusion warning; stale-cache wording for range vs tag PARTIAL. The unmatched-exclusion warning works ([warn] ... matches nothing). The stale-cache warning appears, but it always names the npx-internal range ^0.5.8 instead of the user's spec (@0.5, @latest) and misses a pinned @0.5.8 copy (#2).
8 README documents language + aliases, every refusal reason, minimum sentinel-ir PARTIAL. The MCP README Tools table documents language and its aliases. The refusal reasons are spread across the changelog and the security section, and not-a-folder is missing from the audit-log list. "Needs sentinel-ir 0.5.9" appears only in the changelog (#16).

0.5.8 fixes rechecked, all still OK: the same Access denied for existing and missing outside paths (including .., src/../.. and a dangling symlink); .rb / .go → incomplete / unknown; doctor --client works for each of cursor, windsurf, claude-desktop, vscode and claude-code; log | head -1 exits cleanly with no EPIPE; strict TypeScript declarations; Rust/TSX parse positions; .jsx accepted.

Issues

1. bug: doctor --client vscode reports exclusions and audit log that contradict the real config

  • OS / Node: macOS 26.6.2 arm64, Node 24.21.0 (Homebrew). The same code path runs on 20/22/24.
  • Repro:
    1. cd "/Users/devin/Projekty/Můj projekt ž"
    2. npx -y sentinel-ir-mcp@stable-0.5 setup --client vscode --exclude secrets --audit-log, then run the printed code --add-mcp '{...}' command. VS Code writes ~/Library/Application Support/Code/User/mcp.json containing "--exclude=secrets", "--audit-log".
    3. npx -y sentinel-ir-mcp@stable-0.5 doctor --client vscode
  • Expected: Because doctor cannot read VS Code's list, it should not say anything about exclusions or the audit log, or it should say "unknown, check the VS Code entry". It should not report [ok] Excluded: nothing.
  • Actual: It says, as [ok], that nothing is excluded and the audit log is off, which is the opposite of the real setup. A user who checked can come away thinking their secrets exclusion is gone, or that it is not needed.
  • Full output:
[ok]   Node.js v24.21.0
[ok]   sentinel-ir-mcp 0.5.9, sentinel-ir 0.5.9
[ok]   sentinel-ir-mcp 0.5.9 is the newest stable-0.5 on npm
[ok]   npx cache (/Users/devin/.npm/_npx): no copy with sentinel-ir older than 0.5.9
[skip] VS Code keeps its own server list; check it there (VS Code: "MCP: List Servers", Claude Code: "claude mcp list").
[ok]   Excluded: nothing (the agent may analyze every source file in the folder)
[ok]   Audit log: off (turn it on: npx -y sentinel-ir-mcp@stable-0.5 setup --audit-log)
[ok]   MCP handshake with sentinel-ir-mcp 0.5.9
[ok]   Tools: analyze_code, analyze_directory, analyze_file
[ok]   analyze_directory works on /Users/devin/Projekty/Můj projekt ž (1 file(s) checked)

All checks passed.
Enter fullscreen mode Exit fullscreen mode

The actual mcp.json:

{ "servers": { "sentinel-ir": { "type": "stdio", "command": "npx",
  "args": ["-y","sentinel-ir-mcp@stable-0.5","--exclude=secrets","--audit-log","/Users/devin/Projekty/Můj projekt ž"] } }, "inputs": [] }
Enter fullscreen mode Exit fullscreen mode

The audit-log hint has the same problem: setup --audit-log without --client vscode would not change this entry (see #7). I did not run claude-code separately; the [skip] line shows it takes the same branch.

2. bug: the stale-npx-cache warning misses a pinned copy and names a range the user never wrote

  • OS / Node: macOS 26.6.2 arm64, Node 20.20.2 / npm 10.8.2. Isolated HOME=/Users/devin/r3/hup20.
  • Repro (pinned copy missed):
    1. npx -y sentinel-ir-mcp@0.5.8 --version → 0.5.8. The cache key e90bfea4b29781f8 = sha512("sentinel-ir-mcp@0.5.8"), and its package.json has 0.5.8 / sentinel-ir 0.5.8.
    2. npx --before=2026-11-15T16:00:00Z -y sentinel-ir-mcp@latest --version → 0.5.8 (key 44517f9a0f1686df = @latest).
    3. npx -y sentinel-ir-mcp@stable-0.5 doctor --client cursor
  • Actual: Doctor reports only the @latest copy:
[warn] The npx cache still holds sentinel-ir-mcp@^0.5.8 (sentinel-ir-mcp 0.5.8, sentinel-ir 0.5.8) in /Users/devin/r3/hup20/.npm/_npx/44517f9a0f1686df; a client entry with that version or range keeps starting it, and sentinel-ir older than 0.5.9 misses security fixes
       -> Close the client, delete that folder (npm 11: npm cache npx rm 44517f9a0f1686df), then run: npx -y sentinel-ir-mcp@stable-0.5 setup
...
All checks passed, 1 warning above.
Enter fullscreen mode Exit fullscreen mode

Then move 44517f9a0f1686df away and run doctor again. It prints All checks passed. with no warning, even though e90bfea4b29781f8 (a pinned @0.5.8, the one copy that really does keep starting 0.5.8 forever) is still in the cache with sentinel-ir 0.5.8.
The @latest copy that was flagged gets refreshed by npm 10 itself: npx -y sentinel-ir-mcp@latest --version → 0.5.9, and its package.json → 0.5.9.

  • Repro (wording): seed @0.5 the same way (npx --before=... -y sentinel-ir-mcp@0.5 --version), then run doctor. The warning names sentinel-ir-mcp@^0.5.8 for key 46f9bf218df4163a (= sentinel-ir-mcp@0.5). That is the range npx writes into its private package.json; the user's config says sentinel-ir-mcp@0.5. For the @latest key it also says ^0.5.8, so the message reads the same for a range and a tag.
  • Expected: Every cached copy with sentinel-ir < 0.5.9 is listed, labelled with the spec a client entry would contain (sentinel-ir-mcp@0.5, @latest, @0.5.8). The text says which of them npx refreshes by itself (tags) and which stay stale (pinned versions; ranges on npm 10).
  • Note: the hint shows npm 11: npm cache npx rm ... on npm 10, which is labelled and fine.

3. bug (docs vs behaviour): an explicit unsupported language is not reported as unknown

  • OS / Node: macOS 26.6.2 arm64, Node 20/22/24 (same result).
  • Repro: npm install sentinel-ir, then
const { analyze, compress } = require("sentinel-ir");
const ir = analyze("x = 1", { language: "ruby" });
console.log(ir.language, ir.analysisStatus, ir.facts, compress(ir).facts);
Enter fullscreen mode Exit fullscreen mode
  • Expected (README §Languages): "An explicit unsupported language (e.g. "ruby") ... is reported as analysisStatus: "incomplete" with language: "unknown" and facts.reason: "unsupported file type: .rb (…)"".
  • Actual:
ruby incomplete { error: 'unsupported language: ruby (supported: javascript, typescript, tsx, python, rust)' } { ast: false, reason: 'unsupported language: ruby (supported: javascript, typescript, tsx, python, rust)' }
Enter fullscreen mode Exit fullscreen mode

language is "ruby", not "unknown". The raw IR puts the message in facts.error, not facts.reason (only compress() uses reason). A target with an unknown extension (x.rb) does give unknown + facts.reason, so the two paths are inconsistent. Code that checks ir.language === "unknown" misses this case. Also, analyze("eval(1)", {language:"ruby"}) comes back incomplete + critical from the text heuristics. That is fine, but the README does not say it.

4. docs: the library README field reference does not match the shape analyze() returns

  • OS / Node: macOS, Node 20/22/24.
  • Repro: following the README, const ir = analyze(src, { target: "app.js" }); console.log(ir.world.risk);
  • Expected: prints the risk, since the README "Field reference" documents world.risk, mission.objective and so on.
  • Actual:
TypeError: Cannot read properties of undefined (reading 'risk')
Enter fullscreen mode Exit fullscreen mode

The raw IR is flat (ir.risk, ir.target, ir.objective, ir.forbidden, ir.analysisStatus, ir.facts). Only compress(ir) has world / mission. The shipped .d.ts is correct, so TypeScript users find out at compile time and JS users at runtime. The README should say which shape each section describes.

5. docs: the library "Why send IR" table and the "about 400 characters" claim are out of date

  • OS / Node: macOS, Node 22. node node_modules/sentinel-ir/examples/basic.js <file> on the package's own files.
  • README: ast-facts.js 21,823 → 449; sentinel-ir.js 9,123 → 515; tree-parser.js 4,393 → 465; basic.js 600 → 461; "about 400 characters plus the facts".
  • Actual 0.5.9: ast-facts.js 96,821 → 511; sentinel-ir.js 20,413 → 621; tree-parser.js 13,175 → 803; basic.js 600 → 510/532. The ratio claim still holds, but the numbers no longer match.

6. papercut: doctor says [ok] analyze_directory works after checking 0 files

  • OS / Node: macOS, Node 22.23.5.
  • Repro: mkdir "p q" && cd "p q" && echo 'eval(1)' > a.js && ln -f a.js ../a_link.js (so the only file has 2 links), then npx -y sentinel-ir-mcp@stable-0.5 setup --client cursor --no-exclude --no-audit-log --yes and npx -y sentinel-ir-mcp@stable-0.5 doctor --client cursor.
  • Expected: [warn] "no file could be analysed (1 skipped: several hard links)", or at least no "works" claim.
  • Actual:
[ok]   analyze_directory works on /Users/devin/r3/hl/p q (0 file(s) checked)

All checks passed.
Enter fullscreen mode Exit fullscreen mode

I saw the same on the second volume when the first candidate file was a hard link.

7. papercut: copy-paste hints leave out --client / --global

  • OS / Node: macOS, Node 20/22/24.
  • Repro A: the stale-cache hint in #2 ends with then run: npx -y sentinel-ir-mcp@stable-0.5 setup. Run from a script, CI or a non-TTY terminal:
sentinel-ir-mcp setup: Choose a client with --client (cursor, windsurf, claude-desktop, vscode, claude-code).
Enter fullscreen mode Exit fullscreen mode
  • Repro B: npx -y sentinel-ir-mcp@stable-0.5 setup --client cursor --global --dry-run prints Audit log: off (turn it on with: npx -y sentinel-ir-mcp@stable-0.5 setup --audit-log). The hint drops --client cursor --global, so in a TTY it asks again, and it may target the project config instead of the global one. Doctor for vscode prints the same hint (#1).
  • Expected: the hints repeat the --client (and --global) that was used. Related: the README says "without --client it asks", but it only asks on a TTY. With stdin piped it exits with the message above. That is reasonable behaviour, but the README should mention it.

8. papercut: MCP analyze_code.language is case-sensitive while the library is not

  • OS / Node: macOS, Node 20/22/24, via the MCP SDK client.
  • Repro: callTool("analyze_code", { code: "eval(1)", target: "a.js", language: "JS" })
  • Actual:
MCP error -32602: Input validation error: Invalid arguments for tool analyze_code: Invalid option: expected one of "javascript"|"typescript"|"tsx"|"python"|"rust"|"js"|"ts"|"py"|"rs" at language
Enter fullscreen mode Exit fullscreen mode

The library analyze("eval(1)", { language: "JS" }) → language: "javascript", complete, critical. The error message itself is clear; this is a consistency issue only.

9. papercut: mailto: / data: paths are treated as relative file names

  • Repro (MCP, Node 24): analyze_file { path: "mailto:a@b.js" } and analyze_file { path: "data:text/javascript,eval(1)" }.
  • Actual: Not found: mailto:a@b.js, Not found: data:text/javascript,eval(1).
  • Expected: the same path must be a file path, not a URL as file:src/x.js / http://, which the 0.5.9 changelog describes as covering "other URLs". There is no security impact (they resolve inside the root and do not exist), but the wording is inconsistent.

10. papercut: the URL refusal is formatted differently from the other refusals

Other errors start with a capitalised label and name the path: Access denied: X is outside the allowed folders, Not found: X, File too large: big.js is 1800000 bytes, limit is 1048576, Unsupported file type: ..., Not a file: .... The URL refusal is a lowercase sentence that does not name the path: path must be a file path, not a URL. Suggested wording: Not a file path: <value> is a URL.

11. papercut: the folder summary in log leaves out the symlink and incomplete counts

  • Repro: analyze_directory on a folder with 3 symlinks, 3 hard links, 1 oversized file and broken files, then npx -y sentinel-ir-mcp@stable-0.5 log.
  • Actual: the folder line lists the analysed files, "3 not read (several hard links)" and "1 not read (too large or unreadable)". The 3 skipped symlinks and the number of incomplete files, both in the tool result, do not appear in the log.
  • Expected: the same counts the agent saw, since the log is the user's record of what the agent got.

12. papercut: inconsistent per-file entries in analyze_directory

Parsed files have riskSignals (e.g. ["dynamic_code:eval@4"]) and no forbidden key. Broken files have forbidden and riskSignals: [], even when they are critical. A consumer has to read both fields to find out why a file is risky. The guide tells agents to look at riskSignals, so for a broken critical file they see an empty list.

13. papercut: Rust process::exit naming in broken and parsed files

  • Repro (library, Node 22):
    • A broken file containing use std::process; … process::exit(0) (Rust Book ch. 12 style) plus a syntax error → critical, forbidden: ["child_process"]. The same file without the syntax error → low.
    • A parsed file with std::process::exit(1) → risk: "low" but forbidden: ["process.exit"].
  • The bare use std::process rule is documented, but a "child_process" label on Rust code that only exits looks wrong to a newcomer. A non-empty forbidden with a JS name at low risk is confusing.

14. papercut: examples/basic.js prints a stack trace for a missing file

  • Repro (Node 22): node node_modules/sentinel-ir/examples/basic.js nope.js
  • Actual:
node:fs:440
    return binding.readFileUtf8(path, stringToFlags(options.flag));
                   ^

Error: ENOENT: no such file or directory, open 'nope.js'
    at Object.readFileSync (node:fs:440:20)
    at Object.<anonymous> (/Users/devin/r3/lib22/node_modules/sentinel-ir/examples/basic.js:7:17)
    at Module._compile (node:internal/modules/cjs/loader:1781:14)
    ...
Enter fullscreen mode Exit fullscreen mode
  • Expected: a one-line basic.js: cannot read nope.js plus usage. Also, npx sentinel-ir file.js gives npm error could not determine executable to run. The README does not promise a CLI, but a newcomer will try it.

15. papercut (cosmetic): text layout

  • guide step 2 has a ragged wrap:
2. Look at "incomplete", "skipped.unreadable" and "skipped.hardlinks" before
   anything else. Those
   files were not fully analyzed: ...
Enter fullscreen mode Exit fullscreen mode
  • In doctor, the sub-lines under [ok] and [warn] items are indented differently ([ok] in ... vs [warn] matches nothing).

16. docs: gaps in the MCP README

  • The audit-log section lists why a request was refused (excluded, outside, ...) but leaves out not-a-folder, which log does print.
  • "What the server can and cannot do" (the section a cautious user reads) does not mention that URLs, file: without //, remote file://host/ and UNC paths are refused. That is only in the 0.5.9 changelog.
  • The minimum sentinel-ir version (0.5.9) is stated only in the changelog, not in "Dependencies" or "Setup".

17. docs: npx range refresh depends on the npm version

  • Repro: seed npx --before=2026-11-15T16:00:00Z -y sentinel-ir-mcp@0.5 --version (→ 0.5.8, cache package.json 0.5.8 / 0.5.8), then npx -y sentinel-ir-mcp@0.5 --version.
  • npm 10.8.2 (Node 20): stays 0.5.8, as the README says.
  • npm 11.19.1 (Node 24): 0.5.9, and the cache 46f9bf218df4163a → 0.5.9 / 0.5.9.
  • The README says range copies stay stale and that this was "measured incl. npm 11.21.2". The advice (use @stable-0.5) is still right, but the sentence should say the behaviour depends on the npm version.

18. docs: the library alias list is incomplete

The library README table shows python (alias py) and rust (alias rs) only. js, ts and upper-case names (JS) also work, and the MCP README lists js / ts.

What I verified works

sentinel-ir (Node 20, 22, 24)

  • npm install sentinel-ir in a fresh project. npm 11 prints the install-scripts ... allowScripts notice for tree-sitter*, which the README mentions; analysis works regardless (native prebuild on darwin-arm64, WASM for the others).
  • The README Usage example output matches the README exactly. examples/basic.js works on JS, JSX, TS, .d.ts, TSX, Python and Rust.
  • Files that do not parse fall back to heuristics with facts.ast: false and correct positions: broken.js 1:11 unclosed (, broken.tsx 1:29 unclosed {, broken.rs 1:11 unclosed {, Python 2:7 missing ).
  • .rb / .go targets → incomplete, unknown, unsupported file type reason. Sync Python without init → incomplete with a clear reason.
  • Output is identical on all three Node versions.
  • Strict TypeScript (module = nodenext, bundler, preserve): the shipped declarations type-check, aliases are typed, ESM import works, and wrong argument types are caught.

sentinel-ir-mcp (Node 20, 22, 24)

  • npx -y sentinel-ir-mcp@0.5 --version / -v, --help, guide, log; log | head -1 exits without EPIPE.
  • setup: interactive on a TTY (cursor, with exclusions + audit log), --yes is idempotent, --dry-run, --global, --project <dir>. Windsurf and Claude Desktop JSON is valid. VS Code / Claude Code print a working command. Re-running preserves keys that Claude Desktop added (preferences) and makes a backup.
  • doctor per client, a real MCP handshake, the unmatched-exclusion warning, the warning for a pinned or old entry ("run setup"), and the 0.5.8 self-check ("This is sentinel-ir-mcp 0.5.8, npm has 0.5.9 ... runs from the npx cache (...)").
  • MCP stdio with the SDK client: analyze_code, analyze_file and analyze_directory all work, including paths with spaces and ž ü and a ..cache/ folder name. Refusals: outside existing/missing/../src/../../dangling symlink → the same Access denied; symlink out → outside; hard link → has 2 hard links; files with more than one are refused; big.js → File too large: big.js is 1800000 bytes, limit is 1048576; .md / Makefile / .rb → Unsupported file type ... (only ...); excluded (existing and missing) → the same refusal; Not a file / Not a folder; file:///etc/passwd → outside; empty path → schema error.
  • The audit log records every case above with distinct wording (check 6).
  • First connect on a fresh cache took about 1.8 s; npm's "npm 12" notice goes to stderr and does not break stdio.

Upgrade from 0.5.8 (README flow, npm 10.8.2)

  • Seeded @0.5 and @stable-0.5 with --before → cache package.json 0.5.8 / 0.5.8. Then @stable-0.5 → 0.5.9 (cache 3ec5bc0582433d0b 0.5.9 / 0.5.9), while @0.5 stays 0.5.8, as documented. Doctor warns (with the wording problem in #2). Following the README (close the client, delete the folder, setup --client cursor --yes) rewrites the entry to @stable-0.5. The command in the config then runs 0.5.9, confirmed from the cache package.json, and doctor is all [ok].

Another volume

  • APFS disk image mounted at /Volumes/Druhý disk, project Moje projekty/app ž (Node 22). Relative and absolute paths and file:// URLs work. A symlink back to the boot volume is refused as outside, and hard links are refused. analyze_directory works. setup --client claude-desktop --project "<vol path>" --audit-log --yes works, doctor is OK, and the exact command from the generated config starts the server.

Desktop clients (no login)

  • VS Code 1.146.0: the printed code --add-mcp command → "Added MCP servers: sentinel-ir"; mcp.json is correct, including the non-ASCII path. "Continue without Signing In" → MCP: List Servers → Start → Running, "Discovered 3 tools". ps showed node ~/.npm/_npx/3ec5bc0582433d0b/node_modules/.bin/sentinel-ir-mcp ..., whose cache package.json is 0.5.9 / 0.5.9. Works end to end.
  • Cursor 3.30.14: accepted the generated .cursor/mcp.json. Its log shows mcp.installed {name: sentinel-ir, command: npx -y sentinel-ir-mcp@stable-0.5} and State transition: project-0-Můj projekt ž-sentinel-ir none → disconnected. It then shows a Log In / Sign Up wall, and no server process starts without login. This is a client limitation, not a package bug.
  • Claude Desktop 5.11492.5: accepted the config and kept our entry when it added its own preferences. The "Get started" login wall blocks MCP; mcp.log stays empty and no process starts. This is a client limitation.

Network: across all URL and UNC calls, no SMB traffic and no lookups of the named hosts (check 1).


Independent Engineering Projects

Built as independent engineering experiments across AI, software analysis, security, and autonomous systems.

Evaluated by reproducible evidence, not by the number of layers.

Explore the projects:

Sentinel Ecosystem: AutoDoc-Sentinel, Sentinel-IR, Sentinel-IR-MCP and related tools.
Agentix Lite: Independent security and system-observation project.
Find the projects: GitLab repositories | NPM packages

Support the work: ⭐ Star the repositories on GitLab.

Connect: Follow me here on DEV Community or explore the Playground.

Each project is distributed under its own license. Check the corresponding repository or NPM package for licensing terms.

Copyright © 2026 jackymenCZ. All rights reserved. Written for the community.

Top comments (0)