@sirrlock/mcp 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/README.md ADDED
@@ -0,0 +1,189 @@
1
+ # @sirrlock/mcp — Sirr MCP Server
2
+
3
+ Gives AI assistants like Claude direct access to your [Sirr](https://sirr.dev) secret vault. Push, read, and manage ephemeral secrets without leaving a conversation.
4
+
5
+ ## Demo
6
+
7
+ **Session 1 — store the secret**
8
+
9
+ ```
10
+ ❯ set the BITBUCKET_TOKEN to 123asdzxc
11
+
12
+ ⏺ sirr-mcp - push_secret (MCP)(key: "BITBUCKET_TOKEN", value: "123asdzxc", max_reads: 1)
13
+ ⎿ Stored secret 'BITBUCKET_TOKEN'. Burns after 1 read.
14
+
15
+ ⏺ Stored. Burns after first read.
16
+ ```
17
+
18
+ **Session 2 — Claude retrieves and uses it (the vault burns it)**
19
+
20
+ ```
21
+ ❯ deploy to staging using sirr:BITBUCKET_TOKEN
22
+
23
+ ⏺ sirr-mcp - get_secret (MCP)(key: "BITBUCKET_TOKEN")
24
+ ⎿ 123asdzxc
25
+
26
+ ⏺ Got it. Deploying to staging with the token. Done.
27
+ ```
28
+
29
+ **Session 3 — secret is already gone**
30
+
31
+ ```
32
+ ❯ what is the BITBUCKET_TOKEN?
33
+
34
+ ⏺ sirr-mcp - get_secret (MCP)(key: "BITBUCKET_TOKEN")
35
+ ⎿ Secret 'BITBUCKET_TOKEN' not found, expired, or already burned.
36
+
37
+ ⏺ The secret no longer exists on the server.
38
+ ```
39
+
40
+ The secret existed just long enough to be used once. The vault enforces it server-side (`max_reads=1`). Claude is instructed by the tool description not to memorize or repeat the value. Even if a different agent, session, or attacker asks — there is nothing left to return.
41
+
42
+ ## Install
43
+
44
+ ```bash
45
+ npm install -g @sirrlock/mcp
46
+ ```
47
+
48
+ Or use `npx` without a global install — see the configuration block below.
49
+
50
+ ## Quick start
51
+
52
+ 1. **Start Sirr** — run the Sirr server and note the `SIRR_MASTER_KEY` you set (or the one it printed on first launch).
53
+ 2. **Set your token** — `SIRR_TOKEN` in your MCP config must equal that `SIRR_MASTER_KEY` value exactly.
54
+ 3. **Add to `.mcp.json`** — paste the config block below, substituting your server URL and key.
55
+ 4. **Verify** — run `sirr-mcp --health` to confirm the connection before starting your AI session.
56
+
57
+ ## Configuration
58
+
59
+ Add Sirr to your project's `.mcp.json` or `~/.claude/settings.json`:
60
+
61
+ ```json
62
+ {
63
+ "mcpServers": {
64
+ "sirr": {
65
+ "command": "sirr-mcp",
66
+ "env": {
67
+ "SIRR_SERVER": "http://localhost:39999",
68
+ "SIRR_TOKEN": "your-sirr-master-key"
69
+ }
70
+ }
71
+ }
72
+ }
73
+ ```
74
+
75
+ Using `npx` without a global install:
76
+
77
+ ```json
78
+ {
79
+ "mcpServers": {
80
+ "sirr": {
81
+ "command": "npx",
82
+ "args": ["-y", "@sirrlock/mcp"],
83
+ "env": {
84
+ "SIRR_SERVER": "http://localhost:39999",
85
+ "SIRR_TOKEN": "your-sirr-master-key"
86
+ }
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ > **What is `SIRR_TOKEN`?** It is the value of `SIRR_MASTER_KEY` that you set (or that was generated) when you started the Sirr server. These two values must match exactly — a mismatch is the most common cause of 401 errors. See [sirr.dev/errors#401](https://sirr.dev/errors#401).
93
+
94
+ ### Environment variables
95
+
96
+ | Variable | Default | Description |
97
+ |---|---|---|
98
+ | `SIRR_SERVER` | `http://localhost:39999` | Sirr server URL |
99
+ | `SIRR_TOKEN` | — | Bearer token — must equal `SIRR_MASTER_KEY` on the server |
100
+
101
+ ## CLI flags
102
+
103
+ ```bash
104
+ # Print the installed version and exit
105
+ sirr-mcp --version
106
+
107
+ # Check that the MCP server can reach Sirr and exit
108
+ SIRR_SERVER=http://localhost:39999 SIRR_TOKEN=mykey sirr-mcp --health
109
+ ```
110
+
111
+ `--health` exits with code `0` on success and `1` on failure, making it safe to use in scripts and CI.
112
+
113
+ ## Available tools
114
+
115
+ ### Secrets
116
+
117
+ | Tool | Description |
118
+ |---|---|
119
+ | `get_secret(key)` | Retrieve a secret value (increments read counter; burns if max_reads reached) |
120
+ | `push_secret(key, value, ttl_seconds?, max_reads?)` | Store a secret with optional expiry and read limit |
121
+ | `list_secrets()` | List all active secrets — metadata only, values never returned |
122
+ | `delete_secret(key)` | Burn a secret immediately, regardless of TTL or read count |
123
+ | `prune_secrets()` | Delete all expired secrets in one sweep |
124
+ | `health_check()` | Verify the Sirr server is reachable and healthy |
125
+
126
+ ### Audit
127
+
128
+ | Tool | Description |
129
+ |---|---|
130
+ | `sirr_audit(since?, action?, limit?)` | Query the audit log — secret creates, reads, deletes, and key events |
131
+
132
+ ### Webhooks
133
+
134
+ | Tool | Description |
135
+ |---|---|
136
+ | `sirr_webhook_create(url, events?)` | Register a webhook URL; returns ID and signing secret (shown once) |
137
+ | `sirr_webhook_list()` | List all registered webhooks (signing secrets redacted) |
138
+ | `sirr_webhook_delete(id)` | Remove a webhook by ID |
139
+
140
+ ### API keys
141
+
142
+ | Tool | Description |
143
+ |---|---|
144
+ | `sirr_key_create(label, permissions, prefix?)` | Create a scoped API key; raw key returned once — save it |
145
+ | `sirr_key_list()` | List all scoped API keys (key hashes never returned) |
146
+ | `sirr_key_delete(id)` | Delete an API key by ID |
147
+
148
+ ## Inline secret references
149
+
150
+ You can reference secrets inline in any prompt:
151
+
152
+ ```
153
+ "Use sirr:DATABASE_URL to run a migration"
154
+ "Deploy with sirr:DEPLOY_TOKEN"
155
+ ```
156
+
157
+ The `sirr:KEYNAME` prefix tells Claude to fetch from the vault automatically.
158
+
159
+ ## Security notes
160
+
161
+ - Claude only sees secret **values** when you explicitly ask it to fetch via `get_secret`
162
+ - `list_secrets` returns metadata only — values are never included
163
+ - Set `max_reads=1` on any secret shared for a single AI session
164
+ - The MCP server never logs secret values
165
+ - `SIRR_TOKEN` lives in your MCP config's `env` block — it is never passed as a tool argument or in prompts
166
+ - Use HTTPS (`https://`) when `SIRR_SERVER` points to a remote host — plain HTTP transmits secrets unencrypted
167
+
168
+ ## Troubleshooting
169
+
170
+ | Symptom | Cause | Fix |
171
+ |---|---|---|
172
+ | `Error: Sirr 401` | `SIRR_TOKEN` doesn't match `SIRR_MASTER_KEY` | Verify both values match exactly — no extra spaces or newlines. [sirr.dev/errors#401](https://sirr.dev/errors#401) |
173
+ | `Error: Sirr 402` | Free-tier limit of 100 secrets reached | Delete unused secrets or add a `SIRR_LICENSE_KEY`. [sirr.dev/errors#402](https://sirr.dev/errors#402) |
174
+ | `Error: Sirr 403` | Scoped API key lacks the required permission | Re-create the key with the needed permissions. [sirr.dev/errors#403](https://sirr.dev/errors#403) |
175
+ | `Secret '…' not found` | Secret expired, was burned, or key was mistyped | Re-push the secret if you still need it. [sirr.dev/errors#404](https://sirr.dev/errors#404) |
176
+ | `did not respond within 10s` | Sirr server is unreachable | Check `SIRR_SERVER` URL and confirm Sirr is running (`sirr-mcp --health`). |
177
+ | `[sirr-mcp] Warning: SIRR_TOKEN is not set` | Token missing from MCP config | Add `SIRR_TOKEN` to the `env` block in `.mcp.json`. |
178
+ | MCP server not found by Claude | `sirr-mcp` not on PATH | Install globally (`npm install -g @sirrlock/mcp`) or use the `npx` config variant. |
179
+
180
+ ## Related
181
+
182
+ | Package | Description |
183
+ |---------|-------------|
184
+ | [sirr](https://github.com/sirrlock/sirr) | Rust monorepo: `sirrd` server + `sirr` CLI |
185
+ | [@sirrlock/node](https://github.com/sirrlock/node) | Node.js / TypeScript SDK |
186
+ | [sirr (PyPI)](https://github.com/sirrlock/python) | Python SDK |
187
+ | [Sirr.Client (NuGet)](https://github.com/sirrlock/dotnet) | .NET SDK |
188
+ | [sirr.dev](https://sirr.dev) | Documentation |
189
+ | [secretdrop.app](https://secretdrop.app) | Hosted service + license keys |
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Pure helper functions extracted for testability.
3
+ */
4
+ /**
5
+ * Parse a secret key reference from natural language.
6
+ * "sirr:KEYNAME" → "KEYNAME"
7
+ * "KEYNAME#server" → "KEYNAME"
8
+ * "KEYNAME" → "KEYNAME"
9
+ */
10
+ export declare function parseKeyRef(ref: string): string;
11
+ /**
12
+ * Format a Unix timestamp (seconds) as a human-readable TTL string
13
+ * relative to now. Returns "no expiry" for null, "expired" for past timestamps.
14
+ */
15
+ export declare function formatTtl(expiresAt: number | null): string;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ /**
3
+ * Pure helper functions extracted for testability.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseKeyRef = parseKeyRef;
7
+ exports.formatTtl = formatTtl;
8
+ /**
9
+ * Parse a secret key reference from natural language.
10
+ * "sirr:KEYNAME" → "KEYNAME"
11
+ * "KEYNAME#server" → "KEYNAME"
12
+ * "KEYNAME" → "KEYNAME"
13
+ */
14
+ function parseKeyRef(ref) {
15
+ if (ref.startsWith("sirr:"))
16
+ return ref.slice(5);
17
+ if (ref.includes("#"))
18
+ return ref.split("#")[0];
19
+ return ref.trim();
20
+ }
21
+ /**
22
+ * Format a Unix timestamp (seconds) as a human-readable TTL string
23
+ * relative to now. Returns "no expiry" for null, "expired" for past timestamps.
24
+ */
25
+ function formatTtl(expiresAt) {
26
+ if (expiresAt === null)
27
+ return "no expiry";
28
+ const now = Math.floor(Date.now() / 1000);
29
+ const secs = expiresAt - now;
30
+ if (secs <= 0)
31
+ return "expired";
32
+ if (secs < 60)
33
+ return `${secs}s`;
34
+ if (secs < 3600)
35
+ return `${Math.floor(secs / 60)}m`;
36
+ if (secs < 86400)
37
+ return `${Math.floor(secs / 3600)}h`;
38
+ return `${Math.floor(secs / 86400)}d`;
39
+ }
40
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAQH,kCAIC;AAMD,8BASC;AAzBD;;;;;GAKG;AACH,SAAgB,WAAW,CAAC,GAAW;IACrC,IAAI,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjD,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;IACjD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED;;;GAGG;AACH,SAAgB,SAAS,CAAC,SAAwB;IAChD,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,WAAW,CAAC;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,SAAS,GAAG,GAAG,CAAC;IAC7B,IAAI,IAAI,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAChC,IAAI,IAAI,GAAG,EAAE;QAAE,OAAO,GAAG,IAAI,GAAG,CAAC;IACjC,IAAI,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,CAAC;IACpD,IAAI,IAAI,GAAG,KAAK;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC;IACvD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC;AACxC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const globals_1 = require("@jest/globals");
4
+ const helpers_1 = require("./helpers");
5
+ (0, globals_1.describe)("parseKeyRef", () => {
6
+ (0, globals_1.it)("strips sirr: prefix", () => {
7
+ (0, globals_1.expect)((0, helpers_1.parseKeyRef)("sirr:MY_KEY")).toBe("MY_KEY");
8
+ });
9
+ (0, globals_1.it)("extracts key from hash format", () => {
10
+ (0, globals_1.expect)((0, helpers_1.parseKeyRef)("MY_KEY#some-server")).toBe("MY_KEY");
11
+ });
12
+ (0, globals_1.it)("returns bare key as-is", () => {
13
+ (0, globals_1.expect)((0, helpers_1.parseKeyRef)("MY_KEY")).toBe("MY_KEY");
14
+ });
15
+ (0, globals_1.it)("trims whitespace from bare keys", () => {
16
+ (0, globals_1.expect)((0, helpers_1.parseKeyRef)(" MY_KEY ")).toBe("MY_KEY");
17
+ });
18
+ (0, globals_1.it)("handles sirr: with no key (edge case)", () => {
19
+ (0, globals_1.expect)((0, helpers_1.parseKeyRef)("sirr:")).toBe("");
20
+ });
21
+ (0, globals_1.it)("takes only the part before the first # in hash format", () => {
22
+ (0, globals_1.expect)((0, helpers_1.parseKeyRef)("KEY#a#b")).toBe("KEY");
23
+ });
24
+ });
25
+ (0, globals_1.describe)("formatTtl", () => {
26
+ const realDateNow = Date.now;
27
+ (0, globals_1.beforeEach)(() => {
28
+ // Pin now to a fixed Unix timestamp (seconds = 1_000_000)
29
+ globals_1.jest.spyOn(Date, "now").mockReturnValue(1000000 * 1000);
30
+ });
31
+ (0, globals_1.afterEach)(() => {
32
+ globals_1.jest.restoreAllMocks();
33
+ });
34
+ (0, globals_1.it)("returns 'no expiry' for null", () => {
35
+ (0, globals_1.expect)((0, helpers_1.formatTtl)(null)).toBe("no expiry");
36
+ });
37
+ (0, globals_1.it)("returns 'expired' for past timestamp", () => {
38
+ (0, globals_1.expect)((0, helpers_1.formatTtl)(999999)).toBe("expired");
39
+ });
40
+ (0, globals_1.it)("returns 'expired' for exactly now", () => {
41
+ (0, globals_1.expect)((0, helpers_1.formatTtl)(1000000)).toBe("expired");
42
+ });
43
+ (0, globals_1.it)("formats seconds (< 60s)", () => {
44
+ (0, globals_1.expect)((0, helpers_1.formatTtl)(1000000 + 45)).toBe("45s");
45
+ });
46
+ (0, globals_1.it)("formats minutes (60s – 3599s)", () => {
47
+ (0, globals_1.expect)((0, helpers_1.formatTtl)(1000000 + 120)).toBe("2m");
48
+ (0, globals_1.expect)((0, helpers_1.formatTtl)(1000000 + 3599)).toBe("59m");
49
+ });
50
+ (0, globals_1.it)("formats hours (3600s – 86399s)", () => {
51
+ (0, globals_1.expect)((0, helpers_1.formatTtl)(1000000 + 3600)).toBe("1h");
52
+ (0, globals_1.expect)((0, helpers_1.formatTtl)(1000000 + 7200)).toBe("2h");
53
+ });
54
+ (0, globals_1.it)("formats days (≥ 86400s)", () => {
55
+ (0, globals_1.expect)((0, helpers_1.formatTtl)(1000000 + 86400)).toBe("1d");
56
+ (0, globals_1.expect)((0, helpers_1.formatTtl)(1000000 + 86400 * 7)).toBe("7d");
57
+ });
58
+ });
59
+ //# sourceMappingURL=helpers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.test.js","sourceRoot":"","sources":["../src/helpers.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @sirrlock/mcp — MCP server for Sirr secret vault
4
+ *
5
+ * Exposes Sirr as MCP tools so Claude Code can read/write ephemeral secrets.
6
+ *
7
+ * Configuration (env vars):
8
+ * SIRR_SERVER — Sirr server URL (default: http://localhost:39999)
9
+ * SIRR_TOKEN — Bearer token (SIRR_MASTER_KEY on the server)
10
+ *
11
+ * Install: npm install -g @sirrlock/mcp
12
+ * Configure in .mcp.json:
13
+ * {
14
+ * "mcpServers": {
15
+ * "sirr": {
16
+ * "command": "sirr-mcp",
17
+ * "env": { "SIRR_SERVER": "...", "SIRR_TOKEN": "..." }
18
+ * }
19
+ * }
20
+ * }
21
+ */
22
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,601 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * @sirrlock/mcp — MCP server for Sirr secret vault
5
+ *
6
+ * Exposes Sirr as MCP tools so Claude Code can read/write ephemeral secrets.
7
+ *
8
+ * Configuration (env vars):
9
+ * SIRR_SERVER — Sirr server URL (default: http://localhost:39999)
10
+ * SIRR_TOKEN — Bearer token (SIRR_MASTER_KEY on the server)
11
+ *
12
+ * Install: npm install -g @sirrlock/mcp
13
+ * Configure in .mcp.json:
14
+ * {
15
+ * "mcpServers": {
16
+ * "sirr": {
17
+ * "command": "sirr-mcp",
18
+ * "env": { "SIRR_SERVER": "...", "SIRR_TOKEN": "..." }
19
+ * }
20
+ * }
21
+ * }
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
25
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
26
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
27
+ const package_json_1 = require("../package.json");
28
+ // ── Config ────────────────────────────────────────────────────────────────────
29
+ const SIRR_SERVER = (process.env["SIRR_SERVER"] ?? "http://localhost:39999").replace(/\/$/, "");
30
+ const SIRR_TOKEN = process.env["SIRR_TOKEN"] ?? "";
31
+ // ── Fetch with timeout ────────────────────────────────────────────────────────
32
+ async function fetchWithTimeout(url, options = {}, ms = 10000) {
33
+ const controller = new AbortController();
34
+ const timer = setTimeout(() => controller.abort(), ms);
35
+ try {
36
+ return await fetch(url, { ...options, signal: controller.signal });
37
+ }
38
+ catch (err) {
39
+ if (err instanceof Error) {
40
+ if (err.name === "AbortError") {
41
+ throw new Error(`Sirr server at ${SIRR_SERVER} did not respond within ${ms / 1000}s. Is it running?`);
42
+ }
43
+ // Node fetch throws "fetch failed" for ECONNREFUSED and other network errors
44
+ if (err.message === "fetch failed") {
45
+ throw new Error(`Cannot reach Sirr server at ${SIRR_SERVER}. Is it running?`);
46
+ }
47
+ }
48
+ throw err;
49
+ }
50
+ finally {
51
+ clearTimeout(timer);
52
+ }
53
+ }
54
+ const STATUS_HINTS = {
55
+ 401: "Check that SIRR_TOKEN matches SIRR_MASTER_KEY on the server. See sirr.dev/errors#401",
56
+ 402: "Free tier limit reached. See sirr.dev/errors#402",
57
+ 403: "This API key does not have permission for this operation. See sirr.dev/errors#403",
58
+ 404: "Secret not found, expired, or burned. See sirr.dev/errors#404",
59
+ 500: "Server-side error. See sirr.dev/errors#500",
60
+ };
61
+ function throwSirrError(status, json) {
62
+ const msg = json["error"] ?? "unknown";
63
+ const hint = STATUS_HINTS[status];
64
+ throw new Error(`Sirr ${status}: ${msg}${hint ? `\n → ${hint}` : ""}`);
65
+ }
66
+ async function sirrRequest(method, path, body) {
67
+ const res = await fetchWithTimeout(`${SIRR_SERVER}${path}`, {
68
+ method,
69
+ headers: {
70
+ Authorization: `Bearer ${SIRR_TOKEN}`,
71
+ "Content-Type": "application/json",
72
+ },
73
+ body: body !== undefined ? JSON.stringify(body) : undefined,
74
+ });
75
+ const json = (await res.json());
76
+ if (!res.ok) {
77
+ throwSirrError(res.status, json);
78
+ }
79
+ return json;
80
+ }
81
+ const helpers_1 = require("./helpers");
82
+ // ── Tool definitions ──────────────────────────────────────────────────────────
83
+ const TOOLS = [
84
+ {
85
+ name: "get_secret",
86
+ description: "Retrieve a secret from the Sirr vault by key name. " +
87
+ "The secret's read counter is incremented — if it was set with max_reads=1 it will be deleted after this call. " +
88
+ "Returns null if the secret does not exist, has expired, or has been burned. " +
89
+ "Accepts bare key names, 'sirr:KEYNAME' references, or 'KEYNAME#id' format. " +
90
+ "IMPORTANT: Do not store, log, memorize, or repeat the returned secret value beyond its immediate use. " +
91
+ "Treat it as ephemeral — use it once for its intended purpose and discard it.",
92
+ inputSchema: {
93
+ type: "object",
94
+ properties: {
95
+ key: {
96
+ type: "string",
97
+ description: "Secret key name. Accepts 'sirr:KEYNAME', 'KEYNAME#id', or bare key name.",
98
+ },
99
+ },
100
+ required: ["key"],
101
+ },
102
+ },
103
+ {
104
+ name: "push_secret",
105
+ description: "Store a secret in the Sirr vault. Optionally set a TTL (seconds) and/or a max read limit. " +
106
+ "Use max_reads=1 for one-time credentials that burn after first access. " +
107
+ "Use ttl_seconds for time-expiring secrets.",
108
+ inputSchema: {
109
+ type: "object",
110
+ properties: {
111
+ key: {
112
+ type: "string",
113
+ description: "Key name to store the secret under.",
114
+ },
115
+ value: {
116
+ type: "string",
117
+ description: "Secret value.",
118
+ },
119
+ ttl_seconds: {
120
+ type: "number",
121
+ description: "Optional TTL in seconds. Examples: 3600 (1h), 86400 (1d), 604800 (7d).",
122
+ },
123
+ max_reads: {
124
+ type: "number",
125
+ description: "Optional maximum read count. Set to 1 for a one-time secret.",
126
+ },
127
+ },
128
+ required: ["key", "value"],
129
+ },
130
+ },
131
+ {
132
+ name: "list_secrets",
133
+ description: "List all active secrets in the Sirr vault. Returns metadata only — values are never included. " +
134
+ "Shows key name, expiry time, and read count for each secret.",
135
+ inputSchema: {
136
+ type: "object",
137
+ properties: {},
138
+ },
139
+ },
140
+ {
141
+ name: "delete_secret",
142
+ description: "Immediately delete (burn) a secret from the Sirr vault, regardless of TTL or read count.",
143
+ inputSchema: {
144
+ type: "object",
145
+ properties: {
146
+ key: {
147
+ type: "string",
148
+ description: "Key name to delete.",
149
+ },
150
+ },
151
+ required: ["key"],
152
+ },
153
+ },
154
+ {
155
+ name: "prune_secrets",
156
+ description: "Trigger an immediate sweep of all expired secrets on the server. " +
157
+ "Returns the count of secrets that were deleted.",
158
+ inputSchema: {
159
+ type: "object",
160
+ properties: {},
161
+ },
162
+ },
163
+ {
164
+ name: "health_check",
165
+ description: "Check if the Sirr server is reachable and healthy.",
166
+ inputSchema: {
167
+ type: "object",
168
+ properties: {},
169
+ },
170
+ },
171
+ {
172
+ name: "sirr_audit",
173
+ description: "Query the Sirr audit log. Returns recent events like secret creates, reads, deletes. " +
174
+ "Useful for security monitoring and debugging access patterns.",
175
+ inputSchema: {
176
+ type: "object",
177
+ properties: {
178
+ since: {
179
+ type: "number",
180
+ description: "Only return events after this Unix timestamp.",
181
+ },
182
+ action: {
183
+ type: "string",
184
+ description: "Filter by action type (e.g. secret.create, secret.read, key.create).",
185
+ },
186
+ limit: {
187
+ type: "number",
188
+ description: "Maximum events to return (default: 50).",
189
+ },
190
+ },
191
+ },
192
+ },
193
+ {
194
+ name: "sirr_webhook_create",
195
+ description: "Register a webhook URL to receive Sirr event notifications. " +
196
+ "Returns the webhook ID and signing secret (shown once — save it).",
197
+ inputSchema: {
198
+ type: "object",
199
+ properties: {
200
+ url: {
201
+ type: "string",
202
+ description: "Webhook endpoint URL (must start with http:// or https://).",
203
+ },
204
+ events: {
205
+ type: "array",
206
+ items: { type: "string" },
207
+ description: "Event types to subscribe to (default: all). Examples: secret.created, secret.burned.",
208
+ },
209
+ },
210
+ required: ["url"],
211
+ },
212
+ },
213
+ {
214
+ name: "sirr_webhook_list",
215
+ description: "List all registered webhooks on the Sirr server. Signing secrets are redacted.",
216
+ inputSchema: {
217
+ type: "object",
218
+ properties: {},
219
+ },
220
+ },
221
+ {
222
+ name: "sirr_webhook_delete",
223
+ description: "Remove a webhook registration by its ID.",
224
+ inputSchema: {
225
+ type: "object",
226
+ properties: {
227
+ id: {
228
+ type: "string",
229
+ description: "Webhook ID to delete.",
230
+ },
231
+ },
232
+ required: ["id"],
233
+ },
234
+ },
235
+ {
236
+ name: "sirr_key_create",
237
+ description: "Create a scoped API key with specific permissions. " +
238
+ "The raw key is returned once — save it immediately. " +
239
+ "Permissions: read, write, delete, admin. Optional prefix scoping limits access to secrets matching the prefix.",
240
+ inputSchema: {
241
+ type: "object",
242
+ properties: {
243
+ label: {
244
+ type: "string",
245
+ description: "Human-readable label for the key.",
246
+ },
247
+ permissions: {
248
+ type: "array",
249
+ items: { type: "string" },
250
+ description: "Permissions to grant: read, write, delete, admin.",
251
+ },
252
+ prefix: {
253
+ type: "string",
254
+ description: "Optional prefix scope — key can only access secrets starting with this prefix.",
255
+ },
256
+ },
257
+ required: ["label", "permissions"],
258
+ },
259
+ },
260
+ {
261
+ name: "sirr_key_list",
262
+ description: "List all scoped API keys. Key hashes are never returned.",
263
+ inputSchema: {
264
+ type: "object",
265
+ properties: {},
266
+ },
267
+ },
268
+ {
269
+ name: "sirr_key_delete",
270
+ description: "Delete a scoped API key by its ID.",
271
+ inputSchema: {
272
+ type: "object",
273
+ properties: {
274
+ id: {
275
+ type: "string",
276
+ description: "API key ID to delete.",
277
+ },
278
+ },
279
+ required: ["id"],
280
+ },
281
+ },
282
+ ];
283
+ // ── MCP Server ────────────────────────────────────────────────────────────────
284
+ const server = new index_js_1.Server({ name: "sirr", version: package_json_1.version }, { capabilities: { tools: {} } });
285
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
286
+ tools: TOOLS,
287
+ }));
288
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
289
+ const { name, arguments: args } = request.params;
290
+ try {
291
+ switch (name) {
292
+ case "get_secret": {
293
+ const rawKey = args.key;
294
+ const key = (0, helpers_1.parseKeyRef)(rawKey);
295
+ const res = await fetchWithTimeout(`${SIRR_SERVER}/secrets/${encodeURIComponent(key)}`, { headers: { Authorization: `Bearer ${SIRR_TOKEN}` } });
296
+ if (res.status === 404) {
297
+ return {
298
+ content: [
299
+ {
300
+ type: "text",
301
+ text: `Secret '${key}' not found, expired, or already burned.`,
302
+ },
303
+ ],
304
+ };
305
+ }
306
+ if (!res.ok) {
307
+ const json = (await res.json());
308
+ throwSirrError(res.status, json);
309
+ }
310
+ const data = (await res.json());
311
+ return {
312
+ content: [
313
+ {
314
+ type: "text",
315
+ text: data.value,
316
+ },
317
+ {
318
+ type: "text",
319
+ text: "[Use immediately — do not store, log, or memorize this value.]",
320
+ },
321
+ ],
322
+ };
323
+ }
324
+ case "push_secret": {
325
+ const { key, value: val, ttl_seconds, max_reads } = args;
326
+ await sirrRequest("POST", "/secrets", {
327
+ key,
328
+ value: val,
329
+ ttl_seconds: ttl_seconds ?? null,
330
+ max_reads: max_reads ?? null,
331
+ });
332
+ const parts = [`Stored secret '${key}'.`];
333
+ if (ttl_seconds)
334
+ parts.push(`Expires in ${(0, helpers_1.formatTtl)(Math.floor(Date.now() / 1000) + ttl_seconds)}.`);
335
+ if (max_reads)
336
+ parts.push(`Burns after ${max_reads} read(s).`);
337
+ return {
338
+ content: [{ type: "text", text: parts.join(" ") }],
339
+ };
340
+ }
341
+ case "list_secrets": {
342
+ const data = await sirrRequest("GET", "/secrets");
343
+ if (data.secrets.length === 0) {
344
+ return {
345
+ content: [{ type: "text", text: "No active secrets." }],
346
+ };
347
+ }
348
+ const lines = data.secrets.map((m) => {
349
+ const expiry = (0, helpers_1.formatTtl)(m.expires_at);
350
+ const reads = m.max_reads != null
351
+ ? `${m.read_count}/${m.max_reads} reads`
352
+ : `${m.read_count} reads`;
353
+ return `• ${m.key} — ${expiry} — ${reads}`;
354
+ });
355
+ return {
356
+ content: [
357
+ {
358
+ type: "text",
359
+ text: `${data.secrets.length} active secret(s):\n${lines.join("\n")}`,
360
+ },
361
+ ],
362
+ };
363
+ }
364
+ case "delete_secret": {
365
+ const { key } = args;
366
+ const res = await fetchWithTimeout(`${SIRR_SERVER}/secrets/${encodeURIComponent(key)}`, {
367
+ method: "DELETE",
368
+ headers: { Authorization: `Bearer ${SIRR_TOKEN}` },
369
+ });
370
+ if (res.status === 404) {
371
+ return {
372
+ content: [
373
+ { type: "text", text: `Secret '${key}' not found.` },
374
+ ],
375
+ };
376
+ }
377
+ if (!res.ok) {
378
+ const json = (await res.json());
379
+ throwSirrError(res.status, json);
380
+ }
381
+ return {
382
+ content: [
383
+ {
384
+ type: "text",
385
+ text: `Secret '${key}' deleted.`,
386
+ },
387
+ ],
388
+ };
389
+ }
390
+ case "prune_secrets": {
391
+ const data = await sirrRequest("POST", "/prune");
392
+ return {
393
+ content: [
394
+ {
395
+ type: "text",
396
+ text: `Pruned ${data.pruned} expired secret(s).`,
397
+ },
398
+ ],
399
+ };
400
+ }
401
+ case "health_check": {
402
+ const res = await fetchWithTimeout(`${SIRR_SERVER}/health`);
403
+ if (!res.ok) {
404
+ const json = (await res.json());
405
+ throwSirrError(res.status, json);
406
+ }
407
+ const data = (await res.json());
408
+ return {
409
+ content: [
410
+ {
411
+ type: "text",
412
+ text: `Sirr server status: ${data.status} (${SIRR_SERVER})`,
413
+ },
414
+ ],
415
+ };
416
+ }
417
+ case "sirr_audit": {
418
+ const { since, action, limit } = args;
419
+ const params = new URLSearchParams();
420
+ if (since != null)
421
+ params.set("since", String(since));
422
+ if (action != null)
423
+ params.set("action", action);
424
+ if (limit != null)
425
+ params.set("limit", String(limit));
426
+ const qs = params.toString();
427
+ const data = await sirrRequest("GET", `/audit${qs ? `?${qs}` : ""}`);
428
+ if (data.events.length === 0) {
429
+ return {
430
+ content: [{ type: "text", text: "No audit events found." }],
431
+ };
432
+ }
433
+ const lines = data.events.map((e) => `[${e.timestamp}] ${e.action} key=${e.key ?? "-"} ip=${e.source_ip} ${e.success ? "ok" : "FAIL"}`);
434
+ return {
435
+ content: [
436
+ {
437
+ type: "text",
438
+ text: `${data.events.length} audit event(s):\n${lines.join("\n")}`,
439
+ },
440
+ ],
441
+ };
442
+ }
443
+ case "sirr_webhook_create": {
444
+ const { url, events } = args;
445
+ const body = { url };
446
+ if (events)
447
+ body.events = events;
448
+ const data = await sirrRequest("POST", "/webhooks", body);
449
+ return {
450
+ content: [
451
+ {
452
+ type: "text",
453
+ text: `Webhook registered.\n ID: ${data.id}\n Secret: ${data.secret}\n (Save the secret — it won't be shown again)`,
454
+ },
455
+ ],
456
+ };
457
+ }
458
+ case "sirr_webhook_list": {
459
+ const data = await sirrRequest("GET", "/webhooks");
460
+ if (data.webhooks.length === 0) {
461
+ return {
462
+ content: [{ type: "text", text: "No webhooks registered." }],
463
+ };
464
+ }
465
+ const lines = data.webhooks.map((w) => `• ${w.id} — ${w.url} [${w.events.join(",")}]`);
466
+ return {
467
+ content: [
468
+ {
469
+ type: "text",
470
+ text: `${data.webhooks.length} webhook(s):\n${lines.join("\n")}`,
471
+ },
472
+ ],
473
+ };
474
+ }
475
+ case "sirr_webhook_delete": {
476
+ const { id } = args;
477
+ await sirrRequest("DELETE", `/webhooks/${encodeURIComponent(id)}`);
478
+ return {
479
+ content: [
480
+ { type: "text", text: `Webhook '${id}' deleted.` },
481
+ ],
482
+ };
483
+ }
484
+ case "sirr_key_create": {
485
+ const { label, permissions, prefix } = args;
486
+ const body = { label, permissions };
487
+ if (prefix)
488
+ body.prefix = prefix;
489
+ const data = await sirrRequest("POST", "/keys", body);
490
+ return {
491
+ content: [
492
+ {
493
+ type: "text",
494
+ text: `API key created.\n ID: ${data.id}\n Key: ${data.key}\n Permissions: ${data.permissions.join(", ")}\n Prefix: ${data.prefix ?? "(none)"}\n (Save the key — it won't be shown again)`,
495
+ },
496
+ ],
497
+ };
498
+ }
499
+ case "sirr_key_list": {
500
+ const data = await sirrRequest("GET", "/keys");
501
+ if (data.keys.length === 0) {
502
+ return {
503
+ content: [{ type: "text", text: "No API keys." }],
504
+ };
505
+ }
506
+ const lines = data.keys.map((k) => `• ${k.id} — ${k.label} [${k.permissions.join(",")}] prefix=${k.prefix ?? "*"}`);
507
+ return {
508
+ content: [
509
+ {
510
+ type: "text",
511
+ text: `${data.keys.length} API key(s):\n${lines.join("\n")}`,
512
+ },
513
+ ],
514
+ };
515
+ }
516
+ case "sirr_key_delete": {
517
+ const { id } = args;
518
+ await sirrRequest("DELETE", `/keys/${encodeURIComponent(id)}`);
519
+ return {
520
+ content: [
521
+ { type: "text", text: `API key '${id}' deleted.` },
522
+ ],
523
+ };
524
+ }
525
+ default:
526
+ return {
527
+ content: [{ type: "text", text: `Unknown tool: ${name}` }],
528
+ isError: true,
529
+ };
530
+ }
531
+ }
532
+ catch (err) {
533
+ const message = err instanceof Error ? err.message : String(err);
534
+ return {
535
+ content: [{ type: "text", text: `Error: ${message}` }],
536
+ isError: true,
537
+ };
538
+ }
539
+ });
540
+ // ── Startup warnings ──────────────────────────────────────────────────────────
541
+ function runStartupWarnings() {
542
+ if (!SIRR_TOKEN) {
543
+ process.stderr.write(`[sirr-mcp] Warning: SIRR_TOKEN is not set. See sirr.dev/errors#401\n`);
544
+ }
545
+ try {
546
+ const url = new URL(SIRR_SERVER);
547
+ const isLocal = url.hostname === "localhost" || url.hostname === "127.0.0.1";
548
+ if (url.protocol === "http:" && !isLocal) {
549
+ process.stderr.write(`[sirr-mcp] Warning: SIRR_SERVER is using plain HTTP on a non-local host. Secrets will be transmitted unencrypted.\n`);
550
+ }
551
+ }
552
+ catch {
553
+ // invalid URL — sirrRequest will fail with a clearer message
554
+ }
555
+ }
556
+ // ── Health check (--health flag) ──────────────────────────────────────────────
557
+ async function runHealthCheck() {
558
+ process.stdout.write(`Checking Sirr server at ${SIRR_SERVER}...\n`);
559
+ if (!SIRR_TOKEN) {
560
+ process.stdout.write(`Warning: SIRR_TOKEN is not set — authenticated endpoints will fail.\n`);
561
+ }
562
+ try {
563
+ const res = await fetchWithTimeout(`${SIRR_SERVER}/health`);
564
+ const data = (await res.json());
565
+ process.stdout.write(`Status: ${data.status}\nsirr-mcp is configured correctly.\n`);
566
+ return true;
567
+ }
568
+ catch (err) {
569
+ const msg = err instanceof Error ? err.message : String(err);
570
+ process.stdout.write(`Error: ${msg}\n`);
571
+ return false;
572
+ }
573
+ }
574
+ // ── Main ──────────────────────────────────────────────────────────────────────
575
+ async function main() {
576
+ const transport = new stdio_js_1.StdioServerTransport();
577
+ await server.connect(transport);
578
+ // MCP servers communicate via stdio — no console output here
579
+ }
580
+ // ── Entry point ───────────────────────────────────────────────────────────────
581
+ const cliArgs = process.argv.slice(2);
582
+ if (cliArgs.includes("--version")) {
583
+ process.stdout.write(`sirr-mcp ${package_json_1.version}\n`);
584
+ process.exit(0);
585
+ }
586
+ else if (cliArgs.includes("--health")) {
587
+ runHealthCheck()
588
+ .then((ok) => process.exit(ok ? 0 : 1))
589
+ .catch((e) => {
590
+ process.stderr.write(`sirr-mcp fatal: ${e}\n`);
591
+ process.exit(1);
592
+ });
593
+ }
594
+ else {
595
+ runStartupWarnings();
596
+ main().catch((e) => {
597
+ process.stderr.write(`sirr-mcp fatal: ${e}\n`);
598
+ process.exit(1);
599
+ });
600
+ }
601
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Integration tests — sirrd + sirr-mcp (stdio)
3
+ *
4
+ * Three modes (pick one via env vars):
5
+ *
6
+ * SIRR_SERVER=http://localhost:39999 SIRR_TOKEN=mykey npm run test:integration
7
+ * → Connect to an already-running sirrd. No server is started.
8
+ *
9
+ * SIRRD_BINARY=/path/to/sirrd npm run test:integration
10
+ * → Spawn a local binary. No Docker required.
11
+ *
12
+ * SIRRD_IMAGE=sirrd:test npm run test:integration (default)
13
+ * → Build and run via Docker.
14
+ *
15
+ * Run: npm run test:integration
16
+ */
17
+ export {};
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+ /**
3
+ * Integration tests — sirrd + sirr-mcp (stdio)
4
+ *
5
+ * Three modes (pick one via env vars):
6
+ *
7
+ * SIRR_SERVER=http://localhost:39999 SIRR_TOKEN=mykey npm run test:integration
8
+ * → Connect to an already-running sirrd. No server is started.
9
+ *
10
+ * SIRRD_BINARY=/path/to/sirrd npm run test:integration
11
+ * → Spawn a local binary. No Docker required.
12
+ *
13
+ * SIRRD_IMAGE=sirrd:test npm run test:integration (default)
14
+ * → Build and run via Docker.
15
+ *
16
+ * Run: npm run test:integration
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ const globals_1 = require("@jest/globals");
20
+ const child_process_1 = require("child_process");
21
+ const readline_1 = require("readline");
22
+ // ── Config ────────────────────────────────────────────────────────────────────
23
+ // Spawn a local binary instead of Docker.
24
+ const SIRRD_BINARY = process.env["SIRRD_BINARY"];
25
+ const SIRRD_IMAGE = process.env["SIRRD_IMAGE"] ?? "sirrd:test";
26
+ const SIRR_PORT = 19080;
27
+ // When SIRR_SERVER is set, connect to that existing server — no server is spawned.
28
+ // SIRR_TOKEN must match SIRR_MASTER_KEY on that server.
29
+ const SIRR_TOKEN = process.env["SIRR_TOKEN"] ?? "integration-test-key";
30
+ const SIRR_SERVER = process.env["SIRR_SERVER"] ?? `http://localhost:${SIRR_PORT}`;
31
+ const USE_EXISTING = !!process.env["SIRR_SERVER"];
32
+ const MCP_BIN = `${__dirname}/../dist/index.js`;
33
+ class McpClient {
34
+ constructor(proc) {
35
+ this.proc = proc;
36
+ this.pending = new Map();
37
+ this.nextId = 1;
38
+ this.rl = (0, readline_1.createInterface)({ input: proc.stdout });
39
+ this.rl.on("line", (line) => {
40
+ if (!line.trim())
41
+ return;
42
+ const msg = JSON.parse(line);
43
+ if (msg.id != null) {
44
+ const resolve = this.pending.get(msg.id);
45
+ if (resolve) {
46
+ this.pending.delete(msg.id);
47
+ resolve(msg);
48
+ }
49
+ }
50
+ });
51
+ }
52
+ close() {
53
+ this.rl.close();
54
+ this.proc.kill();
55
+ }
56
+ rpc(method, params) {
57
+ const id = this.nextId++;
58
+ return new Promise((resolve) => {
59
+ this.pending.set(id, resolve);
60
+ this.proc.stdin.write(JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n");
61
+ });
62
+ }
63
+ async initialize() {
64
+ await this.rpc("initialize", {
65
+ protocolVersion: "2024-11-05",
66
+ capabilities: {},
67
+ clientInfo: { name: "integration-test", version: "1" },
68
+ });
69
+ }
70
+ async call(tool, args = {}) {
71
+ const resp = await this.rpc("tools/call", { name: tool, arguments: args });
72
+ if (resp.error)
73
+ throw new Error(`MCP error: ${resp.error.message}`);
74
+ return resp.result?.content?.[0]?.text ?? "";
75
+ }
76
+ }
77
+ // ── Helpers ───────────────────────────────────────────────────────────────────
78
+ async function waitForHealth(url, maxMs = 15000) {
79
+ const deadline = Date.now() + maxMs;
80
+ while (Date.now() < deadline) {
81
+ try {
82
+ const res = await fetch(`${url}/health`);
83
+ if (res.ok)
84
+ return;
85
+ }
86
+ catch { /* not up yet */ }
87
+ await new Promise((r) => setTimeout(r, 250));
88
+ }
89
+ throw new Error(`sirrd at ${url} did not become healthy within ${maxMs}ms`);
90
+ }
91
+ function dockerRun() {
92
+ const result = (0, child_process_1.spawnSync)("docker", [
93
+ "run", "-d", "--rm",
94
+ "-p", `${SIRR_PORT}:39999`,
95
+ "-e", `SIRR_MASTER_KEY=${SIRR_TOKEN}`,
96
+ "-e", "SIRR_DATA_DIR=/tmp",
97
+ "-e", "NO_BANNER=1",
98
+ SIRRD_IMAGE,
99
+ "serve",
100
+ ]);
101
+ if (result.status !== 0) {
102
+ throw new Error(`docker run failed: ${result.stderr.toString()}`);
103
+ }
104
+ return result.stdout.toString().trim();
105
+ }
106
+ function dockerStop(id) {
107
+ (0, child_process_1.spawnSync)("docker", ["stop", id]);
108
+ }
109
+ // ── Fixtures ──────────────────────────────────────────────────────────────────
110
+ let containerId;
111
+ let sirrdProc;
112
+ let client;
113
+ (0, globals_1.beforeAll)(async () => {
114
+ if (USE_EXISTING) {
115
+ // Mode 1: connect to an already-running server — nothing to spawn.
116
+ process.stderr.write(`[integration] connecting to existing server at ${SIRR_SERVER}\n`);
117
+ }
118
+ else if (SIRRD_BINARY) {
119
+ // Mode 2: spawn local binary — no Docker required.
120
+ // Unique data dir per run avoids redb lock conflicts.
121
+ const dataDir = `/tmp/sirrd-test-${Date.now()}`;
122
+ sirrdProc = (0, child_process_1.spawn)(SIRRD_BINARY, ["serve"], {
123
+ env: {
124
+ ...process.env,
125
+ SIRR_MASTER_KEY: SIRR_TOKEN,
126
+ SIRR_DATA_DIR: dataDir,
127
+ SIRR_PORT: String(SIRR_PORT),
128
+ SIRR_HOST: "127.0.0.1",
129
+ NO_BANNER: "1",
130
+ },
131
+ stdio: ["ignore", "ignore", "pipe"],
132
+ });
133
+ sirrdProc.stderr.on("data", (d) => process.stderr.write(`[sirrd] ${d.toString()}`));
134
+ }
135
+ else {
136
+ // Mode 3: Docker.
137
+ containerId = dockerRun();
138
+ }
139
+ await waitForHealth(SIRR_SERVER);
140
+ const mcpProc = (0, child_process_1.spawn)("node", [MCP_BIN], {
141
+ env: { ...process.env, SIRR_SERVER, SIRR_TOKEN },
142
+ stdio: ["pipe", "pipe", "pipe"],
143
+ });
144
+ mcpProc.stderr.on("data", (d) => {
145
+ const msg = d.toString();
146
+ // Suppress expected startup warnings in test output
147
+ if (!msg.includes("[sirr-mcp] Warning"))
148
+ process.stderr.write(msg);
149
+ });
150
+ client = new McpClient(mcpProc);
151
+ await client.initialize();
152
+ }, 30000);
153
+ (0, globals_1.afterAll)(() => {
154
+ client?.close();
155
+ // Only tear down servers we started — leave SIRR_SERVER (USE_EXISTING) server running.
156
+ sirrdProc?.kill();
157
+ if (containerId)
158
+ dockerStop(containerId);
159
+ });
160
+ // ── Tests ─────────────────────────────────────────────────────────────────────
161
+ (0, globals_1.describe)("health_check", () => {
162
+ (0, globals_1.it)("reports server ok", async () => {
163
+ const text = await client.call("health_check");
164
+ (0, globals_1.expect)(text).toContain("ok");
165
+ (0, globals_1.expect)(text).toContain(SIRR_SERVER);
166
+ });
167
+ });
168
+ (0, globals_1.describe)("push_secret / get_secret", () => {
169
+ (0, globals_1.it)("stores and retrieves a bare key", async () => {
170
+ await client.call("push_secret", { key: "INT_BARE", value: "bare-value" });
171
+ const text = await client.call("get_secret", { key: "INT_BARE" });
172
+ (0, globals_1.expect)(text).toBe("bare-value");
173
+ });
174
+ (0, globals_1.it)("retrieves via sirr: prefix", async () => {
175
+ await client.call("push_secret", { key: "INT_PREFIX", value: "prefix-value" });
176
+ const text = await client.call("get_secret", { key: "sirr:INT_PREFIX" });
177
+ (0, globals_1.expect)(text).toBe("prefix-value");
178
+ });
179
+ (0, globals_1.it)("stores with ttl_seconds and reports expiry", async () => {
180
+ const text = await client.call("push_secret", {
181
+ key: "INT_TTL",
182
+ value: "ttl-value",
183
+ ttl_seconds: 3600,
184
+ });
185
+ (0, globals_1.expect)(text).toContain("INT_TTL");
186
+ (0, globals_1.expect)(text).toContain("1h");
187
+ });
188
+ (0, globals_1.it)("stores with max_reads and reports burn limit", async () => {
189
+ const text = await client.call("push_secret", {
190
+ key: "INT_READS",
191
+ value: "reads-value",
192
+ max_reads: 1,
193
+ });
194
+ (0, globals_1.expect)(text).toContain("1 read(s)");
195
+ });
196
+ (0, globals_1.it)("returns not-found message for missing key", async () => {
197
+ const text = await client.call("get_secret", { key: "DOES_NOT_EXIST" });
198
+ (0, globals_1.expect)(text).toContain("not found");
199
+ });
200
+ (0, globals_1.it)("burns a max_reads=1 secret after first read", async () => {
201
+ await client.call("push_secret", { key: "INT_BURN", value: "burn-me", max_reads: 1 });
202
+ await client.call("get_secret", { key: "INT_BURN" }); // consumes it
203
+ const text = await client.call("get_secret", { key: "INT_BURN" });
204
+ (0, globals_1.expect)(text).toContain("not found");
205
+ });
206
+ });
207
+ (0, globals_1.describe)("list_secrets", () => {
208
+ (0, globals_1.it)("lists active secrets", async () => {
209
+ await client.call("push_secret", { key: "INT_LIST", value: "listed" });
210
+ const text = await client.call("list_secrets");
211
+ (0, globals_1.expect)(text).toContain("INT_LIST");
212
+ });
213
+ (0, globals_1.it)("never includes secret values", async () => {
214
+ await client.call("push_secret", { key: "INT_NOVALUE", value: "should-not-appear" });
215
+ const text = await client.call("list_secrets");
216
+ (0, globals_1.expect)(text).not.toContain("should-not-appear");
217
+ });
218
+ });
219
+ (0, globals_1.describe)("delete_secret", () => {
220
+ (0, globals_1.it)("deletes an existing secret", async () => {
221
+ await client.call("push_secret", { key: "INT_DEL", value: "to-delete" });
222
+ const del = await client.call("delete_secret", { key: "INT_DEL" });
223
+ (0, globals_1.expect)(del).toContain("deleted");
224
+ const get = await client.call("get_secret", { key: "INT_DEL" });
225
+ (0, globals_1.expect)(get).toContain("not found");
226
+ });
227
+ (0, globals_1.it)("returns not-found for unknown key", async () => {
228
+ const text = await client.call("delete_secret", { key: "NEVER_EXISTED" });
229
+ (0, globals_1.expect)(text).toContain("not found");
230
+ });
231
+ });
232
+ (0, globals_1.describe)("prune_secrets", () => {
233
+ (0, globals_1.it)("returns a pruned count", async () => {
234
+ const text = await client.call("prune_secrets");
235
+ (0, globals_1.expect)(text).toMatch(/Pruned \d+ expired secret/);
236
+ });
237
+ });
238
+ (0, globals_1.describe)("error handling", () => {
239
+ (0, globals_1.it)("surfaces timeout message when server is unreachable", async () => {
240
+ // Spawn a separate MCP process pointing at a port nothing is listening on
241
+ const badProc = (0, child_process_1.spawn)("node", [MCP_BIN], {
242
+ env: { ...process.env, SIRR_SERVER: "http://127.0.0.1:19099", SIRR_TOKEN },
243
+ stdio: ["pipe", "pipe", "pipe"],
244
+ });
245
+ const badClient = new McpClient(badProc);
246
+ await badClient.initialize();
247
+ const text = await badClient.call("health_check");
248
+ badClient.close();
249
+ // Either a timeout ("did not respond within") or connection refused ("Cannot reach")
250
+ (0, globals_1.expect)(text).toMatch(/did not respond within|Cannot reach/i);
251
+ });
252
+ });
253
+ //# sourceMappingURL=integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.test.js","sourceRoot":"","sources":["../src/integration.test.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAEH,2CAMuB;AACvB,iDAA+D;AAC/D,uCAAsD;AAEtD,iFAAiF;AAEjF,0CAA0C;AAC1C,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AACjD,MAAM,WAAW,GAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,YAAY,CAAC;AAChE,MAAM,SAAS,GAAM,KAAK,CAAC;AAC3B,mFAAmF;AACnF,wDAAwD;AACxD,MAAM,UAAU,GAAK,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,sBAAsB,CAAC;AACzE,MAAM,WAAW,GAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,oBAAoB,SAAS,EAAE,CAAC;AACnF,MAAM,YAAY,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;AAClD,MAAM,OAAO,GAAQ,GAAG,SAAS,mBAAmB,CAAC;AAWrD,MAAM,SAAS;IAKb,YAAoB,IAAkB;QAAlB,SAAI,GAAJ,IAAI,CAAc;QAJ9B,YAAO,GAAG,IAAI,GAAG,EAAwC,CAAC;QAC1D,WAAM,GAAG,CAAC,CAAC;QAIjB,IAAI,CAAC,EAAE,GAAG,IAAA,0BAAe,EAAC,EAAE,KAAK,EAAE,IAAI,CAAC,MAAO,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC1B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE,OAAO;YACzB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAoB,CAAC;YAChD,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;gBACnB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACzC,IAAI,OAAO,EAAE,CAAC;oBACZ,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBAC5B,OAAO,CAAC,GAAG,CAAC,CAAC;gBACf,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;QAChB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC;IAEO,GAAG,CAAC,MAAc,EAAE,MAAe;QACzC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACzB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,KAAM,CAAC,KAAK,CACpB,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAC9D,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE;YAC3B,eAAe,EAAE,YAAY;YAC7B,YAAY,EAAE,EAAE;YAChB,UAAU,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,GAAG,EAAE;SACvD,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,OAAgC,EAAE;QACzD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3E,IAAI,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,cAAc,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;IAC/C,CAAC;CACF;AAED,iFAAiF;AAEjF,KAAK,UAAU,aAAa,CAAC,GAAW,EAAE,KAAK,GAAG,KAAM;IACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;IACpC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;YACzC,IAAI,GAAG,CAAC,EAAE;gBAAE,OAAO;QACrB,CAAC;QAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC;QAC5B,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,YAAY,GAAG,kCAAkC,KAAK,IAAI,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,SAAS;IAChB,MAAM,MAAM,GAAG,IAAA,yBAAS,EAAC,QAAQ,EAAE;QACjC,KAAK,EAAE,IAAI,EAAE,MAAM;QACnB,IAAI,EAAE,GAAG,SAAS,QAAQ;QAC1B,IAAI,EAAE,mBAAmB,UAAU,EAAE;QACrC,IAAI,EAAE,oBAAoB;QAC1B,IAAI,EAAE,aAAa;QACnB,WAAW;QACX,OAAO;KACR,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;AACzC,CAAC;AAED,SAAS,UAAU,CAAC,EAAU;IAC5B,IAAA,yBAAS,EAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,iFAAiF;AAEjF,IAAI,WAA+B,CAAC;AACpC,IAAI,SAAmC,CAAC;AACxC,IAAI,MAAiB,CAAC;AAEtB,IAAA,mBAAS,EAAC,KAAK,IAAI,EAAE;IACnB,IAAI,YAAY,EAAE,CAAC;QACjB,mEAAmE;QACnE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kDAAkD,WAAW,IAAI,CAAC,CAAC;IAC1F,CAAC;SAAM,IAAI,YAAY,EAAE,CAAC;QACxB,mDAAmD;QACnD,sDAAsD;QACtD,MAAM,OAAO,GAAG,mBAAmB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAChD,SAAS,GAAG,IAAA,qBAAK,EAAC,YAAY,EAAE,CAAC,OAAO,CAAC,EAAE;YACzC,GAAG,EAAE;gBACH,GAAG,OAAO,CAAC,GAAG;gBACd,eAAe,EAAE,UAAU;gBAC3B,aAAa,EAAE,OAAO;gBACtB,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC;gBAC5B,SAAS,EAAE,WAAW;gBACtB,SAAS,EAAE,GAAG;aACf;YACD,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC;SACpC,CAAC,CAAC;QACH,SAAS,CAAC,MAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CACzC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAChD,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,kBAAkB;QAClB,WAAW,GAAG,SAAS,EAAE,CAAC;IAC5B,CAAC;IACD,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC;IAEjC,MAAM,OAAO,GAAG,IAAA,qBAAK,EAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE;QACvC,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE;QAChD,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KAChC,CAAC,CAAC;IAEH,OAAO,CAAC,MAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE;QACvC,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;QACzB,oDAAoD;QACpD,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,oBAAoB,CAAC;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,MAAM,GAAG,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;AAC5B,CAAC,EAAE,KAAM,CAAC,CAAC;AAEX,IAAA,kBAAQ,EAAC,GAAG,EAAE;IACZ,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,uFAAuF;IACvF,SAAS,EAAE,IAAI,EAAE,CAAC;IAClB,IAAI,WAAW;QAAE,UAAU,CAAC,WAAW,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEH,iFAAiF;AAEjF,IAAA,kBAAQ,EAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,IAAA,YAAE,EAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACjC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/C,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,kBAAQ,EAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,IAAA,YAAE,EAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;QAC3E,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QAClE,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,IAAA,YAAE,EAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;QAC/E,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,GAAG,EAAE,iBAAiB,EAAE,CAAC,CAAC;QACzE,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,IAAA,YAAE,EAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE;YAC5C,GAAG,EAAE,SAAS;YACd,KAAK,EAAE,WAAW;YAClB,WAAW,EAAE,IAAI;SAClB,CAAC,CAAC;QACH,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAClC,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,IAAA,YAAE,EAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE;YAC5C,GAAG,EAAE,WAAW;YAChB,KAAK,EAAE,aAAa;YACpB,SAAS,EAAE,CAAC;SACb,CAAC,CAAC;QACH,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,IAAA,YAAE,EAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,GAAG,EAAE,gBAAgB,EAAE,CAAC,CAAC;QACxE,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,IAAA,YAAE,EAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;QACtF,MAAM,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,cAAc;QACpE,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QAClE,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,kBAAQ,EAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,IAAA,YAAE,EAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvE,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/C,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,IAAA,YAAE,EAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC5C,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACrF,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/C,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,kBAAQ,EAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,IAAA,YAAE,EAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QACzE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;QACnE,IAAA,gBAAM,EAAC,GAAG,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACjC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;QAChE,IAAA,gBAAM,EAAC,GAAG,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,IAAA,YAAE,EAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,GAAG,EAAE,eAAe,EAAE,CAAC,CAAC;QAC1E,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,kBAAQ,EAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,IAAA,YAAE,EAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QACtC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAChD,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,kBAAQ,EAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,IAAA,YAAE,EAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,0EAA0E;QAC1E,MAAM,OAAO,GAAG,IAAA,qBAAK,EAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE;YACvC,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,wBAAwB,EAAE,UAAU,EAAE;YAC1E,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC;QACzC,MAAM,SAAS,CAAC,UAAU,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAClD,SAAS,CAAC,KAAK,EAAE,CAAC;QAClB,qFAAqF;QACrF,IAAA,gBAAM,EAAC,IAAI,CAAC,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@sirrlock/mcp",
3
+ "version": "0.1.0",
4
+ "description": "Sirr MCP server — lets Claude Code read and write ephemeral secrets",
5
+ "license": "BSL-1.1",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/sirrlock/mcp"
9
+ },
10
+ "main": "dist/index.js",
11
+ "bin": {
12
+ "sirr-mcp": "dist/index.js"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "dev": "tsc --watch",
21
+ "start": "node dist/index.js",
22
+ "test": "jest --testPathIgnorePatterns=integration",
23
+ "test:integration": "jest --testPathPatterns=integration --forceExit",
24
+ "prepublishOnly": "npm run build"
25
+ },
26
+ "engines": {
27
+ "node": ">=18"
28
+ },
29
+ "dependencies": {
30
+ "@modelcontextprotocol/sdk": "^1.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "@jest/globals": "^30.0.0",
34
+ "@types/node": "^20.0.0",
35
+ "jest": "^30.0.0",
36
+ "ts-jest": "^29.0.0",
37
+ "typescript": "^5.4.0"
38
+ },
39
+ "jest": {
40
+ "preset": "ts-jest",
41
+ "testEnvironment": "node"
42
+ },
43
+ "overrides": {
44
+ "minimatch": "^10.2.1",
45
+ "glob": "^11.0.0"
46
+ }
47
+ }