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:
cd "/Users/devin/Projekty/Můj projekt ž"-
npx -y sentinel-ir-mcp@stable-0.5 setup --client vscode --exclude secrets --audit-log, then run the printedcode --add-mcp '{...}'command. VS Code writes~/Library/Application Support/Code/User/mcp.jsoncontaining"--exclude=secrets", "--audit-log". 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 theirsecretsexclusion 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. 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": [] } 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):
-
npx -y sentinel-ir-mcp@0.5.8 --version→0.5.8. The cache keye90bfea4b29781f8= sha512("sentinel-ir-mcp@0.5.8"), and itspackage.jsonhas 0.5.8 / sentinel-ir 0.5.8. -
npx --before=2026-11-15T16:00:00Z -y sentinel-ir-mcp@latest --version→0.5.8(key44517f9a0f1686df=@latest). npx -y sentinel-ir-mcp@stable-0.5 doctor --client cursor
-
- Actual: Doctor reports only the
@latestcopy:
[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. 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.5the same way (npx --before=... -y sentinel-ir-mcp@0.5 --version), then run doctor. The warning namessentinel-ir-mcp@^0.5.8for key46f9bf218df4163a(=sentinel-ir-mcp@0.5). That is the range npx writes into its privatepackage.json; the user's config sayssentinel-ir-mcp@0.5. For the@latestkey 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); - Expected (README §Languages): "An explicit unsupported
language(e.g."ruby") ... is reported asanalysisStatus: "incomplete"withlanguage: "unknown"andfacts.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)' } 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.objectiveand so on. - Actual:
TypeError: Cannot read properties of undefined (reading 'risk') 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.js21,823 → 449;sentinel-ir.js9,123 → 515;tree-parser.js4,393 → 465;basic.js600 → 461; "about 400 characters plus the facts". - Actual 0.5.9:
ast-facts.js96,821 → 511;sentinel-ir.js20,413 → 621;tree-parser.js13,175 → 803;basic.js600 → 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), thennpx -y sentinel-ir-mcp@stable-0.5 setup --client cursor --no-exclude --no-audit-log --yesandnpx -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. 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). - Repro B:
npx -y sentinel-ir-mcp@stable-0.5 setup --client cursor --global --dry-runprintsAudit 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--clientit 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 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" }andanalyze_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 URLasfile: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_directoryon a folder with 3 symlinks, 3 hard links, 1 oversized file and broken files, thennpx -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
incompletefiles, 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"butforbidden: ["process.exit"].
- A broken file containing
- The bare
use std::processrule is documented, but a "child_process" label on Rust code that only exits looks wrong to a newcomer. A non-emptyforbiddenwith a JS name atlowrisk 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) ... - Expected: a one-line
basic.js: cannot read nope.jsplus usage. Also,npx sentinel-ir file.jsgivesnpm 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
-
guidestep 2 has a ragged wrap:
2. Look at "incomplete", "skipped.unreadable" and "skipped.hardlinks" before anything else. Those files were not fully analyzed: ... - 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 outnot-a-folder, whichlogdoes print. - "What the server can and cannot do" (the section a cautious user reads) does not mention that URLs,
file:without//, remotefile://host/and UNC paths are refused. That is only in the 0.5.9 changelog. - The minimum
sentinel-irversion (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, cachepackage.json0.5.8 / 0.5.8), thennpx -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 cache46f9bf218df4163a→ 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-irin a fresh project. npm 11 prints theinstall-scripts ... allowScriptsnotice fortree-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.jsworks on JS, JSX, TS,.d.ts, TSX, Python and Rust. - Files that do not parse fall back to heuristics with
facts.ast: falseand correct positions:broken.js1:11 unclosed(,broken.tsx1:29 unclosed{,broken.rs1:11 unclosed{, Python 2:7 missing). -
.rb/.gotargets →incomplete,unknown,unsupported file typereason. Sync Python without init →incompletewith 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 -1exits without EPIPE. -
setup: interactive on a TTY (cursor, with exclusions + audit log),--yesis 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. -
doctorper 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_fileandanalyze_directoryall work, including paths with spaces andž üand a..cache/folder name. Refusals: outside existing/missing/../src/../../dangling symlink → the sameAccess 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.5and@stable-0.5with--before→ cachepackage.json0.5.8 / 0.5.8. Then@stable-0.5→ 0.5.9 (cache3ec5bc0582433d0b0.5.9 / 0.5.9), while@0.5stays 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 cachepackage.json, and doctor is all[ok].
Another volume
- APFS disk image mounted at
/Volumes/Druhý disk, projectMoje projekty/app ž(Node 22). Relative and absolute paths andfile://URLs work. A symlink back to the boot volume is refused as outside, and hard links are refused.analyze_directoryworks.setup --client claude-desktop --project "<vol path>" --audit-log --yesworks, 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-mcpcommand → "Added MCP servers: sentinel-ir";mcp.jsonis correct, including the non-ASCII path. "Continue without Signing In" →MCP: List Servers→ Start →Running, "Discovered 3 tools".psshowednode ~/.npm/_npx/3ec5bc0582433d0b/node_modules/.bin/sentinel-ir-mcp ..., whose cachepackage.jsonis 0.5.9 / 0.5.9. Works end to end. - Cursor 3.30.14: accepted the generated
.cursor/mcp.json. Its log showsmcp.installed {name: sentinel-ir, command: npx -y sentinel-ir-mcp@stable-0.5}andState 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.logstays 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.



