policylayer 0.1.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.
- package/dist/index.js +6 -0
- package/package.json +38 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{Command as D}from"commander";import{readFileSync as $}from"fs";import{existsSync as v,readFileSync as j}from"fs";import{join as p}from"path";import{homedir as a}from"os";import{parse as h}from"smol-toml";function x(r){return[{path:p(r,".mcp.json"),source:".mcp.json (project)",type:"json-mcp"},{path:p(r,".cursor/mcp.json"),source:".cursor/mcp.json (project)",type:"json-mcp"},{path:p(r,".vscode/settings.json"),source:"VS Code (project)",type:"json-vscode"},{path:p(r,".codex/config.toml"),source:".codex/config.toml (project)",type:"toml-codex"},{path:p(a(),".claude.json"),source:"~/.claude.json (user)",type:"json-mcp"},{path:p(a(),"Library/Application Support/Claude/claude_desktop_config.json"),source:"Claude Desktop (user)",type:"json-mcp"},{path:p(a(),".codeium/windsurf/mcp_config.json"),source:"Windsurf (user)",type:"json-mcp"},{path:p(a(),".codex/config.toml"),source:"~/.codex/config.toml (user)",type:"toml-codex"}]}function R(r){return JSON.parse(r).mcpServers||{}}function w(r){let e=JSON.parse(r);return e.mcp?e.mcp.servers||{}:null}function C(r){return h(r).mcp_servers||{}}function u(r){let e=[],o=x(r);for(let{path:n,source:t,type:s}of o)if(v(n))try{let i=j(n,"utf-8"),c=null;switch(s){case"json-mcp":c=R(i);break;case"json-vscode":c=w(i);break;case"toml-codex":c=C(i);break}if(c===null)continue;e.push({source:t,path:n,servers:Object.keys(c),raw:{mcpServers:c}})}catch{}return e}var k=[/^sk-/,/^ghp_/,/^gho_/,/^ghu_/,/^ghs_/,/^glpat-/,/^xoxb-/,/^xoxp-/,/^Bearer\s/,/^pk_/,/^sk_live_/,/^sk_test_/,/^ict_/,/^[a-z]{2,6}_[a-f0-9]{16,}$/i,/^[a-f0-9]{32,}$/i],E=[/\/Users\//,/\/home\//,/\\Users\\/,/^[A-Z]:\\/,/^\//];function b(r){return k.some(e=>e.test(r))}function M(r){return E.some(e=>e.test(r))}function _(r){return!!(r.startsWith("@")&&r.includes("/")||/^[a-z][\w.-]*$/.test(r))}function g(r){let e={};for(let[o,n]of Object.entries(r)){let t={};if(n.command){let s=n.command.split(/[/\\]/);t.command=s[s.length-1]||n.command}Array.isArray(n.args)&&(t.args=n.args.filter(s=>typeof s!="string"||b(s)||M(s)||s.startsWith("-")?!1:_(s))),e[o]=t}return e}async function l(r,e){let o=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mcpServers:r})}),n=await o.json();if(!o.ok)throw new Error(n.error||`Scan failed with status ${o.status}`);return n}function m(r){let e=[];for(let o of r)e.push(` Found ${o.servers.length} server${o.servers.length===1?"":"s"} in ${o.source}`);return e.join(`
|
|
3
|
+
`)}function d(r){return["No MCP configuration found.","","Checked:",...r.map(o=>` - ${o}`),"","Use --config <path> to specify a config file,","or try the web scanner at https://policylayer.com/scan"].join(`
|
|
4
|
+
`)}function y(r){return[""," Report ready:",` ${r}`,""].join(`
|
|
5
|
+
`)}function S(r){return["","Dry run -- would send:",JSON.stringify(r,null,2)].join(`
|
|
6
|
+
`)}var f=new D;f.name("policylayer").description("Scan your MCP config for security risks").version("0.1.0");f.command("scan").description("Scan MCP server configuration").option("--config <path>","Path to MCP config file").option("--dry-run","Show what would be sent without sending").option("--api-url <url>","Scan API URL","https://policylayer.com/api/scan").action(async r=>{try{let e={};if(r.config)try{let t=JSON.parse($(r.config,"utf-8")),s=t.mcpServers||t;e=s;let i=Object.keys(s).length;console.log(` Found ${i} server${i===1?"":"s"} in ${r.config}`)}catch(t){console.error(`Error reading config: ${r.config}`),console.error(t.message),process.exit(1)}else{let t=u(process.cwd());t.length===0&&(console.log(d([".mcp.json (project root)","~/.claude.json (user-level)","Claude Desktop config (macOS)",".cursor/mcp.json (project)",".vscode/settings.json (project)","Windsurf config (user)",".codex/config.toml (project)","~/.codex/config.toml (user)"])),process.exit(0)),console.log(m(t));let s=t.filter(c=>c.source.includes("user")),i=t.filter(c=>!c.source.includes("user"));for(let c of s)Object.assign(e,c.raw.mcpServers);for(let c of i)Object.assign(e,c.raw.mcpServers)}let o=g(e);if(r.dryRun){console.log(S({mcpServers:o}));return}console.log(" Sending server identifiers only -- secrets stripped");let n=await l(o,r.apiUrl);console.log(y(n.url))}catch(e){console.error(`Error: ${e.message}`),process.exit(1)}});f.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "policylayer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Scan your MCP config for security risks",
|
|
6
|
+
"bin": {
|
|
7
|
+
"policylayer": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=20"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup",
|
|
17
|
+
"test": "vitest run",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"mcp",
|
|
22
|
+
"security",
|
|
23
|
+
"scan",
|
|
24
|
+
"claude",
|
|
25
|
+
"ai-agents"
|
|
26
|
+
],
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"commander": "^14.0.3",
|
|
30
|
+
"smol-toml": "^1.6.1"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^25.5.0",
|
|
34
|
+
"tsup": "^8.5.1",
|
|
35
|
+
"typescript": "^5.9.3",
|
|
36
|
+
"vitest": "^4.1.0"
|
|
37
|
+
}
|
|
38
|
+
}
|