npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@agentx-core/scan

v0.5.0

Published

List the tools your AI agent can call, ranked by how dangerous they are, and which are unguarded.

Readme

@agentx-core/scan

List the tools your AI agent can call, ranked by how dangerous they are.

No install, no signup, no code changes:

npx @agentx-core/scan .
🔍 AGENTX SCAN        (TypeScript · 1 file · 4 tools)
===========================================================================

  RISK   TOOL                SYSTEM    WHY
  ----   ----                ------    ---
  high   purgeUploads        -         calls `fs.unlink`
         src/tools.ts:6

  med    refundCharge        Stripe    calls `fs.writeFile`
         src/tools.ts:7

  -----------------------------------------------------------------------

  1 of 4 tools can take destructive or batch actions.
  1 writes or sends. 2 need a human look.

  1 could not be traced to an agent.
    It is exported, so something outside this scan may wire it up.

  Your tools connect to: Stripe, read from each tool's own code.
  1 tool has no body this scan could read.
  What it reaches is unread.

  Showing high and med only. Run with --all to list all 4 tools.

  -----------------------------------------------------------------------

  These can do things the AgentX gateway blocks on the live call:
    Mass Destructive Intent     purgeUploads

  Nothing in this project is guarding them: no AgentX in your dependencies or
  MCP config. A guard added at runtime would not show in a static scan.

(Trimmed after this point; the run ends with the next steps below.)

What it does

When you give an LLM a tool, you give it a real function and let it choose the arguments. The tools it can call are your risk surface. Scan reads that surface out of your code and sorts it, so the destructive end is the first thing you see.

It reports:

  • What the model can call — every declared tool it can read, with file:line. What it cannot read is named rather than dropped; see What it supports below.
  • How dangerous each one ishigh / med / low, plus review when we genuinely could not tell.
  • Why — every ranking carries its evidence, so you can audit it rather than trust it.
  • What each tool can reach — the external services its own body uses (SYSTEM), named by company rather than by category: Stripe, OpenAI, Anthropic, SendGrid, Postgres. Which company is the question a security review actually asks. Read from the tool's own code, not from its file's imports, so one Stripe import does not tar every tool beside it. A ? in the column means that tool's body went unread, and the column shows nothing else for it. What such a tool's file imports is reported separately in the prose below the table, labelled as the guess it is, rather than filled into the column as though we had read it.
  • Whether an agent can actually call it — a tool that was written but never wired into an agent is not a live capability. Three answers, and the third is the point: registered, not-registered, and unknown when the tools list is assembled somewhere a static scan cannot follow. We would rather say "cannot tell" than tell you a wired-up tool is dead code.
  • Where it was declared — tools in test/ and scripts/ are marked, so an examples-heavy repo does not read as a 400-tool agent.

What it supports

TypeScript agents built on the Vercel AI SDK (ai) or LangChain.js (@langchain/*). Both converge on the same tool() helper, so one detector covers both. If your agent uses something else, we cannot see it yet — that is a gap in this scanner, not in what can be guarded, and the gateway does not care which framework you use.

Two shapes inside those frameworks are not read yet, require() in place of import and LangChain's new DynamicStructuredTool({...}) class form. Neither is silent: the scan names the files and tells you the counts are short. Both are detailed under Limits below, which is where they are described in full so the two lists cannot drift apart.

TypeScript source, literally. Files must be .ts, .tsx, .mts or .cts. Plain JavaScript (.js, .jsx, .mjs, .cjs) is not read at all — a JavaScript agent scans as zero files, and the run tells you nothing was read rather than reporting "no tools found".

How it avoids crying wolf

A scanner that flags everything is a toy. Two rules keep this one honest:

  • AST, never regex, and every detection is import-gated. tool only counts when it was actually imported from ai or @langchain/*. A local function named tool cannot produce a hit. Scanning a current checkout of the Vercel AI SDK repo (5246 TypeScript files), a naive text search matches 916 tool( strings; the real number is 408. Counts move as that repo does, so treat them as one measured run rather than a fixed property.
  • Evidence beats naming. A call to fs.unlink is a fact about your code; a name is only a claim. A tool called tidyUp that unlinks a path ranks high. A tool named runReport with a body we read and found clean does not get escalated on vibes — it goes to review for a human to look at, not to the top of the table.

And when we cannot tell, we say so. This is the part most scanners get wrong, so it is worth being concrete about what review means:

  • An implementation we could not read is review, never low — "unreadable" is not "safe". That includes a body that hands off to an imported helper: execute: handler and execute: (x) => handler(x) are the same fact and get the same answer.
  • A directory we could not open, a broken symlink, a file that would not parse: all reported. Never rounded to "clean".
  • If we could not find your manifest, we say we could not tell whether anything is guarding you, rather than telling you nothing is.

Expect roughly a third of a real codebase to land in review. That is the honest cost of not guessing.

None of those rules came from fixtures. Running this over real repositories is what forced them, and twice it forced a correction. An early classifier demanded a read verb before it would say low, which stranded 168 of 358 tools in review, because real code names tools by noun: weather, cityAttractions. Later, a review found four paths that returned low for a body the scanner had never read, which is the one answer this tool must not give. Both are fixed. No fixture test would have surfaced either.

Guarding what it finds

Scan reports; it does not modify your code. What you do next depends on where you are.

Shipping agents to customers? Their security review will ask what your agent can do and what stops it. Your SOC 2 covers the company, not the agent. We write that up for you, free.

npx @agentx-core/scan . --share

That writes agentx-scan.json locally, then you email it to [email protected] (subject: "security review"). Nothing is uploaded — there is no endpoint; it is a local file and an email address.

By default the file carries only the high and med risk tools, so it is small enough to read before you send it, and it says so at the top. --share --all sends everything.

Just guarding your own project? Both guards are language-agnostic and sit at runtime, so there is no separate SDK to add:

  • Front your agent with the gateway: https://agentx-core.com/gateway
  • Wrap your MCP server in one line: https://github.com/vdalal/agentx-mcp

Limits (worth knowing before you trust a clean result)

  • .ts / .tsx / .mts / .cts only. A plain JavaScript agent is not read, so it scans as zero files. The run says "nothing was read" rather than "no tools found", because those are different answers and only one of them means we looked.
  • ESM only. A file that loads the SDK with require() is not read, so tools declared in it are not listed — but, like the class form below, they are no longer missed in silence. Scan names those files and says the counts are short. It used to tell such a reader that their framework was the one it could not read, while they were on a framework it reads.
  • The tool() helper only. LangChain's new DynamicStructuredTool({...}) class form is not classified yet — but it is no longer missed in silence. Scan counts those declarations and tells you the result is incomplete, because a scan that quietly skips half your tools reads as "you're covered" when you are not.
  • The OpenAI raw-array form (tools: [{ type: 'function' }]) is not detected.
  • SYSTEM spots SDKs, not traffic. We look for a known SDK inside each tool's own code. An API called directly over HTTP has no SDK to spot, so it will not show up. An empty column means "no SDK we could see", never "touches nothing".
  • Reachable, not executed. Everything here is what your agent can do. Only runtime instrumentation knows what it actually did.
  • Risk classification is a coarse heuristic, and deliberately labelled as one. It sorts an inventory; it does not adjudicate whether a tool is exploitable.

Usage

npx @agentx-core/scan [path]        # defaults to the current directory
npx @agentx-core/scan . --all       # list every tool, not just high and med
npx @agentx-core/scan . --json      # machine-readable, always complete
npx @agentx-core/scan . --fail-on-risk  # exit 3 if any high or med risk tool was found
npx @agentx-core/scan . --share     # write the risky tools to a file to send us
npx @agentx-core/scan . --share --all   # same, but every tool
npx @agentx-core/scan --help

--json and --share are different jobs on purpose. --json is for your own tooling and is always the complete list. --share is a file leaving your building, so it defaults to the risky tools only and states in the file how many it left out. Both payloads carry a schema field (agentx.scan/1, view: "full" or view: "share") so a consumer can tell which one it's reading; --json's also carries a cta object (the same next step the human report ends on) so a program parsing it still has something to hand a person. Combine --json and --share and stdout stays pure JSON — the human "wrote the file" message moves to stderr, so npx @agentx-core/scan . --json --share > out.json is always safe to parse.

Use in CI

--fail-on-risk turns a scan into a gate. The command still prints its usual report (or the --json payload, if you also pass --json), and exits 3 if any tool ranked high or med, 0 otherwise. Exit code 3 is deliberate and separate from 1 (a --share write failed) and 2 (bad path), so a bare exit code in a CI log tells you what happened without reading the output.

- name: AgentX scan
  run: npx @agentx-core/scan . --fail-on-risk

Without the flag the exit code is always 0 — this is opt-in, so adding it to your pipeline does not change any scan you already have wired in today.

MIT licensed.