@usekova/mcp-server 0.1.0 → 2.0.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 CHANGED
@@ -1,9 +1,666 @@
1
1
  "use strict";
2
- /**
3
- * @stele/mcp-server — Model Context Protocol server that exposes
4
- * Stele tools to any AI agent.
5
- *
6
- * @packageDocumentation
7
- */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- //# sourceMappingURL=index.js.map
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ JSON_RPC_ERRORS: () => JSON_RPC_ERRORS,
34
+ SteleServer: () => SteleServer,
35
+ createAuthMiddleware: () => createAuthMiddleware
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+ var import_sdk = require("@usekova/sdk");
39
+ var import_crypto2 = require("@usekova/crypto");
40
+
41
+ // src/types.ts
42
+ var JSON_RPC_ERRORS = {
43
+ /** Invalid JSON was received by the server. */
44
+ PARSE_ERROR: -32700,
45
+ /** The JSON sent is not a valid Request object. */
46
+ INVALID_REQUEST: -32600,
47
+ /** The method does not exist or is not available. */
48
+ METHOD_NOT_FOUND: -32601,
49
+ /** Invalid method parameter(s). */
50
+ INVALID_PARAMS: -32602,
51
+ /** Internal JSON-RPC error. */
52
+ INTERNAL_ERROR: -32603
53
+ };
54
+
55
+ // src/auth.ts
56
+ var import_crypto = require("@usekova/crypto");
57
+ function createAuthMiddleware(options) {
58
+ const apiKeys = new Set(options.apiKeys ?? []);
59
+ const trustedKeys = new Set(options.trustedKeys ?? []);
60
+ const rateLimitPerMinute = options.rateLimitPerMinute ?? 0;
61
+ const clientRates = /* @__PURE__ */ new Map();
62
+ const knownClients = /* @__PURE__ */ new Set();
63
+ function authenticate(headers) {
64
+ const now = (0, import_crypto.timestamp)();
65
+ const apiKey = headers["x-api-key"];
66
+ if (apiKey) {
67
+ if (!apiKeys.has(apiKey)) {
68
+ throw new Error("Invalid API key");
69
+ }
70
+ const clientId = `apikey:${(0, import_crypto.sha256String)(apiKey).slice(0, 16)}`;
71
+ knownClients.add(clientId);
72
+ return {
73
+ clientId,
74
+ authMethod: "api-key",
75
+ timestamp: now
76
+ };
77
+ }
78
+ const publicKeyHex = headers["x-public-key"];
79
+ const signatureHex = headers["x-signature"];
80
+ const payload = headers["x-signature-payload"];
81
+ if (publicKeyHex && signatureHex && payload) {
82
+ if (!trustedKeys.has(publicKeyHex)) {
83
+ throw new Error("Untrusted public key");
84
+ }
85
+ const clientId = `sig:${publicKeyHex.slice(0, 16)}`;
86
+ knownClients.add(clientId);
87
+ return {
88
+ clientId,
89
+ authMethod: "signature",
90
+ timestamp: now
91
+ };
92
+ }
93
+ if (apiKeys.size === 0 && trustedKeys.size === 0) {
94
+ const clientId = "anonymous";
95
+ knownClients.add(clientId);
96
+ return {
97
+ clientId,
98
+ authMethod: "none",
99
+ timestamp: now
100
+ };
101
+ }
102
+ throw new Error("Authentication required");
103
+ }
104
+ function isRateLimited(clientId) {
105
+ if (rateLimitPerMinute <= 0) {
106
+ return false;
107
+ }
108
+ const now = Date.now();
109
+ const windowMs = 6e4;
110
+ let window = clientRates.get(clientId);
111
+ if (!window) {
112
+ window = { timestamps: [] };
113
+ clientRates.set(clientId, window);
114
+ }
115
+ window.timestamps = window.timestamps.filter(
116
+ (ts) => now - ts < windowMs
117
+ );
118
+ if (window.timestamps.length >= rateLimitPerMinute) {
119
+ return true;
120
+ }
121
+ window.timestamps.push(now);
122
+ return false;
123
+ }
124
+ function revokeKey(key) {
125
+ apiKeys.delete(key);
126
+ trustedKeys.delete(key);
127
+ }
128
+ function listClients() {
129
+ return Array.from(knownClients);
130
+ }
131
+ return {
132
+ authenticate,
133
+ isRateLimited,
134
+ revokeKey,
135
+ listClients
136
+ };
137
+ }
138
+
139
+ // src/index.ts
140
+ var TOOL_DEFINITIONS = [
141
+ {
142
+ name: "create_covenant",
143
+ description: "Create a new signed covenant document with CCL constraints between an issuer and beneficiary.",
144
+ inputSchema: {
145
+ type: "object",
146
+ properties: {
147
+ issuer: {
148
+ type: "object",
149
+ description: 'The issuing party. Must have id, publicKey, and role="issuer".',
150
+ properties: {
151
+ id: { type: "string", description: "Unique identifier for the issuer." },
152
+ publicKey: { type: "string", description: "Hex-encoded Ed25519 public key." },
153
+ role: { type: "string", description: 'Must be "issuer".', enum: ["issuer"] },
154
+ name: { type: "string", description: "Optional human-readable name." }
155
+ },
156
+ required: ["id", "publicKey", "role"]
157
+ },
158
+ beneficiary: {
159
+ type: "object",
160
+ description: 'The beneficiary party. Must have id, publicKey, and role="beneficiary".',
161
+ properties: {
162
+ id: { type: "string", description: "Unique identifier for the beneficiary." },
163
+ publicKey: { type: "string", description: "Hex-encoded Ed25519 public key." },
164
+ role: { type: "string", description: 'Must be "beneficiary".', enum: ["beneficiary"] },
165
+ name: { type: "string", description: "Optional human-readable name." }
166
+ },
167
+ required: ["id", "publicKey", "role"]
168
+ },
169
+ constraints: {
170
+ type: "string",
171
+ description: `CCL constraint source text (e.g. "permit read on '**'").`
172
+ },
173
+ privateKeyHex: {
174
+ type: "string",
175
+ description: "Hex-encoded issuer private key for signing."
176
+ }
177
+ },
178
+ required: ["issuer", "beneficiary", "constraints", "privateKeyHex"]
179
+ }
180
+ },
181
+ {
182
+ name: "verify_covenant",
183
+ description: "Verify a covenant document by running all specification checks (signature, expiry, CCL syntax, etc.).",
184
+ inputSchema: {
185
+ type: "object",
186
+ properties: {
187
+ covenantId: {
188
+ type: "string",
189
+ description: "The ID of the covenant document in the store to verify."
190
+ }
191
+ },
192
+ required: ["covenantId"]
193
+ }
194
+ },
195
+ {
196
+ name: "evaluate_action",
197
+ description: "Evaluate whether a specific action on a resource is permitted by a covenant's CCL constraints.",
198
+ inputSchema: {
199
+ type: "object",
200
+ properties: {
201
+ covenantId: {
202
+ type: "string",
203
+ description: "The ID of the covenant document to evaluate against."
204
+ },
205
+ action: {
206
+ type: "string",
207
+ description: 'The action to evaluate (e.g. "read", "write", "file.delete").'
208
+ },
209
+ resource: {
210
+ type: "string",
211
+ description: 'The resource path to evaluate (e.g. "/data", "/files/**").'
212
+ },
213
+ context: {
214
+ type: "object",
215
+ description: "Optional evaluation context with additional variables for condition matching."
216
+ }
217
+ },
218
+ required: ["covenantId", "action", "resource"]
219
+ }
220
+ },
221
+ {
222
+ name: "create_identity",
223
+ description: "Create a new agent identity with model attestation, capabilities, and deployment context.",
224
+ inputSchema: {
225
+ type: "object",
226
+ properties: {
227
+ operatorIdentifier: {
228
+ type: "string",
229
+ description: "Optional human-readable operator identifier."
230
+ },
231
+ model: {
232
+ type: "object",
233
+ description: "Model attestation describing the AI model.",
234
+ properties: {
235
+ provider: { type: "string", description: 'Model provider (e.g. "anthropic").' },
236
+ modelId: { type: "string", description: 'Model identifier (e.g. "claude-3").' },
237
+ modelVersion: { type: "string", description: "Optional model version." }
238
+ },
239
+ required: ["provider", "modelId"]
240
+ },
241
+ capabilities: {
242
+ type: "array",
243
+ description: "List of capability strings this agent has.",
244
+ items: { type: "string" }
245
+ },
246
+ deployment: {
247
+ type: "object",
248
+ description: "Deployment context describing where the agent runs.",
249
+ properties: {
250
+ runtime: { type: "string", description: 'Runtime type (e.g. "process", "container", "wasm").', enum: ["wasm", "container", "tee", "firecracker", "process", "browser"] },
251
+ region: { type: "string", description: "Optional deployment region." },
252
+ provider: { type: "string", description: "Optional cloud provider." }
253
+ },
254
+ required: ["runtime"]
255
+ },
256
+ privateKeyHex: {
257
+ type: "string",
258
+ description: "Optional hex-encoded operator private key. A new key pair is generated if omitted."
259
+ }
260
+ },
261
+ required: ["model", "capabilities", "deployment"]
262
+ }
263
+ },
264
+ {
265
+ name: "parse_ccl",
266
+ description: "Parse CCL (Covenant Constraint Language) source text and return the structured document.",
267
+ inputSchema: {
268
+ type: "object",
269
+ properties: {
270
+ source: {
271
+ type: "string",
272
+ description: "The CCL source text to parse."
273
+ }
274
+ },
275
+ required: ["source"]
276
+ }
277
+ },
278
+ {
279
+ name: "list_covenants",
280
+ description: "List all covenant documents currently in the store, optionally filtered by issuer or beneficiary.",
281
+ inputSchema: {
282
+ type: "object",
283
+ properties: {
284
+ issuerId: {
285
+ type: "string",
286
+ description: "Optional filter: only return covenants from this issuer."
287
+ },
288
+ beneficiaryId: {
289
+ type: "string",
290
+ description: "Optional filter: only return covenants for this beneficiary."
291
+ }
292
+ }
293
+ }
294
+ }
295
+ ];
296
+ var SteleServer = class {
297
+ /** The backing store for covenant documents. */
298
+ store;
299
+ /** The SDK client used for operations. */
300
+ client;
301
+ /** Server name. */
302
+ name;
303
+ /** Server version. */
304
+ version;
305
+ constructor(store, options) {
306
+ this.store = store;
307
+ this.client = new import_sdk.KovaClient();
308
+ this.name = options?.name ?? "stele-mcp-server";
309
+ this.version = options?.version ?? "0.1.0";
310
+ }
311
+ // ── Tool listing ────────────────────────────────────────────────────────────
312
+ /**
313
+ * Return all available tool definitions with their JSON Schema input schemas.
314
+ */
315
+ listTools() {
316
+ return [...TOOL_DEFINITIONS];
317
+ }
318
+ // ── Tool execution ──────────────────────────────────────────────────────────
319
+ /**
320
+ * Call a named tool with the given arguments.
321
+ *
322
+ * @param name - The tool name (must match one of the tool definitions).
323
+ * @param args - The tool arguments matching the tool's input schema.
324
+ * @returns A {@link ToolResult} containing the output or error.
325
+ */
326
+ async callTool(name, args) {
327
+ switch (name) {
328
+ case "create_covenant":
329
+ return this._createCovenant(args);
330
+ case "verify_covenant":
331
+ return this._verifyCovenant(args);
332
+ case "evaluate_action":
333
+ return this._evaluateAction(args);
334
+ case "create_identity":
335
+ return this._createIdentity(args);
336
+ case "parse_ccl":
337
+ return this._parseCCL(args);
338
+ case "list_covenants":
339
+ return this._listCovenants(args);
340
+ default:
341
+ return {
342
+ content: [{ type: "text", text: `Unknown tool: ${name}` }],
343
+ isError: true
344
+ };
345
+ }
346
+ }
347
+ // ── JSON-RPC 2.0 message handler ────────────────────────────────────────────
348
+ /**
349
+ * Handle a JSON-RPC 2.0 message and return the appropriate response.
350
+ *
351
+ * Supports the following MCP methods:
352
+ * - `initialize` -- Returns server info and capabilities
353
+ * - `tools/list` -- Returns available tool definitions
354
+ * - `tools/call` -- Executes a tool and returns the result
355
+ * - `ping` -- Returns a pong
356
+ *
357
+ * @param message - A parsed JSON-RPC request object.
358
+ * @returns A JSON-RPC response object.
359
+ */
360
+ async handleMessage(message) {
361
+ if (!message || typeof message !== "object") {
362
+ return this._errorResponse(null, JSON_RPC_ERRORS.INVALID_REQUEST, "Invalid request object");
363
+ }
364
+ if (message.jsonrpc !== "2.0") {
365
+ return this._errorResponse(
366
+ message.id ?? null,
367
+ JSON_RPC_ERRORS.INVALID_REQUEST,
368
+ 'Invalid jsonrpc version, expected "2.0"'
369
+ );
370
+ }
371
+ if (typeof message.method !== "string" || message.method.length === 0) {
372
+ return this._errorResponse(
373
+ message.id ?? null,
374
+ JSON_RPC_ERRORS.INVALID_REQUEST,
375
+ "Missing or invalid method"
376
+ );
377
+ }
378
+ const id = message.id ?? null;
379
+ switch (message.method) {
380
+ case "initialize":
381
+ return this._successResponse(id, {
382
+ protocolVersion: "2024-11-05",
383
+ capabilities: {
384
+ tools: {},
385
+ resources: {},
386
+ prompts: {}
387
+ },
388
+ serverInfo: {
389
+ name: this.name,
390
+ version: this.version
391
+ }
392
+ });
393
+ case "ping":
394
+ return this._successResponse(id, {});
395
+ case "tools/list":
396
+ return this._successResponse(id, {
397
+ tools: this.listTools()
398
+ });
399
+ case "tools/call": {
400
+ const params = message.params;
401
+ if (!params || typeof params.name !== "string") {
402
+ return this._errorResponse(id, JSON_RPC_ERRORS.INVALID_PARAMS, "Missing required param: name");
403
+ }
404
+ const toolName = params.name;
405
+ const toolArgs = params.arguments ?? {};
406
+ const toolDef = TOOL_DEFINITIONS.find((t) => t.name === toolName);
407
+ if (!toolDef) {
408
+ return this._errorResponse(id, JSON_RPC_ERRORS.INVALID_PARAMS, `Unknown tool: ${toolName}`);
409
+ }
410
+ const result = await this.callTool(toolName, toolArgs);
411
+ return this._successResponse(id, result);
412
+ }
413
+ case "notifications/initialized":
414
+ return this._successResponse(id, {});
415
+ case "resources/list":
416
+ return this._successResponse(id, { resources: [] });
417
+ case "resources/templates/list":
418
+ return this._successResponse(id, { resourceTemplates: [] });
419
+ case "prompts/list":
420
+ return this._successResponse(id, { prompts: [] });
421
+ default:
422
+ return this._errorResponse(id, JSON_RPC_ERRORS.METHOD_NOT_FOUND, `Unknown method: ${message.method}`);
423
+ }
424
+ }
425
+ // ── Tool implementations ──────────────────────────────────────────────────
426
+ async _createCovenant(args) {
427
+ try {
428
+ const issuer = args.issuer;
429
+ const beneficiary = args.beneficiary;
430
+ const constraints = args.constraints;
431
+ const privateKeyHex = args.privateKeyHex;
432
+ if (!issuer || !issuer.id || !issuer.publicKey || !issuer.role) {
433
+ return this._toolError("Missing required field: issuer (must have id, publicKey, role)");
434
+ }
435
+ if (!beneficiary || !beneficiary.id || !beneficiary.publicKey || !beneficiary.role) {
436
+ return this._toolError("Missing required field: beneficiary (must have id, publicKey, role)");
437
+ }
438
+ if (!constraints || typeof constraints !== "string") {
439
+ return this._toolError("Missing required field: constraints");
440
+ }
441
+ if (!privateKeyHex || typeof privateKeyHex !== "string") {
442
+ return this._toolError("Missing required field: privateKeyHex");
443
+ }
444
+ const { fromHex: fromHex2 } = await import("@usekova/crypto");
445
+ const privateKey = fromHex2(privateKeyHex);
446
+ const doc = await this.client.createCovenant({
447
+ issuer: {
448
+ id: issuer.id,
449
+ publicKey: issuer.publicKey,
450
+ role: "issuer",
451
+ name: issuer.name
452
+ },
453
+ beneficiary: {
454
+ id: beneficiary.id,
455
+ publicKey: beneficiary.publicKey,
456
+ role: "beneficiary",
457
+ name: beneficiary.name
458
+ },
459
+ constraints,
460
+ privateKey
461
+ });
462
+ await this.store.put(doc);
463
+ return this._toolSuccess({
464
+ id: doc.id,
465
+ version: doc.version,
466
+ issuer: doc.issuer,
467
+ beneficiary: doc.beneficiary,
468
+ constraints: doc.constraints,
469
+ createdAt: doc.createdAt
470
+ });
471
+ } catch (err) {
472
+ return this._toolError(`Failed to create covenant: ${err instanceof Error ? err.message : String(err)}`);
473
+ }
474
+ }
475
+ async _verifyCovenant(args) {
476
+ try {
477
+ const covenantId = args.covenantId;
478
+ if (!covenantId || typeof covenantId !== "string") {
479
+ return this._toolError("Missing required field: covenantId");
480
+ }
481
+ const doc = await this.store.get(covenantId);
482
+ if (!doc) {
483
+ return this._toolError(`Covenant not found: ${covenantId}`);
484
+ }
485
+ const result = await this.client.verifyCovenant(doc);
486
+ return this._toolSuccess({
487
+ valid: result.valid,
488
+ checks: result.checks
489
+ });
490
+ } catch (err) {
491
+ return this._toolError(`Failed to verify covenant: ${err instanceof Error ? err.message : String(err)}`);
492
+ }
493
+ }
494
+ async _evaluateAction(args) {
495
+ try {
496
+ const covenantId = args.covenantId;
497
+ const action = args.action;
498
+ const resource = args.resource;
499
+ const context = args.context;
500
+ if (!covenantId || typeof covenantId !== "string") {
501
+ return this._toolError("Missing required field: covenantId");
502
+ }
503
+ if (!action || typeof action !== "string") {
504
+ return this._toolError("Missing required field: action");
505
+ }
506
+ if (!resource || typeof resource !== "string") {
507
+ return this._toolError("Missing required field: resource");
508
+ }
509
+ const doc = await this.store.get(covenantId);
510
+ if (!doc) {
511
+ return this._toolError(`Covenant not found: ${covenantId}`);
512
+ }
513
+ const result = await this.client.evaluateAction(doc, action, resource, context);
514
+ return this._toolSuccess({
515
+ permitted: result.permitted,
516
+ matchedRule: result.matchedRule,
517
+ reason: result.reason,
518
+ severity: result.severity
519
+ });
520
+ } catch (err) {
521
+ return this._toolError(`Failed to evaluate action: ${err instanceof Error ? err.message : String(err)}`);
522
+ }
523
+ }
524
+ async _createIdentity(args) {
525
+ try {
526
+ const model = args.model;
527
+ const capabilities = args.capabilities;
528
+ const deployment = args.deployment;
529
+ const privateKeyHex = args.privateKeyHex;
530
+ const operatorIdentifier = args.operatorIdentifier;
531
+ if (!model || !model.provider || !model.modelId) {
532
+ return this._toolError("Missing required field: model (must have provider, modelId)");
533
+ }
534
+ if (!capabilities || !Array.isArray(capabilities)) {
535
+ return this._toolError("Missing required field: capabilities (must be an array)");
536
+ }
537
+ if (!deployment || !deployment.runtime) {
538
+ return this._toolError("Missing required field: deployment (must have runtime)");
539
+ }
540
+ let keyPair;
541
+ if (privateKeyHex) {
542
+ const { keyPairFromPrivateKeyHex } = await import("@usekova/crypto");
543
+ keyPair = await keyPairFromPrivateKeyHex(privateKeyHex);
544
+ } else {
545
+ keyPair = await (0, import_crypto2.generateKeyPair)();
546
+ }
547
+ const identity = await this.client.createIdentity({
548
+ operatorKeyPair: keyPair,
549
+ operatorIdentifier,
550
+ model: {
551
+ provider: model.provider,
552
+ modelId: model.modelId,
553
+ modelVersion: model.modelVersion
554
+ },
555
+ capabilities,
556
+ deployment: {
557
+ runtime: deployment.runtime,
558
+ region: deployment.region,
559
+ provider: deployment.provider
560
+ }
561
+ });
562
+ return this._toolSuccess({
563
+ id: identity.id,
564
+ operatorPublicKey: identity.operatorPublicKey,
565
+ operatorIdentifier: identity.operatorIdentifier,
566
+ model: identity.model,
567
+ capabilities: identity.capabilities,
568
+ version: identity.version,
569
+ createdAt: identity.createdAt
570
+ });
571
+ } catch (err) {
572
+ return this._toolError(`Failed to create identity: ${err instanceof Error ? err.message : String(err)}`);
573
+ }
574
+ }
575
+ async _parseCCL(args) {
576
+ try {
577
+ const source = args.source;
578
+ if (!source || typeof source !== "string") {
579
+ return this._toolError("Missing required field: source");
580
+ }
581
+ const doc = this.client.parseCCL(source);
582
+ return this._toolSuccess({
583
+ statements: doc.statements.length,
584
+ permits: doc.permits.length,
585
+ denies: doc.denies.length,
586
+ obligations: doc.obligations.length,
587
+ limits: doc.limits.length,
588
+ details: doc.statements.map((s) => {
589
+ if (s.type === "limit") {
590
+ return {
591
+ type: s.type,
592
+ action: s.action,
593
+ count: s.count,
594
+ periodSeconds: s.periodSeconds,
595
+ severity: s.severity
596
+ };
597
+ }
598
+ return {
599
+ type: s.type,
600
+ action: s.action,
601
+ resource: "resource" in s ? s.resource : void 0,
602
+ severity: s.severity
603
+ };
604
+ })
605
+ });
606
+ } catch (err) {
607
+ return this._toolError(`CCL parse error: ${err instanceof Error ? err.message : String(err)}`);
608
+ }
609
+ }
610
+ async _listCovenants(args) {
611
+ try {
612
+ const issuerId = args.issuerId;
613
+ const beneficiaryId = args.beneficiaryId;
614
+ const filter = {};
615
+ if (issuerId) filter.issuerId = issuerId;
616
+ if (beneficiaryId) filter.beneficiaryId = beneficiaryId;
617
+ const docs = await this.store.list(
618
+ Object.keys(filter).length > 0 ? filter : void 0
619
+ );
620
+ return this._toolSuccess({
621
+ count: docs.length,
622
+ covenants: docs.map((doc) => ({
623
+ id: doc.id,
624
+ issuer: { id: doc.issuer.id, name: doc.issuer.name },
625
+ beneficiary: { id: doc.beneficiary.id, name: doc.beneficiary.name },
626
+ constraints: doc.constraints,
627
+ createdAt: doc.createdAt
628
+ }))
629
+ });
630
+ } catch (err) {
631
+ return this._toolError(`Failed to list covenants: ${err instanceof Error ? err.message : String(err)}`);
632
+ }
633
+ }
634
+ // ── Response helpers ──────────────────────────────────────────────────────
635
+ _successResponse(id, result) {
636
+ return {
637
+ jsonrpc: "2.0",
638
+ result,
639
+ id
640
+ };
641
+ }
642
+ _errorResponse(id, code, message, data) {
643
+ return {
644
+ jsonrpc: "2.0",
645
+ error: { code, message, data },
646
+ id
647
+ };
648
+ }
649
+ _toolSuccess(data) {
650
+ return {
651
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
652
+ };
653
+ }
654
+ _toolError(message) {
655
+ return {
656
+ content: [{ type: "text", text: message }],
657
+ isError: true
658
+ };
659
+ }
660
+ };
661
+ // Annotate the CommonJS export names for ESM import in node:
662
+ 0 && (module.exports = {
663
+ JSON_RPC_ERRORS,
664
+ SteleServer,
665
+ createAuthMiddleware
666
+ });