@agentlogin/mcp 0.0.0-stage → 0.2.0-beta.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/dist/config.js ADDED
@@ -0,0 +1,105 @@
1
+ import { closeSync, constants, fstatSync, openSync, readFileSync } from 'node:fs';
2
+ import { isAbsolute } from 'node:path';
3
+ import { parseHandle } from 'agentlogin';
4
+ import { z } from 'zod';
5
+ export const identifier = z.string().regex(/^[a-z][a-z0-9_-]{0,63}$/);
6
+ const text = z.string().min(1).max(256).refine((s) => !/[\x00-\x1f\x7f]/.test(s));
7
+ const path = z.string().max(2048).refine((s) => s.startsWith('/') && !s.startsWith('//') && !/[\\#\x00-\x20]/.test(s), 'Use an absolute path without a fragment');
8
+ const pointer = z.string().max(256).regex(/^(?:\/(?:[^~\/]|~[01])*)+$/);
9
+ const operation = z.object({
10
+ description: text,
11
+ method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']),
12
+ path,
13
+ inputFields: z.array(identifier).max(32).default([]),
14
+ queryFields: z.array(identifier).max(32).refine((fields) => new Set(fields).size === fields.length, 'Query fields must be unique').optional(),
15
+ output: z.record(identifier, pointer).default({}),
16
+ }).strict();
17
+ export const ConfigSchema = z.object({
18
+ version: z.literal(1),
19
+ stateDirectory: z.string().refine(isAbsolute, 'Use an absolute state directory'),
20
+ developmentLoopback: z.boolean().default(false),
21
+ signInTimeoutSeconds: z.number().int().min(10).max(600).default(180),
22
+ identities: z.record(identifier, z.object({
23
+ handle: z.string().refine((s) => parseHandle(s)?.handle === s, 'Use a canonical Agent Handle'),
24
+ issuer: z.string().optional(),
25
+ ownerPortal: z.string().optional(),
26
+ ownerApprovalPath: z.string().max(2048).refine((s) => s.startsWith('/') && !s.startsWith('//') && !/[\\?#\x00-\x20]/.test(s) && s.split('{transaction_id}').length === 2 && !/[{}]/.test(s.replace('{transaction_id}', '')), 'Use one {transaction_id} placeholder in an absolute path').optional(),
27
+ enrollmentEndpoint: z.string().optional(),
28
+ enrollmentCredentialEnv: z.string().regex(/^[A-Z][A-Z0-9_]{0,127}$/).optional(),
29
+ }).strict()).refine((v) => Object.keys(v).length > 0 && Object.keys(v).length <= 32),
30
+ applications: z.record(identifier, z.object({
31
+ name: text,
32
+ origin: z.string(),
33
+ loginPath: path,
34
+ sessionCheck: z.object({ path, handlePointer: pointer, issuerPointer: pointer, subjectPointer: pointer }).strict(),
35
+ logoutPath: path.optional(),
36
+ operations: z.record(identifier, operation).default({}),
37
+ }).strict()).refine((v) => Object.keys(v).length <= 64),
38
+ catalogFiles: z.array(z.string().refine(isAbsolute)).max(8).default([]),
39
+ }).strict();
40
+ export function checkedUrl(value, developmentLoopback = false) {
41
+ const url = new URL(value);
42
+ const local = ['127.0.0.1', '[::1]', 'localhost'].includes(url.hostname);
43
+ if (url.username || url.password || url.hash || (url.protocol !== 'https:' && !(developmentLoopback && local && url.protocol === 'http:')))
44
+ throw new Error('Invalid configured URL');
45
+ return url;
46
+ }
47
+ export function parseConfig(value) {
48
+ const config = ConfigSchema.parse(value);
49
+ for (const identity of Object.values(config.identities)) {
50
+ if (identity.ownerApprovalPath && !identity.ownerPortal)
51
+ throw new Error('An Owner approval path requires an Owner portal');
52
+ for (const value of [identity.issuer, identity.ownerPortal, identity.enrollmentEndpoint]) {
53
+ if (value) {
54
+ const url = checkedUrl(value, config.developmentLoopback);
55
+ if (url.search)
56
+ throw new Error('Identity URLs cannot contain query parameters');
57
+ }
58
+ }
59
+ }
60
+ for (const app of Object.values(config.applications)) {
61
+ const origin = checkedUrl(app.origin, config.developmentLoopback);
62
+ if (app.origin !== origin.origin)
63
+ throw new Error('Application origin must be a canonical origin');
64
+ for (const p of [app.loginPath, app.sessionCheck.path, app.logoutPath, ...Object.values(app.operations).map((op) => op.path)]) {
65
+ if (p && checkedUrl(new URL(p, origin).href, config.developmentLoopback).origin !== app.origin)
66
+ throw new Error('Application paths must remain on their configured origin');
67
+ }
68
+ for (const op of Object.values(app.operations)) {
69
+ if (op.method === 'GET' && op.inputFields.length)
70
+ throw new Error('GET operations do not accept a body');
71
+ if (op.method !== 'GET' && op.queryFields !== undefined)
72
+ throw new Error('Only GET operations accept query fields');
73
+ const fixedQuery = new URL(op.path, origin).searchParams;
74
+ if (op.queryFields?.some((field) => fixedQuery.has(field)))
75
+ throw new Error('Query fields cannot replace configured query parameters');
76
+ if (Object.keys(op.output).some(sensitiveName) || Object.values(op.output).some((p) => p.split('/').some(sensitiveName)))
77
+ throw new Error('Credentials cannot be selected as operation output');
78
+ }
79
+ }
80
+ return config;
81
+ }
82
+ export const sensitiveName = (name) => /(?:token|secret|password|authorization|cookie|assertion|challenge|private.?jwk|private.?key|redirect.?url|continue.?url)/i.test(name);
83
+ /** Open first and inspect the descriptor, so replacement with a symbolic link cannot race validation. */
84
+ export function readPrivateConfig(file) {
85
+ const fd = openSync(file, constants.O_RDONLY | constants.O_NOFOLLOW);
86
+ try {
87
+ const st = fstatSync(fd);
88
+ if (!st.isFile() || st.size > 128 * 1024 || (typeof process.getuid === 'function' && (st.uid !== process.getuid() || (st.mode & 0o077) !== 0)))
89
+ throw new Error('Configuration must be a regular file owned by you, mode 0600, at most 128 KiB');
90
+ return parseConfig(JSON.parse(readFileSync(fd, 'utf8')));
91
+ }
92
+ finally {
93
+ closeSync(fd);
94
+ }
95
+ }
96
+ export function atPointer(value, pointer) {
97
+ let current = value;
98
+ for (const part of pointer.slice(1).split('/').map((p) => p.replace(/~1/g, '/').replace(/~0/g, '~'))) {
99
+ if (current === null || typeof current !== 'object' || !Object.hasOwn(current, part))
100
+ return undefined;
101
+ current = current[part];
102
+ }
103
+ return current;
104
+ }
105
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { type Config } from './config.js';
2
+ type Progress = {
3
+ identity: string;
4
+ status: 'not_started' | 'starting' | 'awaiting_owner' | 'proving' | 'active' | 'denied' | 'expired' | 'failed';
5
+ polling: boolean;
6
+ resumable: boolean;
7
+ approvalUrl?: string;
8
+ expiresAt?: number;
9
+ error?: string;
10
+ };
11
+ export interface EnrollmentRuntimeOptions {
12
+ /** Clock and scheduler injection for deterministic deadline tests. */
13
+ now?: () => number;
14
+ sleep?: (milliseconds: number) => Promise<void>;
15
+ }
16
+ /** Optional provider enrollment broker. The broker authorizes a public key; proof of possession remains Core 7.2. */
17
+ export declare class EnrollmentRuntime {
18
+ private readonly config;
19
+ private readonly env;
20
+ private readonly running;
21
+ private readonly now;
22
+ private readonly sleep;
23
+ constructor(config: Config, env?: NodeJS.ProcessEnv, options?: EnrollmentRuntimeOptions);
24
+ private identity;
25
+ private filename;
26
+ private saved;
27
+ private approvalUrl;
28
+ status(identityId: string): Progress;
29
+ start(identityId: string): Progress;
30
+ private json;
31
+ private perform;
32
+ private pause;
33
+ }
34
+ export {};
@@ -0,0 +1,218 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { join } from 'node:path';
3
+ import { AgentLogin, FileKeystore, safeFetch } from 'agentlogin';
4
+ import { SignJWT, importJWK } from 'jose';
5
+ import { z } from 'zod';
6
+ import { checkedUrl } from './config.js';
7
+ import { readState, writeState } from './private-state.js';
8
+ import { safeError, ToolError } from './runtime.js';
9
+ const recordSchema = z.object({
10
+ requestId: z.string().regex(/^[A-Za-z0-9_-]{16,128}$/), token: z.string().min(16).max(4096), approvalUrl: z.string(), expiresAt: z.number().positive(),
11
+ kid: z.string(), handle: z.string(), issuer: z.string(), endpoint: z.string(),
12
+ outcome: z.enum(['active', 'denied', 'expired']).optional(),
13
+ }).strict();
14
+ /** Optional provider enrollment broker. The broker authorizes a public key; proof of possession remains Core 7.2. */
15
+ export class EnrollmentRuntime {
16
+ config;
17
+ env;
18
+ running = new Map();
19
+ now;
20
+ sleep;
21
+ constructor(config, env = process.env, options = {}) {
22
+ this.config = config;
23
+ this.env = env;
24
+ this.now = options.now ?? Date.now;
25
+ this.sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
26
+ }
27
+ identity(identityId) {
28
+ const identity = Object.hasOwn(this.config.identities, identityId) ? this.config.identities[identityId] : undefined;
29
+ if (!identity?.enrollmentEndpoint)
30
+ throw new ToolError('enrollment_unavailable', 'This identity has no configured enrollment broker. Use the provider enrollment setup.');
31
+ return identity;
32
+ }
33
+ filename(identityId) {
34
+ // Bind the durable request to the configured identity name too: editing its handle, issuer or
35
+ // broker must not silently orphan the request and create another key under that name.
36
+ return join(this.config.stateDirectory, 'enrollments', `${createHash('sha256').update(identityId).digest('hex')}.json`);
37
+ }
38
+ saved(identityId, identity, issuer = identity.issuer) {
39
+ const endpoint = checkedUrl(identity.enrollmentEndpoint, this.config.developmentLoopback);
40
+ let saved = readState(this.filename(identityId));
41
+ // Read pre-durable-status records without deleting or replacing their keys. The next explicit
42
+ // enrollment run writes the new stable name; a status read remains read-only.
43
+ if (saved === undefined && issuer)
44
+ saved = readState(join(this.config.stateDirectory, 'enrollments', `${createHash('sha256').update(JSON.stringify([identity.handle, issuer, endpoint.href])).digest('hex')}.json`));
45
+ if (saved === undefined)
46
+ return undefined;
47
+ const record = recordSchema.parse(saved);
48
+ if (record.handle !== identity.handle || (issuer && record.issuer !== issuer) || record.endpoint !== endpoint.href)
49
+ throw new ToolError('enrollment_mismatch', 'Saved enrollment no longer matches this identity configuration.');
50
+ this.approvalUrl(record.approvalUrl, endpoint, record.requestId);
51
+ return record;
52
+ }
53
+ approvalUrl(value, endpoint, requestId) {
54
+ const approval = checkedUrl(value, this.config.developmentLoopback);
55
+ const expected = `${endpoint.pathname.replace(/\/$/, '')}/${encodeURIComponent(requestId)}/approve`;
56
+ if (approval.origin !== endpoint.origin || approval.pathname !== expected || approval.search)
57
+ throw new ToolError('enrollment_response_invalid', 'The provider returned an unexpected approval address.');
58
+ return approval.href;
59
+ }
60
+ status(identityId) {
61
+ const identity = this.identity(identityId);
62
+ const current = this.running.get(identityId);
63
+ if (current?.polling)
64
+ return { ...current };
65
+ const record = this.saved(identityId, identity);
66
+ if (!record)
67
+ return current ? { ...current } : { identity: identityId, status: 'not_started', polling: false, resumable: false };
68
+ const status = record.outcome ?? (this.now() >= record.expiresAt * 1000 ? 'expired' : current?.status === 'failed' ? 'failed' : 'awaiting_owner');
69
+ return { identity: identityId, status, polling: false, resumable: status === 'awaiting_owner' || status === 'failed',
70
+ ...(status === 'awaiting_owner' ? { approvalUrl: record.approvalUrl } : {}), expiresAt: record.expiresAt,
71
+ ...(status === 'failed' && current?.error ? { error: current.error } : {}) };
72
+ }
73
+ start(identityId) {
74
+ const identity = this.identity(identityId);
75
+ const existing = this.status(identityId);
76
+ if (existing.polling || ['active', 'denied', 'expired'].includes(existing.status))
77
+ return existing;
78
+ if ([...this.running.values()].filter((v) => v.polling).length >= 2)
79
+ throw new ToolError('busy', 'Wait for a running enrollment check to finish.');
80
+ const progress = { ...existing, status: 'starting', polling: true, resumable: false };
81
+ delete progress.error;
82
+ this.running.set(identityId, progress);
83
+ void this.perform(identity, progress).catch((error) => {
84
+ const code = safeError(error).code;
85
+ progress.resumable = !!progress.expiresAt && this.now() < progress.expiresAt * 1000;
86
+ progress.status = code === 'timeout' && progress.resumable ? 'awaiting_owner' : 'failed';
87
+ if (progress.status === 'failed')
88
+ progress.error = code;
89
+ }).finally(() => { progress.polling = false; });
90
+ return { ...progress };
91
+ }
92
+ async json(url, init, deadline) {
93
+ if (this.now() >= deadline)
94
+ throw new ToolError('timeout', 'Enrollment exceeded its deadline.');
95
+ const headers = {};
96
+ new Headers(init.headers).forEach((value, name) => { headers[name] = value; });
97
+ const response = await safeFetch(url, { method: init.method, headers, body: typeof init.body === 'string' ? init.body : undefined, allowPrivate: this.config.developmentLoopback, timeoutMs: Math.min(10_000, deadline - this.now()), maxBytes: 64 * 1024, maxRedirects: 0 });
98
+ return response;
99
+ }
100
+ async perform(identity, progress) {
101
+ const deadline = this.now() + this.config.signInTimeoutSeconds * 1000;
102
+ const endpoint = checkedUrl(identity.enrollmentEndpoint, this.config.developmentLoopback);
103
+ const store = new FileKeystore(join(this.config.stateDirectory, 'keys.json'));
104
+ const client = new AgentLogin({ handle: identity.handle, issuer: identity.issuer, keystore: store, allowInsecure: this.config.developmentLoopback, timeoutMs: 10_000 });
105
+ const { issuer, metadata } = await client.discover();
106
+ const filename = this.filename(progress.identity);
107
+ let record = this.saved(progress.identity, identity, issuer);
108
+ let key;
109
+ if (record) {
110
+ if (record.handle !== identity.handle || record.issuer !== issuer || record.endpoint !== endpoint.href)
111
+ throw new ToolError('enrollment_mismatch', 'Saved enrollment no longer matches this identity configuration.');
112
+ key = await store.get(record.kid);
113
+ if (!key || key.handle !== identity.handle || key.issuer !== issuer || key.status === 'revoked')
114
+ throw new ToolError('enrollment_mismatch', 'Saved enrollment key is unavailable. Do not create a replacement automatically.');
115
+ }
116
+ else {
117
+ const keys = (await store.list(identity.handle)).filter((k) => k.issuer === issuer);
118
+ if (keys.some((k) => k.status === 'active' && (!k.expiresAt || k.expiresAt > this.now() / 1000))) {
119
+ progress.status = 'active';
120
+ return;
121
+ }
122
+ key = keys.find((k) => k.status === 'pending') ?? await client.generateKey('Agent Login local helper');
123
+ const token = identity.enrollmentCredentialEnv ? this.env[identity.enrollmentCredentialEnv] : undefined;
124
+ if (!token)
125
+ throw new ToolError('enrollment_credential_missing', 'Configure the provider API credential through the host secret configuration.');
126
+ const response = await this.json(endpoint.href, { method: 'POST', headers: { authorization: `Bearer ${token}`, 'content-type': 'application/json', accept: 'application/json' }, body: JSON.stringify({ handle: identity.handle, public_jwk: key.publicJwk, name: key.name }) }, deadline);
127
+ if (response.status !== 201 && response.status !== 200)
128
+ throw new ToolError('enrollment_refused', 'The provider did not accept the enrollment request.');
129
+ const body = JSON.parse(response.body.toString('utf8'));
130
+ const parsed = z.object({ request_id: z.string().regex(/^[A-Za-z0-9_-]{16,128}$/), polling_token: z.string().min(16).max(4096), approval_url: z.string(), expires_at: z.number().positive() }).passthrough().parse(body);
131
+ const approvalUrl = this.approvalUrl(parsed.approval_url, endpoint, parsed.request_id);
132
+ record = { requestId: parsed.request_id, token: parsed.polling_token, approvalUrl, expiresAt: parsed.expires_at, kid: key.kid, handle: identity.handle, issuer, endpoint: endpoint.href };
133
+ }
134
+ writeState(filename, record);
135
+ progress.approvalUrl = record.approvalUrl;
136
+ progress.expiresAt = record.expiresAt;
137
+ progress.status = 'awaiting_owner';
138
+ const finish = (outcome) => {
139
+ writeState(filename, { ...record, outcome });
140
+ progress.status = outcome;
141
+ progress.resumable = false;
142
+ delete progress.approvalUrl;
143
+ };
144
+ const attemptedChallenges = new Set();
145
+ const pollUrl = new URL(`${endpoint.pathname.replace(/\/$/, '')}/${encodeURIComponent(record.requestId)}`, endpoint.origin).href;
146
+ while (this.now() < Math.min(deadline, record.expiresAt * 1000)) {
147
+ const response = await this.json(pollUrl, { headers: { authorization: `Bearer ${record.token}`, accept: 'application/json' } }, deadline);
148
+ if (response.status === 429) {
149
+ await this.pause(5, deadline);
150
+ continue;
151
+ }
152
+ if (response.status !== 200)
153
+ throw new ToolError('enrollment_uncertain', 'Enrollment could not be checked. The saved key has been retained.');
154
+ const body = JSON.parse(response.body.toString('utf8'));
155
+ if (body.status === 'denied' || body.status === 'expired') {
156
+ finish(body.status);
157
+ return;
158
+ }
159
+ if (body.status === 'approved' && body.enrollment) {
160
+ const enrollment = body.enrollment;
161
+ if (typeof enrollment.expires_at !== 'number' || !Number.isFinite(enrollment.expires_at) || enrollment.expires_at <= this.now() / 1000)
162
+ throw new ToolError('enrollment_response_invalid', 'The provider did not return a valid key expiry.');
163
+ if (enrollment.kid !== key.kid)
164
+ throw new ToolError('enrollment_mismatch', 'The provider approved a different key.');
165
+ if (enrollment.status === 'active') {
166
+ await store.put({ ...key, status: 'active', expiresAt: enrollment.expires_at });
167
+ finish('active');
168
+ return;
169
+ }
170
+ if (enrollment.status !== 'pending' || typeof enrollment.challenge !== 'string' || !enrollment.challenge || typeof enrollment.proof_url !== 'string')
171
+ throw new ToolError('enrollment_response_invalid', 'The provider did not return a complete enrollment challenge.');
172
+ const proofUrl = checkedUrl(enrollment.proof_url, this.config.developmentLoopback);
173
+ const agents = new URL(metadata.agents_endpoint);
174
+ const base = agents.pathname.replace(/\/$/, '');
175
+ if (proofUrl.origin !== agents.origin || !proofUrl.pathname.startsWith(`${base}/`) || proofUrl.search)
176
+ throw new ToolError('enrollment_response_invalid', 'The proof endpoint is outside the discovered issuer agent endpoint.');
177
+ // Never loop on a consumed or expired nonce. A later broker poll may mint a fresh proof
178
+ // after rechecking the durable approval and the current Owner, Agent and key lifecycle.
179
+ if (attemptedChallenges.has(enrollment.challenge))
180
+ throw new ToolError('enrollment_uncertain', 'The provider has not supplied a fresh challenge. Resume the saved request later.');
181
+ attemptedChallenges.add(enrollment.challenge);
182
+ const now = Math.floor(this.now() / 1000);
183
+ const proof = await new SignJWT({ nonce: enrollment.challenge, jti: randomUUID() }).setProtectedHeader({ alg: 'ES256', typ: 'agent-login-enrollment+jwt', kid: key.kid }).setIssuer(identity.handle).setSubject(identity.handle).setAudience(issuer).setIssuedAt(now).setExpirationTime(now + 60).sign(await importJWK(key.privateJwk, 'ES256'));
184
+ progress.status = 'proving';
185
+ // A lost answer is reconciled by the next explicit start: it polls the same durable broker request.
186
+ const proved = await this.json(proofUrl.href, { method: 'POST', headers: { 'content-type': 'application/json', accept: 'application/json' }, body: JSON.stringify({ proof }) }, deadline).catch(() => { throw new ToolError('enrollment_uncertain', 'The proof response was lost; retry enrollment to reconcile the saved request.'); });
187
+ if (proved.status === 400 || proved.status === 401) {
188
+ // A short proof challenge can expire during transport. Re-poll the saved request;
189
+ // only the broker can authorize a replacement. This does not retry Owner approval.
190
+ progress.status = 'awaiting_owner';
191
+ await this.pause(5, deadline);
192
+ continue;
193
+ }
194
+ if (proved.status !== 200)
195
+ throw new ToolError('enrollment_uncertain', 'The proof outcome needs reconciliation; the same key and request have been retained.');
196
+ const active = z.object({ kid: z.literal(key.kid), status: z.literal('active'), expires_at: z.number().positive() }).passthrough().safeParse(JSON.parse(proved.body.toString('utf8')));
197
+ if (!active.success)
198
+ throw new ToolError('enrollment_uncertain', 'The proof response did not confirm activation of this key. Resume the saved request.');
199
+ await store.put({ ...key, status: 'active', expiresAt: active.data.expires_at });
200
+ finish('active');
201
+ return;
202
+ }
203
+ if (body.status !== 'pending')
204
+ throw new ToolError('enrollment_response_invalid', 'The provider returned an unknown enrollment status.');
205
+ await this.pause(typeof body.retry_after === 'number' ? body.retry_after : 5, deadline);
206
+ }
207
+ if (this.now() >= record.expiresAt * 1000) {
208
+ finish('expired');
209
+ return;
210
+ }
211
+ // The local polling budget is deliberately shorter than the human decision window.
212
+ // Pausing network activity does not deny, expire or discard the provider request.
213
+ progress.status = 'awaiting_owner';
214
+ progress.resumable = true;
215
+ }
216
+ pause(seconds, deadline) { return this.sleep(Math.max(0, Math.min(Number.isFinite(seconds) ? Math.max(1, Math.min(seconds, 60)) * 1000 : 5000, deadline - this.now()))); }
217
+ }
218
+ //# sourceMappingURL=enrollment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrollment.js","sourceRoot":"","sources":["../src/enrollment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export { createServer } from './server.js';
2
+ export { LoginRuntime, ToolError } from './runtime.js';
3
+ export type { LoginClient, RuntimeOptions } from './runtime.js';
4
+ export { EnrollmentRuntime } from './enrollment.js';
5
+ export { ConfigSchema, parseConfig, readPrivateConfig } from './config.js';
6
+ export type { Config, Application, Identity } from './config.js';
7
+ export { CatalogSchema, readCatalog, catalogView, catalogJsonSchema } from './catalog.js';
8
+ export type { Catalog } from './catalog.js';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { createServer } from './server.js';
2
+ export { LoginRuntime, ToolError } from './runtime.js';
3
+ export { EnrollmentRuntime } from './enrollment.js';
4
+ export { ConfigSchema, parseConfig, readPrivateConfig } from './config.js';
5
+ export { CatalogSchema, readCatalog, catalogView, catalogJsonSchema } from './catalog.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAE3E,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function privateDirectory(dir: string): void;
2
+ export declare function readState(file: string): unknown;
3
+ export declare function writeState(file: string, value: unknown): void;
4
+ /** One serving process per private directory. Never steal a lock from a suspended process. */
5
+ export declare function acquireStateLease(dir: string): () => void;
@@ -0,0 +1,72 @@
1
+ import { closeSync, constants, existsSync, fstatSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { randomUUID } from 'node:crypto';
4
+ export function privateDirectory(dir) {
5
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
6
+ const st = lstatSync(dir);
7
+ if (!st.isDirectory() || st.isSymbolicLink() || (typeof process.getuid === 'function' && (st.uid !== process.getuid() || (st.mode & 0o077) !== 0)))
8
+ throw new Error('State directory must be owned by you with mode 0700');
9
+ }
10
+ export function readState(file) {
11
+ if (!existsSync(file))
12
+ return undefined;
13
+ const fd = openSync(file, constants.O_RDONLY | constants.O_NOFOLLOW);
14
+ try {
15
+ const st = fstatSync(fd);
16
+ if (!st.isFile() || st.size > 64 * 1024 || (typeof process.getuid === 'function' && (st.uid !== process.getuid() || (st.mode & 0o077) !== 0)))
17
+ throw new Error('Invalid private state file');
18
+ return JSON.parse(readFileSync(fd, 'utf8'));
19
+ }
20
+ finally {
21
+ closeSync(fd);
22
+ }
23
+ }
24
+ export function writeState(file, value) {
25
+ privateDirectory(dirname(file));
26
+ const temporary = `${file}.${randomUUID()}.tmp`;
27
+ const fd = openSync(temporary, 'wx', 0o600);
28
+ try {
29
+ try {
30
+ writeFileSync(fd, JSON.stringify(value));
31
+ fsyncSync(fd);
32
+ }
33
+ finally {
34
+ closeSync(fd);
35
+ }
36
+ renameSync(temporary, file);
37
+ }
38
+ catch (error) {
39
+ try {
40
+ unlinkSync(temporary);
41
+ }
42
+ catch { }
43
+ throw error;
44
+ }
45
+ }
46
+ /** One serving process per private directory. Never steal a lock from a suspended process. */
47
+ export function acquireStateLease(dir) {
48
+ privateDirectory(dir);
49
+ const file = join(dir, 'mcp-server.lock');
50
+ const marker = `${process.pid}:${randomUUID()}`;
51
+ let fd;
52
+ try {
53
+ fd = openSync(file, 'wx', 0o600);
54
+ }
55
+ catch {
56
+ throw new Error('State directory is already in use. Stop all helpers before removing an abandoned mcp-server.lock.');
57
+ }
58
+ try {
59
+ writeFileSync(fd, marker);
60
+ }
61
+ finally {
62
+ closeSync(fd);
63
+ }
64
+ return () => {
65
+ try {
66
+ if (readFileSync(file, 'utf8') === marker)
67
+ unlinkSync(file);
68
+ }
69
+ catch { }
70
+ };
71
+ }
72
+ //# sourceMappingURL=private-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"private-state.js","sourceRoot":"","sources":["../src/private-state.ts"],"names":[],"mappings":"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"}