@seekrit/mcp 0.7.0 → 0.8.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 +364 -5
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -45,6 +45,192 @@ z.object({
|
|
|
45
45
|
path: z.string().trim().min(1).max(2048),
|
|
46
46
|
secret: policySecretNameSchema.optional()
|
|
47
47
|
});
|
|
48
|
+
/** One aggregated cell: a dimension tuple and how many times it happened. */
|
|
49
|
+
const activityEntrySchema = z.object({
|
|
50
|
+
host: policyHostSchema,
|
|
51
|
+
method: policyMethodSchema,
|
|
52
|
+
decision: z.enum([
|
|
53
|
+
"allow",
|
|
54
|
+
"no_rule",
|
|
55
|
+
"method_not_allowed",
|
|
56
|
+
"path_not_allowed",
|
|
57
|
+
"secret_not_allowed",
|
|
58
|
+
"unknown_secret",
|
|
59
|
+
"ratchet_withdrawn",
|
|
60
|
+
"policy_unavailable"
|
|
61
|
+
]),
|
|
62
|
+
/**
|
|
63
|
+
* Which published rule decided, when one did. Null for refusals that never
|
|
64
|
+
* reached a rule (`no_rule`, `policy_unavailable`) — the distinction matters to
|
|
65
|
+
* a review, because "rule 3 refused this" and "nothing covered this" call for
|
|
66
|
+
* opposite changes.
|
|
67
|
+
*/
|
|
68
|
+
ruleIndex: z.number().int().min(0).max(255).nullable(),
|
|
69
|
+
count: z.number().int().min(1).max(1e6),
|
|
70
|
+
/**
|
|
71
|
+
* Secret names actually injected, name → count. Only meaningful on `allow`.
|
|
72
|
+
* This is what lets a review say "rule 2 permits three secrets and the agent
|
|
73
|
+
* has only ever used one" — the most useful narrowing there is, and impossible
|
|
74
|
+
* to see from policy alone.
|
|
75
|
+
*/
|
|
76
|
+
secrets: z.record(policySecretNameSchema, z.number().int().min(1)).optional()
|
|
77
|
+
});
|
|
78
|
+
z.object({
|
|
79
|
+
/** Start of the window these counts cover (ISO 8601). */
|
|
80
|
+
windowStart: z.string().trim().min(20).max(40),
|
|
81
|
+
/** Policy version in force while they were collected, for the ledger. */
|
|
82
|
+
policyVersion: z.number().int().min(0).optional(),
|
|
83
|
+
/**
|
|
84
|
+
* Capped so one report cannot be unbounded work. A proxy with more distinct
|
|
85
|
+
* cells than this in a window has a policy far broader than a review can help
|
|
86
|
+
* with, and truncating loudly beats accepting anything.
|
|
87
|
+
*/
|
|
88
|
+
entries: z.array(activityEntrySchema).min(1).max(500)
|
|
89
|
+
});
|
|
90
|
+
/**
|
|
91
|
+
* Twelve hours, matching `[control] max_ttl` in a proxy config. A task is meant
|
|
92
|
+
* to bound one run; something that needs longer wants a policy change, not a
|
|
93
|
+
* longer ticket.
|
|
94
|
+
*/
|
|
95
|
+
const TASK_MAX_TTL_SECONDS = 720 * 60;
|
|
96
|
+
/** An EC P-256 public JWK, for a sender-constraint proof key. */
|
|
97
|
+
const taskProofJwkSchema = z.object({
|
|
98
|
+
kty: z.literal("EC"),
|
|
99
|
+
crv: z.literal("P-256"),
|
|
100
|
+
x: z.string().min(1).max(128),
|
|
101
|
+
y: z.string().min(1).max(128)
|
|
102
|
+
});
|
|
103
|
+
z.object({
|
|
104
|
+
/**
|
|
105
|
+
* The public `skd_…` segment of the minted token. Sent because the API never
|
|
106
|
+
* sees the token at dispatch and still needs a readable handle for the audit
|
|
107
|
+
* row and for a revoke to name — the id half of a credential, without the
|
|
108
|
+
* secret half.
|
|
109
|
+
*/
|
|
110
|
+
taskRef: z.string().trim().regex(/^skd_[0-9A-Za-z]+$/, "taskRef must be the skd_… segment of the minted token"),
|
|
111
|
+
/**
|
|
112
|
+
* SHA-256 (base64url) of the token the dispatcher minted. The token itself
|
|
113
|
+
* never reaches this API on the dispatch path — only on introspection, where
|
|
114
|
+
* it is hashed and discarded.
|
|
115
|
+
*/
|
|
116
|
+
tokenHash: z.string().trim().min(16).max(128),
|
|
117
|
+
/**
|
|
118
|
+
* Secret names this run may use. Omit for "whatever the agent's policy
|
|
119
|
+
* allows" — mirroring `Session.scopes: Option<BTreeSet<String>>` in the proxy,
|
|
120
|
+
* so absent means unnarrowed in both places.
|
|
121
|
+
*/
|
|
122
|
+
scopes: z.array(policySecretNameSchema).max(64).optional(),
|
|
123
|
+
ttlSeconds: z.number().int().min(60).max(TASK_MAX_TTL_SECONDS).optional(),
|
|
124
|
+
/**
|
|
125
|
+
* What this run is for, for the audit row and the operator's task list. Free
|
|
126
|
+
* text, and **not** a security input: never put a secret value in it.
|
|
127
|
+
*/
|
|
128
|
+
label: z.string().trim().max(200).optional(),
|
|
129
|
+
/**
|
|
130
|
+
* Public half of a proof key the presenter holds, recorded as an RFC 7638
|
|
131
|
+
* thumbprint. See `AgentTaskSession.proofThumbprint` for what this does and —
|
|
132
|
+
* importantly — does not yet do.
|
|
133
|
+
*/
|
|
134
|
+
proofJwk: taskProofJwkSchema.optional()
|
|
135
|
+
});
|
|
136
|
+
z.object({
|
|
137
|
+
/** The presented token. In the body, never a URL — it is a credential. */
|
|
138
|
+
token: z.string().trim().min(8).max(512) });
|
|
139
|
+
//#endregion
|
|
140
|
+
//#region ../../packages/core/src/archive.ts
|
|
141
|
+
/**
|
|
142
|
+
* The **break-glass archive** format: one signed JSON file holding everything
|
|
143
|
+
* seekrit stores for an org, in the form seekrit stores it — ciphertext stays
|
|
144
|
+
* ciphertext. Its whole purpose is to be openable on a machine that has never
|
|
145
|
+
* heard of seekrit, so the format is plain JSON, self-describing, and versioned
|
|
146
|
+
* by name (`seekrit-archive/v1`); a breaking change ships a new format string
|
|
147
|
+
* rather than mutating this one, exactly like the `sc1.`/`wd1.` blob prefixes.
|
|
148
|
+
*
|
|
149
|
+
* Three parts:
|
|
150
|
+
* - `manifest` — what this archive is, and a SHA-256 digest per section.
|
|
151
|
+
* - `signature` — Ed25519 over the canonical manifest, or null when the
|
|
152
|
+
* producing deployment has no signing key configured.
|
|
153
|
+
* - `data` — the sections themselves.
|
|
154
|
+
*
|
|
155
|
+
* Integrity fields (`digest`, `signature.value`, `publicKey`, `keyId`) are
|
|
156
|
+
* lowercase hex. Every blob *inside* `data` keeps its native base64url form, so
|
|
157
|
+
* the one encoding rule to remember is "the archive's own bookkeeping is hex,
|
|
158
|
+
* seekrit's blobs are unchanged".
|
|
159
|
+
*
|
|
160
|
+
* See docs/break-glass-export.md for what is deliberately excluded and why.
|
|
161
|
+
*/
|
|
162
|
+
const ARCHIVE_FORMAT = "seekrit-archive/v1";
|
|
163
|
+
const sectionHeaderSchema = z.object({
|
|
164
|
+
name: z.enum([
|
|
165
|
+
"organization",
|
|
166
|
+
"users",
|
|
167
|
+
"memberships",
|
|
168
|
+
"invites",
|
|
169
|
+
"applications",
|
|
170
|
+
"groups",
|
|
171
|
+
"environments",
|
|
172
|
+
"environmentGroups",
|
|
173
|
+
"environmentKeys",
|
|
174
|
+
"secrets",
|
|
175
|
+
"secretVersions",
|
|
176
|
+
"serviceTokens",
|
|
177
|
+
"m2mClients",
|
|
178
|
+
"kmsKeys",
|
|
179
|
+
"kmsKeyVersions",
|
|
180
|
+
"kmsKeyGrants",
|
|
181
|
+
"recoveryConfig",
|
|
182
|
+
"recoveryShares",
|
|
183
|
+
"rotations",
|
|
184
|
+
"syncConnections",
|
|
185
|
+
"syncBindings",
|
|
186
|
+
"leaseTargets",
|
|
187
|
+
"agentIdentities",
|
|
188
|
+
"agentPolicies",
|
|
189
|
+
"auditLog",
|
|
190
|
+
"keyMaterial"
|
|
191
|
+
]),
|
|
192
|
+
count: z.number().int().min(0),
|
|
193
|
+
truncated: z.boolean(),
|
|
194
|
+
digest: z.string().regex(/^sha256:[0-9a-f]{64}$/)
|
|
195
|
+
});
|
|
196
|
+
const manifestSchema = z.object({
|
|
197
|
+
archiveId: z.string().min(1),
|
|
198
|
+
createdAt: z.string().min(1),
|
|
199
|
+
org: z.object({
|
|
200
|
+
id: z.string(),
|
|
201
|
+
slug: z.string(),
|
|
202
|
+
name: z.string()
|
|
203
|
+
}),
|
|
204
|
+
producer: z.object({
|
|
205
|
+
service: z.string(),
|
|
206
|
+
environment: z.string(),
|
|
207
|
+
formatVersion: z.string()
|
|
208
|
+
}),
|
|
209
|
+
requestedBy: z.object({
|
|
210
|
+
actorType: z.string(),
|
|
211
|
+
actorId: z.string(),
|
|
212
|
+
label: z.string().nullable()
|
|
213
|
+
}),
|
|
214
|
+
options: z.object({
|
|
215
|
+
includeVersions: z.boolean(),
|
|
216
|
+
includeAudit: z.boolean(),
|
|
217
|
+
auditLimit: z.number().int().min(0)
|
|
218
|
+
}),
|
|
219
|
+
sections: z.array(sectionHeaderSchema),
|
|
220
|
+
digest: z.string().regex(/^sha256:[0-9a-f]{64}$/)
|
|
221
|
+
});
|
|
222
|
+
const signatureSchema = z.object({
|
|
223
|
+
algorithm: z.literal("ed25519"),
|
|
224
|
+
publicKey: z.string().regex(/^[0-9a-f]{64}$/),
|
|
225
|
+
keyId: z.string().regex(/^[0-9a-f]{16}$/),
|
|
226
|
+
value: z.string().regex(/^[0-9a-f]{128}$/)
|
|
227
|
+
});
|
|
228
|
+
z.object({
|
|
229
|
+
format: z.literal(ARCHIVE_FORMAT),
|
|
230
|
+
manifest: manifestSchema,
|
|
231
|
+
signature: signatureSchema.nullable(),
|
|
232
|
+
data: z.record(z.string(), z.unknown())
|
|
233
|
+
});
|
|
48
234
|
/** All catalog keys as a runtime array (for iteration / zod enums). */
|
|
49
235
|
const ENTITLEMENT_KEYS = Object.keys({
|
|
50
236
|
"feature.kms": {
|
|
@@ -891,6 +1077,13 @@ const inviteRoleSchema = z.enum(["admin", "member"]);
|
|
|
891
1077
|
const principalTypeSchema = z.enum(["user", "service_token"]);
|
|
892
1078
|
/** Org-level capability a service token can hold (never `owner`). */
|
|
893
1079
|
const serviceTokenRoleSchema = z.enum(["admin", "member"]);
|
|
1080
|
+
z.object({
|
|
1081
|
+
/** Include the full append-only ciphertext history of every secret. */
|
|
1082
|
+
includeVersions: z.boolean().optional(),
|
|
1083
|
+
includeAudit: z.boolean().optional(),
|
|
1084
|
+
/** Newest audit rows to keep. Exceeding the server cap is a 400, not a silent trim. */
|
|
1085
|
+
auditLimit: z.number().int().min(0).optional()
|
|
1086
|
+
});
|
|
894
1087
|
z.object({
|
|
895
1088
|
name: nameSchema,
|
|
896
1089
|
slug: slugSchema
|
|
@@ -902,6 +1095,8 @@ z.object({
|
|
|
902
1095
|
z.object({ name: nameSchema });
|
|
903
1096
|
z.object({ name: nameSchema });
|
|
904
1097
|
z.object({ name: nameSchema });
|
|
1098
|
+
z.object({ name: nameSchema });
|
|
1099
|
+
z.object({ name: nameSchema });
|
|
905
1100
|
z.object({ required: z.boolean() });
|
|
906
1101
|
z.object({
|
|
907
1102
|
email: emailSchema,
|
|
@@ -1242,7 +1437,8 @@ z.enum([
|
|
|
1242
1437
|
"netlify",
|
|
1243
1438
|
"bunnyshell",
|
|
1244
1439
|
"github-actions",
|
|
1245
|
-
"gcp-secret-manager"
|
|
1440
|
+
"gcp-secret-manager",
|
|
1441
|
+
"langgraph-platform"
|
|
1246
1442
|
]);
|
|
1247
1443
|
/**
|
|
1248
1444
|
* Vercel account scope. The API token itself is never here — it is wrapped to
|
|
@@ -1507,6 +1703,56 @@ const gcpSecretManagerConnectionConfigSchema = z.object({
|
|
|
1507
1703
|
/** Project ID (`acme-prod`) or project number. */
|
|
1508
1704
|
projectId: gcpProjectSchema
|
|
1509
1705
|
});
|
|
1706
|
+
/**
|
|
1707
|
+
* LangSmith workspace/tenant scope for LangGraph Platform.
|
|
1708
|
+
*
|
|
1709
|
+
* The API key is never here — it is wrapped to the connection's public key and
|
|
1710
|
+
* stored as ciphertext, exactly as Vercel's token is.
|
|
1711
|
+
*
|
|
1712
|
+
* Two optional fields, for two different situations, and setting both is
|
|
1713
|
+
* rejected rather than silently resolved:
|
|
1714
|
+
*
|
|
1715
|
+
* - `region` picks one of {@link LANGGRAPH_PLATFORM_HOSTS}. Omitted means
|
|
1716
|
+
* `us`, which is where an account created at `smith.langchain.com` lives.
|
|
1717
|
+
* - `baseUrl` points the connection at a **self-hosted** LangSmith install,
|
|
1718
|
+
* whose control plane is served from the customer's own host under
|
|
1719
|
+
* `/api-host` rather than from `*.api.host.langchain.com`.
|
|
1720
|
+
*
|
|
1721
|
+
* `tenantId` is the workspace a key was minted in. A workspace-scoped key names
|
|
1722
|
+
* its own tenant and does not need it; an organization-scoped key reaches
|
|
1723
|
+
* several workspaces and gets a bare 403 without it, which is the same trap
|
|
1724
|
+
* Vercel's `teamId` sets — so it is passed through as `X-Tenant-Id` whenever
|
|
1725
|
+
* it is present.
|
|
1726
|
+
*/
|
|
1727
|
+
const langgraphPlatformConnectionConfigSchema = z.object({
|
|
1728
|
+
provider: z.literal("langgraph-platform"),
|
|
1729
|
+
/** Control-plane region. Omit for `us`. Mutually exclusive with `baseUrl`. */
|
|
1730
|
+
region: z.enum([
|
|
1731
|
+
"us",
|
|
1732
|
+
"eu",
|
|
1733
|
+
"apac",
|
|
1734
|
+
"aws-us"
|
|
1735
|
+
]).optional(),
|
|
1736
|
+
/**
|
|
1737
|
+
* Self-hosted LangSmith control-plane root, e.g.
|
|
1738
|
+
* `https://langsmith.acme.com/api-host`. Omit for LangChain's own hosts.
|
|
1739
|
+
* Must be `https:` — this URL carries the API key.
|
|
1740
|
+
*/
|
|
1741
|
+
baseUrl: z.string().trim().max(300).refine((value) => {
|
|
1742
|
+
let parsed;
|
|
1743
|
+
try {
|
|
1744
|
+
parsed = new URL(value);
|
|
1745
|
+
} catch {
|
|
1746
|
+
return false;
|
|
1747
|
+
}
|
|
1748
|
+
return parsed.protocol === "https:" && !parsed.username && !parsed.password;
|
|
1749
|
+
}, "must be an https:// URL — the self-hosted control-plane root, e.g. https://langsmith.acme.com/api-host").optional(),
|
|
1750
|
+
/** LangSmith workspace (tenant) UUID, sent as `X-Tenant-Id`. */
|
|
1751
|
+
tenantId: z.string().trim().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, "must be a LangSmith workspace UUID").optional()
|
|
1752
|
+
}).refine((c) => !(c.baseUrl !== void 0 && c.region !== void 0), {
|
|
1753
|
+
message: "set region for a LangChain-hosted account or baseUrl for a self-hosted one, not both",
|
|
1754
|
+
path: ["baseUrl"]
|
|
1755
|
+
});
|
|
1510
1756
|
const syncConnectionConfigSchema = z.discriminatedUnion("provider", [
|
|
1511
1757
|
vercelConnectionConfigSchema,
|
|
1512
1758
|
cloudflareWorkersConnectionConfigSchema,
|
|
@@ -1523,7 +1769,8 @@ const syncConnectionConfigSchema = z.discriminatedUnion("provider", [
|
|
|
1523
1769
|
netlifyConnectionConfigSchema,
|
|
1524
1770
|
bunnyshellConnectionConfigSchema,
|
|
1525
1771
|
githubActionsConnectionConfigSchema,
|
|
1526
|
-
gcpSecretManagerConnectionConfigSchema
|
|
1772
|
+
gcpSecretManagerConnectionConfigSchema,
|
|
1773
|
+
langgraphPlatformConnectionConfigSchema
|
|
1527
1774
|
]);
|
|
1528
1775
|
const vercelDestinationSchema = z.object({
|
|
1529
1776
|
provider: z.literal("vercel"),
|
|
@@ -2210,6 +2457,27 @@ const gcpSecretManagerDestinationSchema = z.object({
|
|
|
2210
2457
|
message: "a customer-managed key covers one location — use automatic replication, or a single location",
|
|
2211
2458
|
path: ["kmsKeyName"]
|
|
2212
2459
|
});
|
|
2460
|
+
/**
|
|
2461
|
+
* One LangGraph Platform (Agent Server) **deployment**, addressed by its id.
|
|
2462
|
+
*
|
|
2463
|
+
* A deployment is the whole unit here: its secrets are a property of the
|
|
2464
|
+
* deployment, delivered to the agent container as environment variables, and
|
|
2465
|
+
* there is nothing finer to point at — no per-revision or per-graph scope, and
|
|
2466
|
+
* no equivalent of Vercel's `production`/`preview` split. A deployment that
|
|
2467
|
+
* needs different values is a different deployment, so it is a different
|
|
2468
|
+
* binding.
|
|
2469
|
+
*
|
|
2470
|
+
* Validated as a UUID because `PATCH /v2/deployments/{deployment_id}` declares
|
|
2471
|
+
* the path parameter as one: a name or a URL slug in the slot fails validation
|
|
2472
|
+
* at the control plane hours later inside an alarm, with nobody watching. It is
|
|
2473
|
+
* the `id` from `GET /v2/deployments`, and the UUID in the deployment's
|
|
2474
|
+
* dashboard URL.
|
|
2475
|
+
*/
|
|
2476
|
+
const langgraphPlatformDestinationSchema = z.object({
|
|
2477
|
+
provider: z.literal("langgraph-platform"),
|
|
2478
|
+
/** Deployment UUID, from the dashboard URL or `GET /v2/deployments`. */
|
|
2479
|
+
deploymentId: z.string().trim().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, "must be a LangGraph Platform deployment UUID")
|
|
2480
|
+
});
|
|
2213
2481
|
const syncDestinationSchema = z.discriminatedUnion("provider", [
|
|
2214
2482
|
vercelDestinationSchema,
|
|
2215
2483
|
cloudflareWorkersDestinationSchema,
|
|
@@ -2226,7 +2494,8 @@ const syncDestinationSchema = z.discriminatedUnion("provider", [
|
|
|
2226
2494
|
netlifyDestinationSchema,
|
|
2227
2495
|
bunnyshellDestinationSchema,
|
|
2228
2496
|
githubActionsDestinationSchema,
|
|
2229
|
-
gcpSecretManagerDestinationSchema
|
|
2497
|
+
gcpSecretManagerDestinationSchema,
|
|
2498
|
+
langgraphPlatformDestinationSchema
|
|
2230
2499
|
]);
|
|
2231
2500
|
/**
|
|
2232
2501
|
* How seekrit secret names become destination key names. Applied in order:
|
|
@@ -2956,7 +3225,7 @@ function isServiceToken(value) {
|
|
|
2956
3225
|
}
|
|
2957
3226
|
//#endregion
|
|
2958
3227
|
//#region ../cli/package.json
|
|
2959
|
-
var version$1 = "0.
|
|
3228
|
+
var version$1 = "0.46.0";
|
|
2960
3229
|
const PROJECT_FILE = "seekrit.json";
|
|
2961
3230
|
function globalConfigPath() {
|
|
2962
3231
|
return join(process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"), "seekrit", "config.json");
|
|
@@ -3157,6 +3426,10 @@ var SeekritClient = class {
|
|
|
3157
3426
|
getEnv(orgId, envId) {
|
|
3158
3427
|
return this.request("GET", `/v1/orgs/${orgId}/envs/${envId}`);
|
|
3159
3428
|
}
|
|
3429
|
+
/** Rename an environment (display name only — the slug is immutable). */
|
|
3430
|
+
updateEnv(orgId, envId, input) {
|
|
3431
|
+
return this.request("PATCH", `/v1/orgs/${orgId}/envs/${envId}`, input);
|
|
3432
|
+
}
|
|
3160
3433
|
deleteEnv(orgId, envId) {
|
|
3161
3434
|
return this.request("DELETE", `/v1/orgs/${orgId}/envs/${envId}`);
|
|
3162
3435
|
}
|
|
@@ -3310,6 +3583,10 @@ var SeekritClient = class {
|
|
|
3310
3583
|
createToken(orgId, input) {
|
|
3311
3584
|
return this.request("POST", `/v1/orgs/${orgId}/tokens`, input);
|
|
3312
3585
|
}
|
|
3586
|
+
/** Rename a token. Role, environment binding, and expiry are immutable. */
|
|
3587
|
+
updateToken(orgId, tokenId, input) {
|
|
3588
|
+
return this.request("PATCH", `/v1/orgs/${orgId}/tokens/${tokenId}`, input);
|
|
3589
|
+
}
|
|
3313
3590
|
revokeToken(orgId, tokenId) {
|
|
3314
3591
|
return this.request("DELETE", `/v1/orgs/${orgId}/tokens/${tokenId}`);
|
|
3315
3592
|
}
|
|
@@ -3365,6 +3642,77 @@ var SeekritClient = class {
|
|
|
3365
3642
|
getMyPolicySigner(orgId) {
|
|
3366
3643
|
return this.request("GET", `/v1/orgs/${orgId}/agents/signers/me`);
|
|
3367
3644
|
}
|
|
3645
|
+
/**
|
|
3646
|
+
* The bundle a proxy would see — `GET /v1/agents/:ref/policy`, the same route
|
|
3647
|
+
* `seekrit-proxy` polls, resolved by agent id or slug.
|
|
3648
|
+
*
|
|
3649
|
+
* Not org-scoped, because the caller is not: a proxy holds a service token that
|
|
3650
|
+
* knows an agent slug and nothing about org ids. Reachable with any service
|
|
3651
|
+
* token bound to the agent's org (or a user session), which is what lets
|
|
3652
|
+
* `seekrit proxy init` generate a config on the machine that holds the proxy's
|
|
3653
|
+
* own token rather than requiring an admin credential there.
|
|
3654
|
+
*
|
|
3655
|
+
* The `bundle` is signed and opaque to the API. Anything that *acts* on it must
|
|
3656
|
+
* verify the signature against locally pinned signers; decoding it for display
|
|
3657
|
+
* or to name a route is not acting on it.
|
|
3658
|
+
*/
|
|
3659
|
+
getAgentPolicyBundle(agentRef) {
|
|
3660
|
+
return this.request("GET", `/v1/agents/${encodeURIComponent(agentRef)}/policy`);
|
|
3661
|
+
}
|
|
3662
|
+
/**
|
|
3663
|
+
* Dispatch a task for one agent run.
|
|
3664
|
+
*
|
|
3665
|
+
* The caller mints the token (`createAgentTaskToken` in `@seekrit/crypto`) and
|
|
3666
|
+
* sends only its hash plus the public `skd_…` segment, so no presentable
|
|
3667
|
+
* credential ever reaches this API — the same shape as service-token and CLI
|
|
3668
|
+
* session creation. `scopes` may only narrow what the agent's published policy
|
|
3669
|
+
* already permits; a name outside it is refused rather than dropped.
|
|
3670
|
+
*
|
|
3671
|
+
* Not org-scoped, because an orchestrator is not: it knows an agent slug.
|
|
3672
|
+
*/
|
|
3673
|
+
dispatchAgentTask(agentRef, input) {
|
|
3674
|
+
return this.request("POST", `/v1/agents/${encodeURIComponent(agentRef)}/dispatch`, input);
|
|
3675
|
+
}
|
|
3676
|
+
/**
|
|
3677
|
+
* Exchange a presented token for the session it authorizes — what an
|
|
3678
|
+
* enforcement point calls once per task and caches until expiry.
|
|
3679
|
+
*
|
|
3680
|
+
* A POST because the token is a credential and must not land in a URL or an
|
|
3681
|
+
* access log. Fails closed and says which way: revoked, expired, or a disabled
|
|
3682
|
+
* identity are three different answers.
|
|
3683
|
+
*/
|
|
3684
|
+
introspectAgentTask(token) {
|
|
3685
|
+
return this.request("POST", "/v1/tasks/introspect", { token });
|
|
3686
|
+
}
|
|
3687
|
+
/** End a run's authority now. Idempotent. */
|
|
3688
|
+
revokeAgentTask(taskId) {
|
|
3689
|
+
return this.request("POST", `/v1/tasks/${taskId}/revoke`);
|
|
3690
|
+
}
|
|
3691
|
+
getAgentTask(taskId) {
|
|
3692
|
+
return this.request("GET", `/v1/tasks/${taskId}`);
|
|
3693
|
+
}
|
|
3694
|
+
/** Runs dispatched for one identity, newest first (admin). */
|
|
3695
|
+
listAgentTasks(orgId, agentId) {
|
|
3696
|
+
return this.request("GET", `/v1/orgs/${orgId}/agents/${agentId}/tasks`);
|
|
3697
|
+
}
|
|
3698
|
+
/**
|
|
3699
|
+
* Report aggregate decisions. Called by an enforcement point, not a person.
|
|
3700
|
+
*
|
|
3701
|
+
* Counts only — hosts, methods, secret *names*, decisions, and rule indices.
|
|
3702
|
+
* Never a request path: see the module comment in `agent-activity.ts` for why
|
|
3703
|
+
* that line is drawn where it is.
|
|
3704
|
+
*/
|
|
3705
|
+
reportAgentActivity(agentRef, input) {
|
|
3706
|
+
return this.request("POST", `/v1/agents/${encodeURIComponent(agentRef)}/activity`, input);
|
|
3707
|
+
}
|
|
3708
|
+
/**
|
|
3709
|
+
* What an agent actually did, collapsed onto its dimensions — the evidence a
|
|
3710
|
+
* grant review reasons over. The proposals themselves are computed client-side
|
|
3711
|
+
* (`reviewPolicy` in `@seekrit/core`), so the API never opines on policy.
|
|
3712
|
+
*/
|
|
3713
|
+
getAgentActivity(orgId, agentId, days = 14) {
|
|
3714
|
+
return this.request("GET", `/v1/orgs/${orgId}/agents/${agentId}/activity?days=${encodeURIComponent(String(days))}`);
|
|
3715
|
+
}
|
|
3368
3716
|
/** Keys the caller can see: all org keys for admins, granted keys otherwise. */
|
|
3369
3717
|
listKmsKeys(orgId) {
|
|
3370
3718
|
return this.request("GET", `/v1/orgs/${orgId}/kms/keys`);
|
|
@@ -3517,6 +3865,17 @@ var SeekritClient = class {
|
|
|
3517
3865
|
const qs = params.size > 0 ? `?${params}` : "";
|
|
3518
3866
|
return this.request("GET", `/v1/orgs/${orgId}/audit${qs}`);
|
|
3519
3867
|
}
|
|
3868
|
+
/**
|
|
3869
|
+
* Export the org as one signed archive: every row seekrit holds for it, with
|
|
3870
|
+
* ciphertext still ciphertext (docs/break-glass-export.md).
|
|
3871
|
+
*
|
|
3872
|
+
* The archive comes back inline rather than as a job handle, and it can be
|
|
3873
|
+
* megabytes — buffer it to a file rather than holding several copies. Requires
|
|
3874
|
+
* admin; deliberately not entitlement-gated.
|
|
3875
|
+
*/
|
|
3876
|
+
exportArchive(orgId, input = {}) {
|
|
3877
|
+
return this.request("POST", `/v1/orgs/${orgId}/export`, input);
|
|
3878
|
+
}
|
|
3520
3879
|
getLogSink(orgId) {
|
|
3521
3880
|
return this.request("GET", `/v1/orgs/${orgId}/log-sink`);
|
|
3522
3881
|
}
|
|
@@ -5145,7 +5504,7 @@ async function runMcpServer(options = {}) {
|
|
|
5145
5504
|
* `seekrit mcp`. tsdown bundles the shared server source in at build time, so the
|
|
5146
5505
|
* published package is self-contained and needs no `@seekrit/cli` install.
|
|
5147
5506
|
*/
|
|
5148
|
-
runMcpServer({ version: "0.
|
|
5507
|
+
runMcpServer({ version: "0.8.0" }).catch((err) => {
|
|
5149
5508
|
const message = err instanceof Error ? err.message : String(err);
|
|
5150
5509
|
process.stderr.write(`seekrit-mcp: fatal: ${message}\n`);
|
|
5151
5510
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seekrit/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "npx-able MCP server for seekrit — let Claude Code and other MCP clients provision, manage, and inject end-to-end encrypted secrets.",
|
|
5
5
|
"mcpName": "dev.seekrit/mcp",
|
|
6
6
|
"type": "module",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@types/node": "^26.1.0",
|
|
25
25
|
"tsdown": "^0.22.3",
|
|
26
26
|
"vitest": "^4.1.9",
|
|
27
|
-
"@seekrit/cli": "0.
|
|
27
|
+
"@seekrit/cli": "0.46.0"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"build": "tsdown",
|