<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ranadhir ghosh</title>
    <description>The latest articles on DEV Community by ranadhir ghosh (@ranadhir19).</description>
    <link>https://dev.to/ranadhir19</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4224852%2F129163ea-3ebc-47ef-8c3e-20785e8ca8d5.png</url>
      <title>DEV Community: ranadhir ghosh</title>
      <link>https://dev.to/ranadhir19</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ranadhir19"/>
    <language>en</language>
    <item>
      <title>Know What Your Agent's Tools Can Do to You: Scanning MCP Servers Before You Install Them</title>
      <dc:creator>ranadhir ghosh</dc:creator>
      <pubDate>Tue, 03 Nov 2026 19:07:00 +0000</pubDate>
      <link>https://dev.to/ranadhir19/know-what-your-agents-tools-can-do-to-you-scanning-mcp-servers-before-you-install-them-21jk</link>
      <guid>https://dev.to/ranadhir19/know-what-your-agents-tools-can-do-to-you-scanning-mcp-servers-before-you-install-them-21jk</guid>
      <description>&lt;p&gt;In an April 2026 audit, 27 detections from MCP security scanners boiled down to 6 genuine concerns. The scanners weren't missing attacks — they were crying wolf, which in a CI pipeline is the same failure wearing a different coat.&lt;/p&gt;

&lt;p&gt;So I built a scanner whose first feature is its own error profile: every rule publishes a measured precision from a labelled corpus of planted positives and near-miss traps. This is how it works, what it catches — tool poisoning, rug pulls, dangerous sinks, hardcoded secrets — and where its numbers say it still gets things wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  One command before you install
&lt;/h2&gt;

&lt;p&gt;Sentinel Scan is a security and conformance scanner for MCP servers and SKILL.md agent skills. One command scans a server or skill for tool poisoning, rug pulls, dangerous code sinks, and hardcoded secrets — and reports each rule's measured precision rather than just asserting it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;sentinel-scan
sentinel-scan demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The demo scans the bundled 12-tool corpus in about a second: 6 benign tools — two of them near-miss traps — and 6 with planted findings, producing 7 findings. The two traps produce no findings: a tool that "ignores previous cached results" and a security tool that quotes an injection as an example. That restraint is the product.&lt;/p&gt;

&lt;p&gt;Pure Python, no API keys, no GPU, no network. Python ≥ 3.10.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it catches
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tool poisoning:&lt;/strong&gt; hidden instructions in tool descriptions — markup directives, "note to the AI" framing, ignore-instruction phrasing — plus descriptions that direct credentials, files, or conversation contents out, and covert actions a tool takes "without telling the user."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rug pulls:&lt;/strong&gt; a tool's description changing after you pinned it. Sentinel Scan stores a SHA-256 pin of the normalized description and flags quiet changes (whitespace-only edits ignored).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dangerous sinks:&lt;/strong&gt; command execution (&lt;code&gt;shell=True&lt;/code&gt;, &lt;code&gt;os.system&lt;/code&gt;, string commands — fixed argv with &lt;code&gt;shell=False&lt;/code&gt; does not fire), dynamic code (&lt;code&gt;eval&lt;/code&gt;/&lt;code&gt;exec&lt;/code&gt; — &lt;code&gt;ast.literal_eval&lt;/code&gt; does not fire), and sensitive-file access (&lt;code&gt;~/.ssh&lt;/code&gt;, &lt;code&gt;~/.aws&lt;/code&gt;, &lt;code&gt;/etc/passwd&lt;/code&gt;, key files, full environment dumps — a comment merely mentioning a path does not fire).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardcoded secrets:&lt;/strong&gt; AWS key ids, GitHub tokens, OpenAI-style keys, private-key blocks, assigned credential literals (&lt;code&gt;${VAR}&lt;/code&gt; references do not fire).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skill rules:&lt;/strong&gt; hidden instructions in a SKILL.md body, capabilities the body uses but the frontmatter does not declare, and filesystem servers scoped to &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;~&lt;/code&gt;, or a home directory instead of a project directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Measured, not asserted
&lt;/h2&gt;

&lt;p&gt;Each rule is deliberately narrow: it fires on a specific, explainable signal shape. The rates are measured with &lt;code&gt;scripts/measure.py&lt;/code&gt; over the labelled corpus in &lt;code&gt;fixtures/corpus/&lt;/code&gt; — 32 cases of planted positives and benign near-miss negatives for every rule. Across all rules: 18 true positives, 0 false positives, 0 false negatives.&lt;/p&gt;

&lt;p&gt;Those are corpus rates, not a promise about the open internet. Re-run the measurement yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 scripts/measure.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using it
&lt;/h2&gt;

&lt;p&gt;Scan an MCP config, a tools manifest, server sources, or skill folders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sentinel-scan scan ~/.config/...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exit codes are CI-shaped: the scan exits 1 when any finding is at or above &lt;code&gt;--fail-on&lt;/code&gt; (default high). Outputs are terminal text, JSON, and SARIF, which renders in the GitHub Security tab. There is also a GitHub Action (&lt;code&gt;ranadhir19/sentinel-scan@v0.1.0&lt;/code&gt;) that runs the scan, writes SARIF, and uploads it to the Security tab.&lt;/p&gt;

&lt;p&gt;What it does not do: no dynamic execution of scanned servers, no LLM judgement calls, no network calls. It is static analysis. There is also a local web demo in &lt;code&gt;demo/&lt;/code&gt; (React front end, FastAPI backend) if you want to paste a description, a SKILL.md body, or source and watch it scan.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/ranadhir19/sentinel-scan" rel="noopener noreferrer"&gt;https://github.com/ranadhir19/sentinel-scan&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>mcp</category>
      <category>ai</category>
      <category>python</category>
    </item>
    <item>
      <title>Prove It Works: Building an Eval That Can Catch a Broken Benchmark</title>
      <dc:creator>ranadhir ghosh</dc:creator>
      <pubDate>Tue, 03 Nov 2026 18:57:15 +0000</pubDate>
      <link>https://dev.to/ranadhir19/prove-it-works-building-an-eval-that-can-catch-a-broken-benchmark-2c4</link>
      <guid>https://dev.to/ranadhir19/prove-it-works-building-an-eval-that-can-catch-a-broken-benchmark-2c4</guid>
      <description>&lt;p&gt;A benchmark with flawed tests measures the tests. So I built two suites — one clean, one with 12 flaws planted in the tests — and watched a do-nothing agent start scoring points while my reference agent lost 8.3 points to the tests themselves.&lt;/p&gt;

&lt;p&gt;This is the full experiment: calibrating the graders first, pre-registering the audit bar, catching 11 of 12 flaws — and being honest about the one that got away.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Local, deterministic, no API keys — a lab for auditing your eval before your eval audits your agent. The setup is a clean 60-task suite (arithmetic, extraction and classification; gold answers cross-checked by an independent second implementation) and an identical twin with 12 flaws planted in the tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the flaws did
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Null agent (outputs nothing): 0/60 on the clean suite, 2/60 on the flawed suite&lt;/li&gt;
&lt;li&gt;Echo agent: 0/60 on the clean suite, 4/60 on the flawed suite&lt;/li&gt;
&lt;li&gt;Reference agent: 60/60 on the clean suite, 55/60 on the flawed suite — 8.3 points lost to the tests, not the tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Calibrate the graders first
&lt;/h2&gt;

&lt;p&gt;Three graders were validated on 150 labelled items before any audit run: exact-match 80.0%, normalized 100%, rubric 99.3%. The point is stated plainly in the lab: an uncalibrated grader is just another flawed test.&lt;/p&gt;

&lt;h2&gt;
  
  
  The audit
&lt;/h2&gt;

&lt;p&gt;The audit bar was registered before the run: at least 10 of the 12 flaws caught, at most 3 false flags. The audit caught 11 of 12 planted flaws with zero false flags. The one miss, flaw-09, had its gold and its source document disagreeing (300 vs 315) from the same table — shared-source flaws are the hard class, and that is exactly what to test for next.&lt;/p&gt;

&lt;p&gt;If you build or trust agent benchmarks, audit the proof itself, not just the score.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/ranadhir19/agent-eval-lab" rel="noopener noreferrer"&gt;https://github.com/ranadhir19/agent-eval-lab&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>llm</category>
      <category>python</category>
    </item>
    <item>
      <title>Build an MCP Server a Model Can Actually Use</title>
      <dc:creator>ranadhir ghosh</dc:creator>
      <pubDate>Tue, 03 Nov 2026 18:51:52 +0000</pubDate>
      <link>https://dev.to/ranadhir19/build-an-mcp-server-a-model-can-actually-use-1flc</link>
      <guid>https://dev.to/ranadhir19/build-an-mcp-server-a-model-can-actually-use-1flc</guid>
      <description>&lt;p&gt;Most MCP tutorials stop at "it connects." But a model never sees your server code — it sees tool names, descriptions and JSON schemas. An MCP server is a user interface designed for a language model, and interfaces can be measured.&lt;/p&gt;

&lt;p&gt;So I built one server twice, attacked both designs with the ten worst calls a model could plausibly make, and ran a model against each. The loose design rejected 0 of 10. The strict redesign rejected 10 of 10. Here is the full experiment — including the metric that pointed the wrong way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two designs, one notes store
&lt;/h2&gt;

&lt;p&gt;The lab is a notes MCP server in pure Python stdlib, speaking JSON-RPC 2.0 over stdio, with &lt;code&gt;initialize&lt;/code&gt;, &lt;code&gt;tools/list&lt;/code&gt; and &lt;code&gt;tools/call&lt;/code&gt;. The same notes store is exposed through two schema designs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;v1, deliberately loose:&lt;/strong&gt; three vague tools, a free-form action string, no required fields, and bloated results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v2, the strict redesign:&lt;/strong&gt; one verb per tool, descriptions that say when &lt;em&gt;not&lt;/em&gt; to use the tool, strict schemas, compact results, and structured errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The question was stated before any run: does schema redesign change how often models pick the wrong tool, produce malformed calls, or fail tasks? The pre-stated bar was that v2 counts as a win only if wrong-tool calls fall by at least 30% relative to v1 and task completion rises.&lt;/p&gt;

&lt;h2&gt;
  
  
  The adversarial audit
&lt;/h2&gt;

&lt;p&gt;The deterministic audit sends 10 adversarial call classes — unknown ids, missing fields, wrong types, and invented actions. v1 rejected none of them and let bad calls change its data; v2 rejected all 10.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model trials
&lt;/h2&gt;

&lt;p&gt;Then a small local model (Qwen2.5-0.5B) ran 16 tasks against each design, with a chooser that sees only the &lt;code&gt;tools/list&lt;/code&gt; output and a request, answers with one JSON tool call, and has that call executed for real against a fresh seeded store. Wrong-tool calls fell from 7 to 1, malformed calls from 4 to 1, and completed tasks rose from 6 to 13 of 16.&lt;/p&gt;

&lt;p&gt;One honest failure is kept in the repo: a word-overlap "confusability" metric ranked the designs backwards (0.074 vs 0.289). Longer descriptions share more vocabulary; shared words are not shared meaning.&lt;/p&gt;

&lt;p&gt;The point is not the notes app. It is that an MCP server is a UI for a model, and that interface can be measured — with an audit suite, a fixed task set, and a grading rubric — before you trust it in production.&lt;/p&gt;

&lt;p&gt;Repo (server, both schemas, harness, audits — all runnable): &lt;a href="https://github.com/ranadhir19/mcp-server-lab" rel="noopener noreferrer"&gt;https://github.com/ranadhir19/mcp-server-lab&lt;/a&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>mcp</category>
      <category>ai</category>
      <category>python</category>
    </item>
  </channel>
</rss>
