argus-aml 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/README.md +68 -2
- package/bin/init.js +200 -0
- package/package.json +13 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Daertho
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,69 @@
|
|
|
1
|
-
#
|
|
1
|
+
# argus-aml
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Add the [Argus API](https://daertho.com/founders/)'s compliance tools to your AI agent: sanctions and PEP screening,
|
|
4
|
+
adverse media, face checks, e-signatures and financial-crime typologies, as MCP tools.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npx argus-aml init
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
It starts you on a sandbox key. Sandbox results are invented, cost nothing, and need no account.
|
|
11
|
+
|
|
12
|
+
## What this script does
|
|
13
|
+
|
|
14
|
+
Exactly this, and nothing else:
|
|
15
|
+
|
|
16
|
+
1. **One request** to `POST https://argus.unbackoffice.com/v1/founder/sandbox-key` to create a sandbox key.
|
|
17
|
+
No account, no email, no personal data. Skipped when you pass `--key` or a key is already saved.
|
|
18
|
+
2. **Writes one file**, `~/.config/argus/key`, with mode 600 so only you can read it.
|
|
19
|
+
3. **Adds the Argus server** to the agents it finds on this machine, and only those:
|
|
20
|
+
|
|
21
|
+
| Agent | How it's detected | What is touched |
|
|
22
|
+
| ---------- | -------------------------- | --------------------------------------------------- |
|
|
23
|
+
| Claude Code | `claude` CLI on your PATH | `claude mcp add --scope user argus …` |
|
|
24
|
+
| Cursor | `~/.cursor/` exists | `argus` entry in `~/.cursor/mcp.json` |
|
|
25
|
+
| Codex | `~/.codex/` exists | `[mcp_servers.argus]` in `~/.codex/config.toml` |
|
|
26
|
+
| Windsurf | `~/.codeium/windsurf/` | `argus` entry in `~/.codeium/windsurf/mcp_config.json` |
|
|
27
|
+
| Gemini CLI | `~/.gemini/` exists | `argus` entry in `~/.gemini/settings.json` |
|
|
28
|
+
|
|
29
|
+
Only the `argus` entry is written; the rest of each file is left as it was. A config file that isn't valid JSON is
|
|
30
|
+
left alone and reported.
|
|
31
|
+
|
|
32
|
+
It sends nothing else anywhere and collects no telemetry. The whole script is [`bin/init.js`](bin/init.js), about
|
|
33
|
+
200 lines with no dependencies. To see what it would do on your machine before it does it:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx argus-aml init --print
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Going live
|
|
40
|
+
|
|
41
|
+
When Daertho issues your live key, run the same command with it:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx argus-aml init --key ak_your_live_key
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Same URL, same tools. The only change is that results stop carrying `"sandbox": true`. Running `init` again later
|
|
48
|
+
keeps the saved key: it never swaps a live key for a sandbox one.
|
|
49
|
+
|
|
50
|
+
## Any other MCP client
|
|
51
|
+
|
|
52
|
+
Point it at `https://argus.unbackoffice.com/mcp` and send your key in the `X-API-Key` header. The Claude desktop app
|
|
53
|
+
adds remote servers through its own Connectors settings rather than a config file, so this script can't set it up;
|
|
54
|
+
use the URL there.
|
|
55
|
+
|
|
56
|
+
## Plain HTTP
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
curl https://argus.unbackoffice.com/v1/screen \
|
|
60
|
+
-H "X-API-Key: $(cat ~/.config/argus/key)" \
|
|
61
|
+
-H "Content-Type: application/json" \
|
|
62
|
+
-d '{"name": "Sandbox Sanctioned"}'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
API reference: https://argus.unbackoffice.com/developers/reference
|
|
66
|
+
|
|
67
|
+
## Licence
|
|
68
|
+
|
|
69
|
+
The installer in this package is MIT licensed. The Argus API it connects to is a Daertho service under its own terms.
|
package/bin/init.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
// npx argus-aml init: get a sandbox key (or take --key) and add the Argus MCP server to the agents on this machine.
|
|
4
|
+
//
|
|
5
|
+
// Everything this script does, and nothing else:
|
|
6
|
+
// 1. POST https://argus.unbackoffice.com/v1/founder/sandbox-key, only when no key is given or already saved
|
|
7
|
+
// 2. write ~/.config/argus/key, readable only by you
|
|
8
|
+
// 3. add the Argus server to the agents it finds on this machine:
|
|
9
|
+
// Claude Code `claude mcp add` (needs the Claude Code CLI on PATH)
|
|
10
|
+
// Cursor ~/.cursor/mcp.json
|
|
11
|
+
// Codex ~/.codex/config.toml
|
|
12
|
+
// Windsurf ~/.codeium/windsurf/mcp_config.json
|
|
13
|
+
// Gemini CLI ~/.gemini/settings.json
|
|
14
|
+
// It sends nothing else anywhere and collects no telemetry. `--print` shows these steps without doing them.
|
|
15
|
+
const fs = require("fs");
|
|
16
|
+
const os = require("os");
|
|
17
|
+
const path = require("path");
|
|
18
|
+
const { spawnSync } = require("child_process");
|
|
19
|
+
|
|
20
|
+
const API = (process.env.ARGUS_API_URL || "https://argus.unbackoffice.com").replace(/\/$/, "");
|
|
21
|
+
const MCP = API + "/mcp";
|
|
22
|
+
const HOME = os.homedir();
|
|
23
|
+
const KEY_FILE = path.join(HOME, ".config", "argus", "key");
|
|
24
|
+
const ok = (s) => console.log("✓ " + s);
|
|
25
|
+
const fail = (s) => { console.error("✗ " + s); process.exit(1); };
|
|
26
|
+
const mask = (key) => (key ? key.slice(0, 6) + "…" : "");
|
|
27
|
+
|
|
28
|
+
function argValue(args, name) {
|
|
29
|
+
const i = args.indexOf(name);
|
|
30
|
+
if (i < 0) return "";
|
|
31
|
+
if (!args[i + 1]) fail(name + " needs a value");
|
|
32
|
+
return args[i + 1];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function sandboxKey() {
|
|
36
|
+
let r;
|
|
37
|
+
try {
|
|
38
|
+
r = await fetch(API + "/v1/founder/sandbox-key", { method: "POST" });
|
|
39
|
+
} catch (e) {
|
|
40
|
+
fail("Couldn't reach " + API + ". Check your connection and try again.");
|
|
41
|
+
}
|
|
42
|
+
const d = await r.json().catch(() => ({}));
|
|
43
|
+
if (!r.ok || !d.api_key) fail(d.detail || "Couldn't create a sandbox key. Try again shortly.");
|
|
44
|
+
return d.api_key;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function savedKey() {
|
|
48
|
+
try {
|
|
49
|
+
return fs.readFileSync(KEY_FILE, "utf8").trim();
|
|
50
|
+
} catch (e) {
|
|
51
|
+
return "";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function saveKey(key) {
|
|
56
|
+
fs.mkdirSync(path.dirname(KEY_FILE), { recursive: true, mode: 0o700 });
|
|
57
|
+
fs.writeFileSync(KEY_FILE, key + "\n", { mode: 0o600 });
|
|
58
|
+
fs.chmodSync(KEY_FILE, 0o600);
|
|
59
|
+
return KEY_FILE;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function onPath(cmd) {
|
|
63
|
+
return spawnSync(process.platform === "win32" ? "where" : "which", [cmd], { stdio: "ignore" }).status === 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Replace or add the "argus" entry under mcpServers in a JSON config file. A file that isn't valid JSON is left alone.
|
|
67
|
+
function writeJsonEntry(file, entry) {
|
|
68
|
+
let cfg = {};
|
|
69
|
+
if (fs.existsSync(file)) {
|
|
70
|
+
try {
|
|
71
|
+
cfg = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
72
|
+
} catch (e) {
|
|
73
|
+
console.error("✗ Left " + file + " alone: it isn't valid JSON.");
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
cfg.mcpServers = { ...(cfg.mcpServers || {}), argus: entry };
|
|
78
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
79
|
+
fs.writeFileSync(file, JSON.stringify(cfg, null, 2) + "\n", { mode: 0o600 });
|
|
80
|
+
fs.chmodSync(file, 0o600);
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Replace or add the [mcp_servers.argus] table in a TOML file, without touching anything else in it.
|
|
85
|
+
function writeTomlTable(file, lines) {
|
|
86
|
+
let text = fs.existsSync(file) ? fs.readFileSync(file, "utf8") : "";
|
|
87
|
+
const block = "[mcp_servers.argus]\n" + lines.join("\n") + "\n";
|
|
88
|
+
const re = /^\[mcp_servers\.argus\]\n(?:(?!\[)[^\n]*\n?)*/m;
|
|
89
|
+
if (re.test(text)) text = text.replace(re, (m, at) => block + (at + m.length < text.length ? "\n" : ""));
|
|
90
|
+
else text = text.replace(/\s*$/, "") + (text.trim() ? "\n\n" : "") + block;
|
|
91
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
92
|
+
fs.writeFileSync(file, text, { mode: 0o600 });
|
|
93
|
+
fs.chmodSync(file, 0o600);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Each agent: how it's detected, what gets touched, and how to add the server.
|
|
98
|
+
const AGENTS = [
|
|
99
|
+
{
|
|
100
|
+
name: "Claude Code",
|
|
101
|
+
found: () => onPath("claude"),
|
|
102
|
+
touches: "`claude mcp add --scope user argus` (your Claude Code user config)",
|
|
103
|
+
add(key) {
|
|
104
|
+
spawnSync("claude", ["mcp", "remove", "argus", "--scope", "user"], { stdio: "ignore" });
|
|
105
|
+
const r = spawnSync("claude", ["mcp", "add", "--transport", "http", "--scope", "user", "argus", MCP,
|
|
106
|
+
"--header", "X-API-Key: " + key], { encoding: "utf8" });
|
|
107
|
+
if (r.status !== 0) {
|
|
108
|
+
console.error("✗ Couldn't add Argus to Claude Code: " + ((r.stderr || "").split(key).join("***").trim() || "unknown error"));
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: "Cursor",
|
|
116
|
+
file: path.join(HOME, ".cursor", "mcp.json"),
|
|
117
|
+
found() { return fs.existsSync(path.dirname(this.file)); },
|
|
118
|
+
add(key) { return writeJsonEntry(this.file, { url: MCP, headers: { "X-API-Key": key } }); },
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: "Codex",
|
|
122
|
+
file: path.join(HOME, ".codex", "config.toml"),
|
|
123
|
+
found() { return fs.existsSync(path.dirname(this.file)); },
|
|
124
|
+
add(key) {
|
|
125
|
+
return writeTomlTable(this.file, ['url = "' + MCP + '"', 'http_headers = { "X-API-Key" = "' + key + '" }']);
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
name: "Windsurf",
|
|
130
|
+
file: path.join(HOME, ".codeium", "windsurf", "mcp_config.json"),
|
|
131
|
+
found() { return fs.existsSync(path.dirname(this.file)); },
|
|
132
|
+
add(key) { return writeJsonEntry(this.file, { serverUrl: MCP, headers: { "X-API-Key": key } }); },
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: "Gemini CLI",
|
|
136
|
+
file: path.join(HOME, ".gemini", "settings.json"),
|
|
137
|
+
found() { return fs.existsSync(path.dirname(this.file)); },
|
|
138
|
+
add(key) { return writeJsonEntry(this.file, { httpUrl: MCP, headers: { "X-API-Key": key } }); },
|
|
139
|
+
},
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
function manualInstructions(file) {
|
|
143
|
+
console.log("\nAdd this to any MCP client:");
|
|
144
|
+
console.log(" URL: " + MCP);
|
|
145
|
+
console.log(" Header: X-API-Key: " + (file ? "(the key in " + file + ")" : "your key"));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function printPlan(given) {
|
|
149
|
+
console.log("argus-aml init would do this, and nothing else:\n");
|
|
150
|
+
if (given) console.log(" 1. Use the key you gave (" + mask(given) + "); no request is made to create one");
|
|
151
|
+
else console.log(" 1. POST " + API + "/v1/founder/sandbox-key to create a sandbox key (no account, no personal data)");
|
|
152
|
+
console.log(" 2. Write " + KEY_FILE + " (mode 600: readable only by you)");
|
|
153
|
+
console.log(" 3. Add the server " + MCP + " with header X-API-Key to the agents found on this machine:");
|
|
154
|
+
let any = false;
|
|
155
|
+
for (const a of AGENTS) {
|
|
156
|
+
const here = a.found();
|
|
157
|
+
any = any || here;
|
|
158
|
+
console.log(" " + (here ? "found " : "not found") + " " + a.name + " → " + (a.touches || a.file));
|
|
159
|
+
}
|
|
160
|
+
if (!any) console.log(" (none found: it would print the URL and header for you to add by hand)");
|
|
161
|
+
console.log("\nNothing else is sent or stored. Run without --print to do it.");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function main() {
|
|
165
|
+
const args = process.argv.slice(2);
|
|
166
|
+
if (args[0] !== "init") {
|
|
167
|
+
console.log("Usage: npx argus-aml init [--key ak_...] [--print]");
|
|
168
|
+
console.log(" --key use a key you already have (your live key, after Daertho issues one)");
|
|
169
|
+
console.log(" --print show what init would do on this machine without doing it");
|
|
170
|
+
process.exit(args.length && !["-h", "--help"].includes(args[0]) ? 1 : 0);
|
|
171
|
+
}
|
|
172
|
+
// a key saved by an earlier run is kept: running init again must never swap a live key for a sandbox one
|
|
173
|
+
const given = argValue(args, "--key") || process.env.ARGUS_API_KEY || savedKey();
|
|
174
|
+
if (args.includes("--print")) return printPlan(given);
|
|
175
|
+
|
|
176
|
+
const key = given || (await sandboxKey());
|
|
177
|
+
ok(given ? "Using your API key (" + mask(key) + ")" : "Sandbox key created");
|
|
178
|
+
const file = saveKey(key);
|
|
179
|
+
ok("Key saved to " + file);
|
|
180
|
+
|
|
181
|
+
const added = [];
|
|
182
|
+
for (const a of AGENTS) if (a.found() && a.add(key)) added.push(a.name);
|
|
183
|
+
if (added.length) {
|
|
184
|
+
ok("Argus tools added to " + added.join(", "));
|
|
185
|
+
manualInstructions(file);
|
|
186
|
+
console.log("\nRestart your agent, then try:");
|
|
187
|
+
} else {
|
|
188
|
+
console.log("\nNo supported agent found on this machine.");
|
|
189
|
+
if (!onPath("claude")) {
|
|
190
|
+
console.log(" The Claude Code CLI isn't on your PATH (the Claude desktop app alone can't be set up by this script).");
|
|
191
|
+
console.log(" Install it with: npm install -g @anthropic-ai/claude-code then run this again.");
|
|
192
|
+
}
|
|
193
|
+
manualInstructions(file);
|
|
194
|
+
console.log("\nThen try:");
|
|
195
|
+
}
|
|
196
|
+
console.log(" Screen Sandbox Sanctioned and tell me what happens next.");
|
|
197
|
+
if (!given) console.log("\nSandbox results are invented. Ask for a live key at " + API + "/developers");
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
main().catch((e) => fail("Something went wrong: " + (e && e.message ? e.message : e)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "argus-aml",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Add the Argus API's compliance tools (sanctions and PEP screening, adverse media, face checks, e-signatures, typologies) to your AI agent.",
|
|
5
|
+
"keywords": ["aml", "sanctions", "pep", "kyc", "compliance", "mcp", "claude-code", "cursor", "codex", "argus", "daertho"],
|
|
6
|
+
"homepage": "https://daertho.com/founders/",
|
|
7
|
+
"repository": { "type": "git", "url": "git+https://github.com/sect0rial/argus-aml.git" },
|
|
8
|
+
"bugs": { "url": "https://github.com/sect0rial/argus-aml/issues", "email": "1@daertho.com" },
|
|
9
|
+
"author": "Daertho <1@daertho.com> (https://daertho.com)",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"bin": { "argus-aml": "bin/init.js" },
|
|
12
|
+
"files": ["bin", "README.md", "LICENSE"],
|
|
13
|
+
"engines": { "node": ">=18" },
|
|
14
|
+
"publishConfig": { "access": "public", "provenance": true }
|
|
15
|
+
}
|