{"slug": "sentinel-ir-mcp-0-5-give-your-ai-agent-a-library-card-not-the-master-key", "title": "Sentinel-IR MCP 0.5: give your AI agent a library card, not the master key", "summary": "A developer released sentinel-ir-mcp 0.5, a read-only stdio MCP server that gives coding agents a compact structural intermediate representation of code — risk level, dangerous capabilities, routes, imports, and env/network/filesystem/process/crypto calls with line numbers — instead of raw source, supporting JavaScript, TypeScript, Python and, new in 0.5, Rust. The server confines every path to operator-approved roots, refuses symlinks and excluded files, never writes or executes code, and offers an opt-in audit log recording tool, path, result and file SHA-256; on a 190-file Node project the default directory summary was about 35,856 characters (~9,000 tokens) versus 8,439 tokens for a single mid-sized file read raw.", "body_md": "*A 10-minute read for developers, platform teams and whoever has to answer \"wait, what can the agent read?\" in a security review.*\n\n`io.github.jakcmencz/sentinel-ir-mcp`)\n`sentinel-ir-mcp` is a stdio [MCP](https://modelcontextprotocol.io) server\n\nwith three read-only tools: `analyze_code`, `analyze_file` and\n\n`analyze_directory`. Instead of raw source, the agent gets a compact\n\nstructural IR from\n\n[`sentinel-ir`](https://gitlab.com/jakubrojicek11/sentinel-ir): risk level,\n\ndangerous capabilities, routes, imports, env reads, network, filesystem,\n\nprocess and crypto calls, each with a line number. It works with\n\nJavaScript, TypeScript, Python and, since 0.5, Rust.\n\nThe 0.5 line is about two things: **Rust**, and making sure the copy\n\nrunning on your machine is **the one with the fixes**. Plus a `doctor` that\n\nwe tried very hard to break on three operating systems.\n\nCoding agents have discovered the filesystem, and they *love* it. Ask \"is this\n\nrepo safe to deploy?\" and a typical agent `cat` s twenty files into its context.\n\nThat's 50,000 tokens of business logic, license headers and a comment from\n\n2019 that says `// TODO: remove before prod`. Then it answers from vibes.\n\nThree costs:\n\n`src/ast-facts.js` is 8,439 tokens. Its IR is\n120.`curl … | sh`\" is a real genre now.`~/.ssh` included.\n`sentinel-ir-mcp` is the opposite design: small facts, narrow scope, no\n\nwrites.\n\nThe intended workflow, which the tool descriptions spell out for the agent:\n\n`analyze_directory` the project. You get one short entry per file\n(path, risk, status, language, lines, operations, up to 3 risk signals),\nsorted from highest to lowest risk, plus `riskCounts`.` critical` and `high` files and the `incomplete` ones.\nIncomplete means \"didn't fully parse\", and its `low` is On a 190-file Node project the default summary was 35,856 characters\n\n(about 9,000 tokens) for the **whole folder**. That's less than a single\n\nmid-sized file read raw.\n\n```\n{\"folder\":\".\",\"analyzed\":42,\"riskCounts\":{\"critical\":1,\"high\":2,\"medium\":6,\"low\":33},\n \"files\":[{\"path\":\"src/deploy.rs\",\"risk\":\"critical\",\"language\":\"rust\",\n   \"operations\":[\"processSpawn\"],\"riskSignals\":[\"process_spawn:Cmd::new@14\"]}, \"...\"]}\n```\n\n(Illustrative shape, trimmed.)\n\nThis is the part your security team will read, so we wrote it like an\n\ninterface contract.\n\n**It only reads.** The server never writes project files, never executes\n\ncode and never opens a network connection. The tools are annotated\n\n`readOnlyHint: true`, `destructiveHint: false`, `openWorldHint: false`.\n\n**Only inside the folders you allowed.** Roots come from the command line\n\nor, without folder arguments, from the client's MCP roots. Every requested\n\npath is resolved to its real path and must land inside a root. In our audit\n\nof the published 0.5.5 package, the server refused all of these:\n\n``` php\n../outside/s.js            -> Access denied: outside the allowed folders\n/etc/passwd                -> Access denied: outside the allowed folders\nsrc/link.js (symlink out)  -> Access denied\nsecrets/x.js (excluded)    -> Excluded by the user's settings. Do not try to read it another way.\n```\n\n**The boring attacks are handled too:**\n\n`O_NOFOLLOW` and directory scans skip every symlink.`node_modules`, `.git`, `venv`, hidden folders and Cargo `target/` (only when it has Cargo's `CACHEDIR.TAG`).\n**Exclusions belong to the human.** `setup --exclude secrets --exclude dist`\n\nwrites them into the client config. The agent can't change them, and\n\nneither can the analyzed repo: there's deliberately no `.sentinelignore`,\n\nbecause a malicious repo would use it to hide its own payload. Excluded\n\nfiles are refused by `analyze_file` and only *counted* by\n\n`analyze_directory`, because file names can be sensitive too.\n\n**An audit log, for the \"who asked for what\" question.** It's opt-in\n\n(`setup --audit-log`). It records the tool, the path, the result and the\n\nSHA-256 of each file the agent was shown, and never the source. It must\n\nlive outside the project, rotates daily, keeps 30 days and stays under 50 MB\n\na day. Read it with `npx -y sentinel-ir-mcp@stable-0.5 log`:\n\n```\n2026-10-18 10:32:05 [cursor] file src/app.js: critical\n2026-10-18 10:32:09 [cursor] REFUSED file secrets/aws.js: excluded by your settings\n2026-10-18 10:33:40 [cursor] folder .: 42 file(s) (1 critical, 6 medium, 35 low), 3 excluded\n```\n\n**The IR is still untrusted text.** Comments and string bodies are not\n\ncopied, and since `sentinel-ir` 0.5.4 every string is capped at 128\n\ncharacters and literals in evidence show up as `\"…\"`. Identifiers and route\n\npaths still come from the code. That *reduces* the injection surface; it\n\ndoesn't remove it, and every tool description tells the agent to treat IR\n\nvalues as data, not instructions.\n\n`.rs` files go through `sentinel-ir`'s new Rust analyzer: `unsafe` and FFI,\n\n`std::process::Command`, file writes and deletes, HTTP clients and servers\n\n(`axum`, `actix-web`, ...). A `build.rs` or procedural macro that touches\n\nfiles, the network or secret env vars is at least `high`, because it runs on\n\nyour machine during `cargo build`. For a supply-chain attacker that's the\n\nbest seat in the house.\n\nHere's a fun fact we measured against a local npm registry: **`npx` never\nre-resolves a cached version range.** Configure your client with\n\n`sentinel-ir-mcp@0.5` and npx keeps starting the first 0.5.x it downloaded,\n\nforever, even after security fixes ship. It's like a fridge that only ever\n\nrestocks the milk you bought in March.\n\nA dist-tag *is* re-resolved on every start. So `setup` now writes\n\n`sentinel-ir-mcp@stable-0.5`, and CI moves that tag forward on every release\n\n(never backwards). Without network access, the cached copy still starts. The\n\nserver also requires `sentinel-ir` ≥ 0.5.6, which pulls in the\n\ncomment-hiding, parse-budget and broken-file fixes. `doctor` warns about\n\npinned entries and stale `_npx` cache copies, with the exact folder to\n\ndelete.\n\nEach tool description is now short lines in a fixed order: what it does,\n\nwhat it returns, the parameters, the risk scale, when it refuses, and **which sibling tool to use instead** (\"for a folder use \n\n`medium` (network, writes, crypto) is normal in`fetch()`.` doctor`, the part we tried hardest to break (0.5.4–0.5.5)\n`npx -y sentinel-ir-mcp@stable-0.5 doctor` checks Node, the package versions,\n\nthe client configs, exclusions, the audit log, a real MCP handshake and a\n\nreal `analyze_directory` call. Since 0.5.4 it also asks npm whether a newer\n\n`stable-0.5` exists (3 s timeout, skipped offline) and tells you where the old\n\ncopy runs from: the npx cache, a global install, `npm link`, Homebrew,\n\nnvm-windows or Volta.\n\nThen we spent a day trying to break it on Linux, macOS and Windows, with a\n\nfake registry that answered in 28 different wrong ways (slow drips, gzip\n\nbombs, redirect loops, `__proto__`, ANSI escapes with newlines) and 17\n\nproxy setups. Things we found and fixed before 0.5.5 shipped:\n\n`%` in a password crashed the check.`NO_PROXY` was ignored under npx, because npm sets an empty `npm_config_noproxy`.` cafile` and `strict-ssl` from `.npmrc` were ignored, so corporate proxies looked \"offline\".`[warn]`. Now it counts the warnings.\nEvery case ends with a sensible message and exit code 0, in at most about\n\n3.5 s. Behind a corporate proxy, `doctor` now behaves like npm does.\n\nAfter 0.5.5 we audited the published package as a whole instead of trying to\n\nbreak one feature. Nothing security-relevant turned up. Four small fixes\n\nshipped:\n\n`guide` (the agent's manual) still said \"JavaScript and TypeScript\".`..cache` was treated as \"outside\".`npm audit` in the lock file showed two moderate advisories in a transitive\nHono dependency of the MCP SDK. The stdio server never loads Hono, and fresh\ninstalls were already clean. The lock file now reports 0 vulnerabilities.`@modelcontextprotocol/sdk`, `zod` and\n`sentinel-ir`. About 100 packages in \n\n```\n# interactive: picks the client, the project folder, exclusions, audit log\nnpx -y sentinel-ir-mcp@stable-0.5 setup\n\n# or explicit\nnpx -y sentinel-ir-mcp@stable-0.5 setup --client cursor --project ~/code/app \\\n  --exclude secrets --exclude dist --audit-log\n\n# then\nnpx -y sentinel-ir-mcp@stable-0.5 doctor\n```\n\n`setup` shows what it will write, makes a backup, writes atomically, and\n\nrefuses to give an agent your whole home folder or a whole disk. Claude\n\nDesktop, Cursor and Windsurf are supported directly. Any other MCP client\n\njust runs `npx -y sentinel-ir-mcp@stable-0.5 /path/to/project`.\n\n`build.rs` and proc-macro behaviour in new\ndependencies before `cargo build` runs them on 200 laptops.`rustc`).\nGo is next. Because the server speaks the shared `sentinel-ir` IR, a new\n\nlanguage in the library lands in the MCP server and the\n\n[playground](https://sentinel-ir-playground-dc30c8.gitlab.io/) without a\n\nnew output format, so your agent's prompts don't change.\n\nBug reports and merge requests are welcome on\n\n[GitLab](https://gitlab.com/jakubrojicek11/sentinel-ir-mcp). If you manage to\n\nmake the server read `/etc/passwd`, we'd genuinely like to hear about it\n\nbefore your glama.ai followers do.\n\nIndependent Engineering Projects\n\nBuilt as independent engineering experiments across AI, software analysis, security, and autonomous systems.\n\nEvaluated by reproducible evidence, not by the number of layers.\n\nExplore the projects:\n\nSentinel Ecosystem: AutoDoc-Sentinel, Sentinel-IR, Sentinel-IR-MCP and related tools.\n\nAgentix Lite: Independent security and system-observation project.\n\nFind the projects: GitLab repositories | NPM packages\n\nSupport the work: ⭐ Star the repositories on GitLab.\n\nConnect: Follow me here on DEV Community or explore the Playground.\n\nEach project is distributed under its own license. Check the corresponding repository or NPM package for licensing terms.\n\nCopyright © 2026 jackymenCZ. All rights reserved. Written for the community.", "url": "https://wpnews.pro/news/sentinel-ir-mcp-0-5-give-your-ai-agent-a-library-card-not-the-master-key", "canonical_source": "https://dev.to/jackymencz/sentinel-ir-mcp-05-give-your-ai-agent-a-library-card-not-the-master-key-5hg1", "published_at": "2026-11-14 17:44:54+00:00", "updated_at": "2026-11-14 17:50:57.588552+00:00", "lang": "en", "topics": ["ai-agents", "agent-protocols", "developer-tools", "ai-tools", "ai-safety"], "entities": ["sentinel-ir-mcp", "sentinel-ir", "Model Context Protocol", "Rust", "JavaScript", "TypeScript", "Python"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/sentinel-ir-mcp-0-5-give-your-ai-agent-a-library-card-not-the-master-key", "markdown": "https://wpnews.pro/news/sentinel-ir-mcp-0-5-give-your-ai-agent-a-library-card-not-the-master-key.md", "text": "https://wpnews.pro/news/sentinel-ir-mcp-0-5-give-your-ai-agent-a-library-card-not-the-master-key.txt", "jsonld": "https://wpnews.pro/news/sentinel-ir-mcp-0-5-give-your-ai-agent-a-library-card-not-the-master-key.jsonld"}}