@nodatachat/mcp 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +71 -4
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -31,12 +31,16 @@
31
31
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
32
32
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
33
33
  import { z } from "zod";
34
+ // Our deepest content scanner, shipped as its own zero-dep, Node-native npm
35
+ // package. nodata_scan_folder wires to it directly (not a reimplementation) so
36
+ // the "SEE what's sensitive" step runs INSIDE this one command, entirely local.
37
+ import { runFolderScan, silentLogger, formatFolderScan } from "@nodatachat/folder-scan";
34
38
  import { homedir, hostname } from "node:os";
35
- import { join } from "node:path";
39
+ import { join, resolve, basename } from "node:path";
36
40
  import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from "node:fs";
37
41
  import { spawn } from "node:child_process";
38
42
  import { generateKeyPairSync, createPrivateKey, sign, randomBytes } from "node:crypto";
39
- const VERSION = "0.8.0";
43
+ const VERSION = "0.9.0";
40
44
  // ---------------------------------------------------------------------------
41
45
  // Local credential store — "register once, autoload forever"
42
46
  // ---------------------------------------------------------------------------
@@ -614,8 +618,8 @@ const SETUP_STEPS = "TURN THE DATA TOOLS ON — 3 steps, about a minute, once:\n
614
618
  // Admin mode: connected. Frame the whole product as the developer's real journey
615
619
  // — SEE -> CHOOSE -> PROVE — each step a plain-language ask mapped to a tool.
616
620
  const START_OUTCOMES_ADMIN = "NOW — TURN YOUR DATA INTO AN AGENT THAT CAN'T LEAK, in 3 asks (just say them in plain words):\n\n" +
617
- " 1. SEE what's sensitive open https://www.nodatacapsule.com/ai-folder\n" +
618
- " -> pick a folder; it shows what an AI could read. Nothing uploads.\n\n" +
621
+ " 1. SEE what's sensitive run nodata_scan_folder — scans a local folder right here, nothing\n" +
622
+ " uploads (or open https://www.nodatacapsule.com/ai-folder in a browser).\n\n" +
619
623
  " 2. CHOOSE what to release say \"let <agent> read name + plan on <table>, hide the rest\"\n" +
620
624
  " -> I run nodata_register_table + nodata_grant; the agent gets a token.\n\n" +
621
625
  " 3. PROVE & control the agent now reads ONLY those columns — the rest never decrypt.\n" +
@@ -805,6 +809,65 @@ function registerConnectTool(server, baseUrl) {
805
809
  });
806
810
  }
807
811
  // ---------------------------------------------------------------------------
812
+ // nodata_scan_folder — SEE what's sensitive, locally, before you govern it
813
+ // ---------------------------------------------------------------------------
814
+ // The journey's first step ("SEE") brought inside the one command. It runs our
815
+ // deep content scanner (the published @nodatachat/folder-scan — the same detection
816
+ // engine the NoData agent uses: 24 secret patterns + checksum-validated PII, and
817
+ // PDF/Office text extraction) ENTIRELY on this machine — nothing uploads — over a
818
+ // folder the developer names, then points at register_table + grant for what it
819
+ // surfaces. Local compute needs no credential, so this is offered even in setup
820
+ // mode: scan before you even sign up.
821
+ function formatScanReport(r) {
822
+ // The neutral report comes from the scanner package (shared with its CLI);
823
+ // the MCP only adds the governance bridge — turn what the scan surfaced into
824
+ // the next step of the same journey.
825
+ const base = formatFolderScan(r);
826
+ if (r.error)
827
+ return base;
828
+ return (base +
829
+ "\n\nGOVERN what it surfaced — same journey, inside this command:\n" +
830
+ " · CHOOSE what an agent may read: nodata_register_table then nodata_grant (denied columns never decrypt)\n" +
831
+ " · PROVE every access afterwards: nodata_evidence\n" +
832
+ "\nWant a standalone deep scan any time? npx @nodatachat/folder-scan (this same engine).");
833
+ }
834
+ function registerScanFolderTool(server) {
835
+ server.registerTool("nodata_scan_folder", {
836
+ description: "SEE what's sensitive before you govern it. Scans a LOCAL folder for hardcoded secrets and unencrypted PII (checksum-validated — Israeli ID / Luhn credit-card / IBAN) with NoData's deep content scanner, reading PDFs and Office files too, ENTIRELY on this machine — nothing uploads, no credential needed. Returns the findings by file and severity plus the first fix, then points at nodata_register_table + nodata_grant to govern what it found. If the user asks to scan / audit / check a folder or repo for sensitive data, secrets, or exposure, call this.",
837
+ inputSchema: {
838
+ path: z
839
+ .string()
840
+ .optional()
841
+ .describe("Folder to scan (absolute or relative). Default: the directory the server runs in."),
842
+ },
843
+ }, async ({ path: scanPath }) => {
844
+ const dir = (scanPath ?? ".").trim() || ".";
845
+ const absDir = resolve(dir);
846
+ if (!existsSync(absDir)) {
847
+ return {
848
+ content: [{ type: "text", text: `No folder found at: ${absDir}\nPass an existing path, e.g. nodata_scan_folder path: "."` }],
849
+ };
850
+ }
851
+ try {
852
+ // Deep scanner: async, takes an injected logger. silentLogger keeps the
853
+ // MCP's stdout (JSON-RPC) clean; the scan never writes to stdout itself.
854
+ const report = await runFolderScan({
855
+ target_id: "mcp",
856
+ target_label: basename(absDir),
857
+ target_path: absDir,
858
+ log: silentLogger,
859
+ });
860
+ return { content: [{ type: "text", text: formatScanReport(report) }] };
861
+ }
862
+ catch (e) {
863
+ return {
864
+ content: [{ type: "text", text: `Scan failed: ${e instanceof Error ? e.message : String(e)}` }],
865
+ isError: true,
866
+ };
867
+ }
868
+ });
869
+ }
870
+ // ---------------------------------------------------------------------------
808
871
  // Server setup
809
872
  // ---------------------------------------------------------------------------
810
873
  async function main() {
@@ -823,6 +886,10 @@ async function main() {
823
886
  if (grantToken)
824
887
  registerAgentTool(server, baseUrl, grantToken);
825
888
  registerGetStarted(server, mode);
889
+ // The local exposure scan needs no credential — offer it wherever the owner is
890
+ // driving (setup, before signup, or admin), just not to a scoped agent.
891
+ if (mode !== "agent")
892
+ registerScanFolderTool(server);
826
893
  if (mode === "setup") {
827
894
  registerConnectTool(server, baseUrl);
828
895
  console.error("nodata-mcp: no credential given — running in setup mode (data tools disabled).\n" +
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nodatachat/mcp",
3
- "version": "0.8.0",
4
- "description": "NoData MCP Server — govern data AND code for AI agents: decide (may I?) + retrieve (authorized context) + read + secret-blind invoke + blind code advise/patch (fix code without exposure), plus admin governance/encrypt/decrypt/deliver",
3
+ "version": "0.9.0",
4
+ "description": "NoData MCP Server — scan a folder for exposure (locally, nothing uploads) + govern data AND code for AI agents: decide (may I?) + retrieve (authorized context) + read + secret-blind invoke + blind code advise/patch (fix code without exposure), plus admin governance/encrypt/decrypt/deliver",
5
5
  "bin": {
6
6
  "nodata-mcp": "dist/index.js"
7
7
  },
@@ -13,6 +13,7 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "@modelcontextprotocol/sdk": "^1.29.0",
16
+ "@nodatachat/folder-scan": "^1.0.0",
16
17
  "zod": "^4.0.0"
17
18
  },
18
19
  "devDependencies": {