@attested-intelligence/aga-mcp-server 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.
Files changed (165) hide show
  1. package/AGA_MCP_SERVER_SPEC.md +632 -0
  2. package/LICENSE +21 -0
  3. package/README.md +42 -0
  4. package/dist/core/artifact.d.ts +19 -0
  5. package/dist/core/artifact.d.ts.map +1 -0
  6. package/dist/core/artifact.js +27 -0
  7. package/dist/core/artifact.js.map +1 -0
  8. package/dist/core/attestation.d.ts +19 -0
  9. package/dist/core/attestation.d.ts.map +1 -0
  10. package/dist/core/attestation.js +12 -0
  11. package/dist/core/attestation.js.map +1 -0
  12. package/dist/core/behavioral.d.ts +45 -0
  13. package/dist/core/behavioral.d.ts.map +1 -0
  14. package/dist/core/behavioral.js +88 -0
  15. package/dist/core/behavioral.js.map +1 -0
  16. package/dist/core/bundle.d.ts +13 -0
  17. package/dist/core/bundle.d.ts.map +1 -0
  18. package/dist/core/bundle.js +31 -0
  19. package/dist/core/bundle.js.map +1 -0
  20. package/dist/core/chain.d.ts +13 -0
  21. package/dist/core/chain.d.ts.map +1 -0
  22. package/dist/core/chain.js +63 -0
  23. package/dist/core/chain.js.map +1 -0
  24. package/dist/core/checkpoint.d.ts +8 -0
  25. package/dist/core/checkpoint.d.ts.map +1 -0
  26. package/dist/core/checkpoint.js +21 -0
  27. package/dist/core/checkpoint.js.map +1 -0
  28. package/dist/core/delegation.d.ts +37 -0
  29. package/dist/core/delegation.d.ts.map +1 -0
  30. package/dist/core/delegation.js +104 -0
  31. package/dist/core/delegation.js.map +1 -0
  32. package/dist/core/disclosure.d.ts +12 -0
  33. package/dist/core/disclosure.d.ts.map +1 -0
  34. package/dist/core/disclosure.js +25 -0
  35. package/dist/core/disclosure.js.map +1 -0
  36. package/dist/core/index.d.ts +12 -0
  37. package/dist/core/index.d.ts.map +1 -0
  38. package/dist/core/index.js +12 -0
  39. package/dist/core/index.js.map +1 -0
  40. package/dist/core/portal.d.ts +28 -0
  41. package/dist/core/portal.d.ts.map +1 -0
  42. package/dist/core/portal.js +95 -0
  43. package/dist/core/portal.js.map +1 -0
  44. package/dist/core/quarantine.d.ts +8 -0
  45. package/dist/core/quarantine.d.ts.map +1 -0
  46. package/dist/core/quarantine.js +13 -0
  47. package/dist/core/quarantine.js.map +1 -0
  48. package/dist/core/receipt.d.ts +17 -0
  49. package/dist/core/receipt.d.ts.map +1 -0
  50. package/dist/core/receipt.js +17 -0
  51. package/dist/core/receipt.js.map +1 -0
  52. package/dist/core/subject.d.ts +4 -0
  53. package/dist/core/subject.d.ts.map +1 -0
  54. package/dist/core/subject.js +9 -0
  55. package/dist/core/subject.js.map +1 -0
  56. package/dist/core/types.d.ts +167 -0
  57. package/dist/core/types.d.ts.map +1 -0
  58. package/dist/core/types.js +2 -0
  59. package/dist/core/types.js.map +1 -0
  60. package/dist/crypto/hash.d.ts +9 -0
  61. package/dist/crypto/hash.d.ts.map +1 -0
  62. package/dist/crypto/hash.js +30 -0
  63. package/dist/crypto/hash.js.map +1 -0
  64. package/dist/crypto/index.d.ts +6 -0
  65. package/dist/crypto/index.d.ts.map +1 -0
  66. package/dist/crypto/index.js +6 -0
  67. package/dist/crypto/index.js.map +1 -0
  68. package/dist/crypto/merkle.d.ts +8 -0
  69. package/dist/crypto/merkle.d.ts.map +1 -0
  70. package/dist/crypto/merkle.js +42 -0
  71. package/dist/crypto/merkle.js.map +1 -0
  72. package/dist/crypto/salt.d.ts +5 -0
  73. package/dist/crypto/salt.d.ts.map +1 -0
  74. package/dist/crypto/salt.js +14 -0
  75. package/dist/crypto/salt.js.map +1 -0
  76. package/dist/crypto/sign.d.ts +11 -0
  77. package/dist/crypto/sign.d.ts.map +1 -0
  78. package/dist/crypto/sign.js +37 -0
  79. package/dist/crypto/sign.js.map +1 -0
  80. package/dist/crypto/types.d.ts +24 -0
  81. package/dist/crypto/types.d.ts.map +1 -0
  82. package/dist/crypto/types.js +2 -0
  83. package/dist/crypto/types.js.map +1 -0
  84. package/dist/index.d.ts +3 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +11 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/middleware/governance.d.ts +27 -0
  89. package/dist/middleware/governance.d.ts.map +1 -0
  90. package/dist/middleware/governance.js +65 -0
  91. package/dist/middleware/governance.js.map +1 -0
  92. package/dist/middleware/index.d.ts +2 -0
  93. package/dist/middleware/index.d.ts.map +1 -0
  94. package/dist/middleware/index.js +2 -0
  95. package/dist/middleware/index.js.map +1 -0
  96. package/dist/server.d.ts +13 -0
  97. package/dist/server.d.ts.map +1 -0
  98. package/dist/server.js +369 -0
  99. package/dist/server.js.map +1 -0
  100. package/dist/storage/index.d.ts +4 -0
  101. package/dist/storage/index.d.ts.map +1 -0
  102. package/dist/storage/index.js +3 -0
  103. package/dist/storage/index.js.map +1 -0
  104. package/dist/storage/interface.d.ts +21 -0
  105. package/dist/storage/interface.d.ts.map +1 -0
  106. package/dist/storage/interface.js +2 -0
  107. package/dist/storage/interface.js.map +1 -0
  108. package/dist/storage/memory.d.ts +26 -0
  109. package/dist/storage/memory.d.ts.map +1 -0
  110. package/dist/storage/memory.js +24 -0
  111. package/dist/storage/memory.js.map +1 -0
  112. package/dist/storage/sqlite.d.ts +25 -0
  113. package/dist/storage/sqlite.d.ts.map +1 -0
  114. package/dist/storage/sqlite.js +44 -0
  115. package/dist/storage/sqlite.js.map +1 -0
  116. package/dist/utils/canonical.d.ts +3 -0
  117. package/dist/utils/canonical.d.ts.map +1 -0
  118. package/dist/utils/canonical.js +17 -0
  119. package/dist/utils/canonical.js.map +1 -0
  120. package/dist/utils/constants.d.ts +4 -0
  121. package/dist/utils/constants.d.ts.map +1 -0
  122. package/dist/utils/constants.js +4 -0
  123. package/dist/utils/constants.js.map +1 -0
  124. package/dist/utils/timestamp.d.ts +4 -0
  125. package/dist/utils/timestamp.d.ts.map +1 -0
  126. package/dist/utils/timestamp.js +13 -0
  127. package/dist/utils/timestamp.js.map +1 -0
  128. package/dist/utils/uuid.d.ts +2 -0
  129. package/dist/utils/uuid.d.ts.map +1 -0
  130. package/dist/utils/uuid.js +3 -0
  131. package/dist/utils/uuid.js.map +1 -0
  132. package/package.json +45 -0
  133. package/src/core/artifact.ts +45 -0
  134. package/src/core/attestation.ts +33 -0
  135. package/src/core/behavioral.ts +132 -0
  136. package/src/core/bundle.ts +31 -0
  137. package/src/core/chain.ts +72 -0
  138. package/src/core/checkpoint.ts +22 -0
  139. package/src/core/delegation.ts +146 -0
  140. package/src/core/disclosure.ts +32 -0
  141. package/src/core/index.ts +11 -0
  142. package/src/core/portal.ts +96 -0
  143. package/src/core/quarantine.ts +16 -0
  144. package/src/core/receipt.ts +33 -0
  145. package/src/core/subject.ts +11 -0
  146. package/src/core/types.ts +244 -0
  147. package/src/crypto/hash.ts +33 -0
  148. package/src/crypto/index.ts +5 -0
  149. package/src/crypto/merkle.ts +43 -0
  150. package/src/crypto/salt.ts +18 -0
  151. package/src/crypto/sign.ts +35 -0
  152. package/src/crypto/types.ts +19 -0
  153. package/src/index.ts +12 -0
  154. package/src/middleware/governance.ts +95 -0
  155. package/src/middleware/index.ts +1 -0
  156. package/src/server.ts +436 -0
  157. package/src/storage/index.ts +3 -0
  158. package/src/storage/interface.ts +21 -0
  159. package/src/storage/memory.ts +27 -0
  160. package/src/storage/sqlite.ts +45 -0
  161. package/src/tools/README.md +13 -0
  162. package/src/utils/canonical.ts +14 -0
  163. package/src/utils/constants.ts +3 -0
  164. package/src/utils/timestamp.ts +12 -0
  165. package/src/utils/uuid.ts +2 -0
@@ -0,0 +1,11 @@
1
+ export * from './types.js';
2
+ export * from './subject.js';
3
+ export * from './attestation.js';
4
+ export * from './artifact.js';
5
+ export * from './receipt.js';
6
+ export * from './chain.js';
7
+ export * from './portal.js';
8
+ export * from './quarantine.js';
9
+ export * from './checkpoint.js';
10
+ export * from './bundle.js';
11
+ export * from './disclosure.js';
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Portal (Sentinel) — Runtime Enforcement Boundary. Ref 150, 270-280.
3
+ * V3: TTL + revocation checked every measurement. Fail-closed semantics.
4
+ * Aligned with NCCoE filing Sections 3-4 and NIST-2025-0035.
5
+ */
6
+ import { sha256Bytes, sha256Str } from '../crypto/hash.js';
7
+ import { b64ToSig, hexToPk, verifyStr } from '../crypto/sign.js';
8
+ import { canonicalize } from '../utils/canonical.js';
9
+ import { isWithinPeriod, isExpired, utcNow } from '../utils/timestamp.js';
10
+ import type { PolicyArtifact, PortalState, EnforcementAction, SubjectMetadata } from './types.js';
11
+ import type { HashHex } from '../crypto/types.js';
12
+
13
+ export interface MeasurementResult {
14
+ match: boolean;
15
+ currentBytesHash: HashHex;
16
+ currentMetaHash: HashHex;
17
+ expectedBytesHash: HashHex;
18
+ expectedMetaHash: HashHex;
19
+ ttl_ok: boolean;
20
+ revoked: boolean;
21
+ }
22
+
23
+ export class Portal {
24
+ state: PortalState = 'INITIALIZATION';
25
+ artifact: PolicyArtifact | null = null;
26
+ sequenceCounter = 0;
27
+ lastLeafHash: HashHex | null = null;
28
+ revocations: Set<string> = new Set();
29
+
30
+ loadArtifact(artifact: PolicyArtifact, pinnedPkHex: string): { ok: boolean; error?: string } {
31
+ this.state = 'ARTIFACT_VERIFICATION';
32
+ const { signature, ...unsigned } = artifact;
33
+ if (!verifyStr(b64ToSig(signature), canonicalize(unsigned), hexToPk(pinnedPkHex))) {
34
+ this.state = 'TERMINATED'; return { ok: false, error: 'Signature verification failed' };
35
+ }
36
+ if (!isWithinPeriod(utcNow(), artifact.effective_timestamp, artifact.expiration_timestamp)) {
37
+ this.state = 'TERMINATED'; return { ok: false, error: 'Artifact outside effective period' };
38
+ }
39
+ if (this.revocations.has(artifact.sealed_hash)) {
40
+ this.state = 'TERMINATED'; return { ok: false, error: 'Artifact has been revoked' };
41
+ }
42
+ this.artifact = artifact;
43
+ this.state = 'ACTIVE_MONITORING';
44
+ return { ok: true };
45
+ }
46
+
47
+ measure(subjectBytes: Uint8Array, meta: SubjectMetadata): MeasurementResult {
48
+ if (!this.artifact) throw new Error('No artifact loaded');
49
+ if (this.state === 'TERMINATED') throw new Error('Portal is terminated');
50
+ const empty = { currentBytesHash: '', currentMetaHash: '',
51
+ expectedBytesHash: this.artifact.subject_identifier.bytes_hash,
52
+ expectedMetaHash: this.artifact.subject_identifier.metadata_hash };
53
+
54
+ // Fail-closed: TTL check
55
+ const ttl_ok = !isExpired(this.artifact.issued_timestamp, this.artifact.enforcement_parameters.ttl_seconds);
56
+ if (!ttl_ok) { this.state = 'TERMINATED'; return { match: false, ttl_ok: false, revoked: false, ...empty }; }
57
+
58
+ // Fail-closed: revocation check
59
+ if (this.revocations.has(this.artifact.sealed_hash)) {
60
+ this.state = 'TERMINATED'; return { match: false, ttl_ok: true, revoked: true, ...empty };
61
+ }
62
+
63
+ const currentBytesHash = sha256Bytes(subjectBytes);
64
+ const currentMetaHash = sha256Str(canonicalize(meta));
65
+ const match = currentBytesHash === this.artifact.subject_identifier.bytes_hash &&
66
+ currentMetaHash === this.artifact.subject_identifier.metadata_hash;
67
+
68
+ if (!match && this.state === 'ACTIVE_MONITORING') this.state = 'DRIFT_DETECTED';
69
+ return { match, currentBytesHash, currentMetaHash,
70
+ expectedBytesHash: this.artifact.subject_identifier.bytes_hash,
71
+ expectedMetaHash: this.artifact.subject_identifier.metadata_hash,
72
+ ttl_ok: true, revoked: false };
73
+ }
74
+
75
+ enforce(action: EnforcementAction): void {
76
+ if (this.state !== 'DRIFT_DETECTED') throw new Error(`Cannot enforce in state ${this.state}`);
77
+ switch (action) {
78
+ case 'TERMINATE': case 'SAFE_STATE': this.state = 'TERMINATED'; break;
79
+ case 'QUARANTINE': this.state = 'PHANTOM_QUARANTINE'; break;
80
+ case 'ALERT_ONLY': this.state = 'ACTIVE_MONITORING'; break;
81
+ default: break;
82
+ }
83
+ }
84
+
85
+ revoke(sealedHash: string): void {
86
+ this.revocations.add(sealedHash);
87
+ if (this.artifact?.sealed_hash === sealedHash) this.state = 'TERMINATED';
88
+ }
89
+
90
+ isRevoked(sealedHash: string): boolean { return this.revocations.has(sealedHash); }
91
+
92
+ reset(): void {
93
+ this.state = 'INITIALIZATION'; this.artifact = null;
94
+ this.sequenceCounter = 0; this.lastLeafHash = null;
95
+ }
96
+ }
@@ -0,0 +1,16 @@
1
+ import { utcNow } from '../utils/timestamp.js';
2
+ import type { QuarantineState } from './types.js';
3
+
4
+ export function initQuarantine(): QuarantineState {
5
+ return { active: true, started_at: utcNow(), inputs_captured: 0, outputs_severed: true, forensic_buffer: [] };
6
+ }
7
+
8
+ export function captureInput(q: QuarantineState, inputType: string, data: unknown): void {
9
+ q.forensic_buffer.push({ timestamp: utcNow(), type: inputType, data });
10
+ q.inputs_captured++;
11
+ }
12
+
13
+ export function releaseQuarantine(q: QuarantineState): { duration_ms: number; total_captures: number } {
14
+ q.active = false;
15
+ return { duration_ms: q.started_at ? Date.now() - Date.parse(q.started_at) : 0, total_captures: q.inputs_captured };
16
+ }
@@ -0,0 +1,33 @@
1
+ /** V3: measurement_type field. Receipts generated for EVERY measurement. */
2
+ import { signStr, sigToB64 } from '../crypto/sign.js';
3
+ import { canonicalize } from '../utils/canonical.js';
4
+ import { utcNow } from '../utils/timestamp.js';
5
+ import { uuid } from '../utils/uuid.js';
6
+ import type { KeyPair, HashHex } from '../crypto/types.js';
7
+ import type { SignedReceipt, SubjectIdentifier, EnforcementAction } from './types.js';
8
+
9
+ export interface ReceiptInput {
10
+ subjectId: SubjectIdentifier;
11
+ artifactRef: HashHex;
12
+ currentHash: string;
13
+ sealedHash: string;
14
+ driftDetected: boolean;
15
+ driftDescription: string | null;
16
+ action: EnforcementAction | null;
17
+ measurementType: string;
18
+ seq: number;
19
+ prevLeaf: HashHex | null;
20
+ portalKP: KeyPair;
21
+ }
22
+
23
+ export function generateReceipt(input: ReceiptInput): SignedReceipt {
24
+ const unsigned = {
25
+ receipt_id: uuid(), subject_identifier: input.subjectId,
26
+ artifact_reference: input.artifactRef, current_hash: input.currentHash,
27
+ sealed_hash: input.sealedHash, drift_detected: input.driftDetected,
28
+ drift_description: input.driftDescription, enforcement_action: input.action,
29
+ measurement_type: input.measurementType, timestamp: utcNow(),
30
+ sequence_number: input.seq, previous_leaf_hash: input.prevLeaf,
31
+ };
32
+ return { ...unsigned, portal_signature: sigToB64(signStr(canonicalize(unsigned), input.portalKP.secretKey)) };
33
+ }
@@ -0,0 +1,11 @@
1
+ import { sha256Bytes, sha256Str } from '../crypto/hash.js';
2
+ import { canonicalize } from '../utils/canonical.js';
3
+ import type { SubjectIdentifier, SubjectMetadata } from './types.js';
4
+
5
+ export function computeSubjectId(bytes: Uint8Array, meta: SubjectMetadata): SubjectIdentifier {
6
+ return { bytes_hash: sha256Bytes(bytes), metadata_hash: sha256Str(canonicalize(meta)) };
7
+ }
8
+
9
+ export function computeSubjectIdFromString(content: string, meta: SubjectMetadata): SubjectIdentifier {
10
+ return computeSubjectId(new TextEncoder().encode(content), meta);
11
+ }
@@ -0,0 +1,244 @@
1
+ /**
2
+ * V3: Aligned with NIST-2025-0035 and NCCoE AI Agent Identity filings.
3
+ * Every interface annotated with patent reference numeral.
4
+ */
5
+ import type { HashHex, SignatureBase64, SaltHex, MerkleInclusionProof } from '../crypto/types.js';
6
+
7
+ // ── Subject (100, 102, 104, 106, 126) ──────────────────────────
8
+
9
+ export interface SubjectIdentifier { // Ref 126
10
+ bytes_hash: HashHex; // Ref 104
11
+ metadata_hash: HashHex; // Ref 106
12
+ }
13
+
14
+ export interface SubjectMetadata {
15
+ filename?: string;
16
+ creation_timestamp?: string;
17
+ author?: string;
18
+ version?: string;
19
+ content_type?: string;
20
+ [key: string]: unknown;
21
+ }
22
+
23
+ // ── Enforcement (130–136, 162–168) ──────────────────────────────
24
+
25
+ export type EnforcementAction =
26
+ | 'TERMINATE' // Ref 162: immediate kill
27
+ | 'QUARANTINE' // Ref 164: phantom execution
28
+ | 'NETWORK_ISOLATE' // Ref 166: sever network, continue local
29
+ | 'SAFE_STATE' // Ref 168: return-to-home / controlled shutdown
30
+ | 'KEY_REVOKE' // invalidate crypto keys
31
+ | 'TOKEN_INVALIDATE' // revoke access tokens
32
+ | 'ACTUATOR_DISCONNECT' // sever physical actuator connections
33
+ | 'ALERT_ONLY'; // log without enforcement (gradual deployment)
34
+
35
+ export type MeasurementType =
36
+ | 'EXECUTABLE_IMAGE' | 'LOADED_MODULES' | 'CONTAINER_IMAGE'
37
+ | 'CONFIG_MANIFEST' | 'SBOM' | 'TEE_QUOTE'
38
+ | 'MEMORY_REGIONS' | 'CONTROL_FLOW' | 'FILE_SYSTEM_STATE'
39
+ | 'NETWORK_CONFIG';
40
+
41
+ export interface EnforcementParams { // Ref 130
42
+ measurement_cadence_ms: number; // Ref 132
43
+ ttl_seconds: number; // Ref 134
44
+ enforcement_triggers: EnforcementAction[]; // Ref 136
45
+ re_attestation_required: boolean;
46
+ measurement_types: MeasurementType[];
47
+ }
48
+
49
+ // ── Policy & Disclosure (112, 138–142) ──────────────────────────
50
+
51
+ export type Sensitivity = 'S1_LOW' | 'S2_MODERATE' | 'S3_HIGH' | 'S4_CRITICAL';
52
+ export type DisclosureMode = 'PROOF_ONLY' | 'REVEAL_MIN' | 'REVEAL_FULL';
53
+
54
+ export interface ClaimRecord { // Ref 140
55
+ claim_id: string;
56
+ sensitivity: Sensitivity;
57
+ substitutes: string[];
58
+ inference_risks: string[];
59
+ permitted_modes: DisclosureMode[];
60
+ }
61
+
62
+ export interface SubstitutionRule { // Ref 142
63
+ original_claim_id: string;
64
+ substitute_claim_id: string;
65
+ conditions: Record<string, unknown>;
66
+ }
67
+
68
+ export interface DisclosurePolicy { // Ref 138
69
+ claims_taxonomy: ClaimRecord[];
70
+ substitution_rules: SubstitutionRule[];
71
+ }
72
+
73
+ // ── Evidence Commitment (114) ───────────────────────────────────
74
+
75
+ export interface EvidenceCommitmentRecord {
76
+ commitment: HashHex;
77
+ salt: SaltHex;
78
+ label: string;
79
+ }
80
+
81
+ // ── Policy Artifact (120, 122, 124, 144) ────────────────────────
82
+
83
+ export interface PolicyArtifact { // Ref 122 (Weave Piece)
84
+ schema_version: string;
85
+ protocol_version: string;
86
+ subject_identifier: SubjectIdentifier;
87
+ policy_reference: HashHex; // Ref 128
88
+ policy_version: number;
89
+ sealed_hash: HashHex; // Ref 124
90
+ seal_salt: SaltHex; // stored for audit
91
+ issued_timestamp: string;
92
+ effective_timestamp: string;
93
+ expiration_timestamp: string | null;
94
+ issuer_identifier: string;
95
+ enforcement_parameters: EnforcementParams;
96
+ disclosure_policy: DisclosurePolicy;
97
+ evidence_commitments: EvidenceCommitmentRecord[];
98
+ signature: SignatureBase64; // Ref 144
99
+ }
100
+
101
+ // ── Receipts (170, 172) ─────────────────────────────────────────
102
+ // V3: Generated for EVERY measurement, not just drift. Per NIST filing:
103
+ // "each measurement generates a signed receipt — match or mismatch"
104
+
105
+ export interface SignedReceipt { // Ref 172
106
+ receipt_id: string;
107
+ subject_identifier: SubjectIdentifier;
108
+ artifact_reference: HashHex;
109
+ current_hash: string;
110
+ sealed_hash: string;
111
+ drift_detected: boolean;
112
+ drift_description: string | null;
113
+ enforcement_action: EnforcementAction | null;
114
+ measurement_type: string; // V3: which measurement was performed
115
+ timestamp: string;
116
+ sequence_number: number;
117
+ previous_leaf_hash: HashHex | null;
118
+ portal_signature: SignatureBase64;
119
+ }
120
+
121
+ // ── Continuity Chain (180–196) ──────────────────────────────────
122
+
123
+ export type EventType =
124
+ | 'GENESIS'
125
+ | 'POLICY_ISSUANCE'
126
+ | 'INTERACTION_RECEIPT'
127
+ | 'REVOCATION' // V3: mid-session revocation
128
+ | 'ATTESTATION'
129
+ | 'ANCHOR_BATCH'
130
+ | 'DISCLOSURE'
131
+ | 'SUBSTITUTION'
132
+ | 'KEY_ROTATION'; // V3: key lifecycle event
133
+
134
+ export interface GenesisPayload {
135
+ protocol_version: string;
136
+ taxonomy_version: string;
137
+ root_fingerprint: string;
138
+ specification_hash: HashHex;
139
+ marker: 'GENESIS';
140
+ }
141
+
142
+ export interface ContinuityEvent { // Ref 184
143
+ schema_version: string;
144
+ protocol_version: string;
145
+ event_type: EventType;
146
+ event_id: string;
147
+ sequence_number: number;
148
+ timestamp: string;
149
+ previous_leaf_hash: HashHex | null;
150
+ leaf_hash: HashHex; // Ref 186
151
+ payload: unknown; // Ref 192
152
+ payload_hash: HashHex; // Ref 194
153
+ event_signature: SignatureBase64; // Ref 196
154
+ }
155
+
156
+ export interface StructuralMetadata { // Ref 190
157
+ schema_version: string;
158
+ protocol_version: string;
159
+ event_type: EventType;
160
+ event_id: string;
161
+ sequence_number: number;
162
+ timestamp: string;
163
+ previous_leaf_hash: HashHex | null;
164
+ }
165
+
166
+ // ── Checkpoints (200–214) ───────────────────────────────────────
167
+
168
+ export interface CheckpointReference {
169
+ merkle_root: HashHex;
170
+ batch_start_sequence: number;
171
+ batch_end_sequence: number;
172
+ anchor_network: string;
173
+ transaction_id: string;
174
+ timestamp: string;
175
+ }
176
+
177
+ export interface AnchorBatchPayload {
178
+ checkpoint_reference: CheckpointReference;
179
+ leaf_count: number;
180
+ }
181
+
182
+ // ── Evidence Bundle (240–246) ───────────────────────────────────
183
+
184
+ export interface EvidenceBundle {
185
+ artifact: PolicyArtifact;
186
+ receipts: SignedReceipt[];
187
+ merkle_proofs: MerkleInclusionProof[];
188
+ checkpoint_reference: CheckpointReference;
189
+ public_key: string;
190
+ bundle_signature: SignatureBase64;
191
+ }
192
+
193
+ // ── Disclosure (250–256) ────────────────────────────────────────
194
+
195
+ export interface DisclosureRequest {
196
+ requested_claim_id: string;
197
+ requester_id: string;
198
+ mode: DisclosureMode;
199
+ timestamp: string;
200
+ }
201
+
202
+ export interface SubstitutionReceipt {
203
+ receipt_id: string;
204
+ original_claim_id: string;
205
+ substitute_claim_id: string | null;
206
+ policy_version: number;
207
+ reason_code: string;
208
+ timestamp: string;
209
+ chain_sequence_ref: number;
210
+ signature: SignatureBase64;
211
+ }
212
+
213
+ // ── Portal State Machine (150, 270–280) ─────────────────────────
214
+
215
+ export type PortalState =
216
+ | 'INITIALIZATION' // Ref 270
217
+ | 'ARTIFACT_VERIFICATION' // Ref 272
218
+ | 'ACTIVE_MONITORING' // Ref 274
219
+ | 'DRIFT_DETECTED' // Ref 276
220
+ | 'PHANTOM_QUARANTINE' // Ref 278
221
+ | 'TERMINATED'; // Ref 280
222
+
223
+ export type VerificationTier = 'BRONZE' | 'SILVER' | 'GOLD';
224
+
225
+ // ── Revocation (V3) ────────────────────────────────────────────
226
+ // Per NCCoE filing Phase 3b: "An administrator pushes a REVOCATION event
227
+ // to the continuity chain, invalidating the agent's active policy artifact."
228
+
229
+ export interface RevocationRecord {
230
+ artifact_sealed_hash: HashHex;
231
+ reason: string;
232
+ revoked_by: string; // issuer pk hex
233
+ timestamp: string;
234
+ }
235
+
236
+ // ── Quarantine (220–230) ────────────────────────────────────────
237
+
238
+ export interface QuarantineState {
239
+ active: boolean;
240
+ started_at: string | null;
241
+ inputs_captured: number;
242
+ outputs_severed: boolean;
243
+ forensic_buffer: Array<{ timestamp: string; type: string; data: unknown }>;
244
+ }
@@ -0,0 +1,33 @@
1
+ import { sha256 } from '@noble/hashes/sha256';
2
+ import { blake2b } from '@noble/hashes/blake2b';
3
+ import { bytesToHex } from '@noble/hashes/utils';
4
+ import type { HashHex } from './types.js';
5
+
6
+ const enc = new TextEncoder();
7
+
8
+ export function sha256Bytes(data: Uint8Array): HashHex {
9
+ return bytesToHex(sha256(data));
10
+ }
11
+
12
+ export function sha256Str(data: string): HashHex {
13
+ return sha256Bytes(enc.encode(data));
14
+ }
15
+
16
+ export function blake2b256(data: Uint8Array): HashHex {
17
+ return bytesToHex(blake2b(data, { dkLen: 32 }));
18
+ }
19
+
20
+ /** Concatenate inputs (NO delimiter) and SHA-256. Patent Section D: "no delimiters." */
21
+ export function sha256Cat(...parts: (Uint8Array | string)[]): HashHex {
22
+ const bufs = parts.map(p => typeof p === 'string' ? enc.encode(p) : p);
23
+ const total = bufs.reduce((n, b) => n + b.length, 0);
24
+ const combined = new Uint8Array(total);
25
+ let off = 0;
26
+ for (const b of bufs) { combined.set(b, off); off += b.length; }
27
+ return sha256Bytes(combined);
28
+ }
29
+
30
+ /** Concatenate hex strings as text (no decode) and hash. For sealed_hash computation. */
31
+ export function sha256HexCat(...hexes: string[]): HashHex {
32
+ return sha256Str(hexes.join(''));
33
+ }
@@ -0,0 +1,5 @@
1
+ export * from './types.js';
2
+ export * from './hash.js';
3
+ export * from './sign.js';
4
+ export * from './salt.js';
5
+ export * from './merkle.js';
@@ -0,0 +1,43 @@
1
+ import { sha256Str } from './hash.js';
2
+ import type { HashHex, MerkleInclusionProof } from './types.js';
3
+
4
+ function pair(l: HashHex, r: HashHex): HashHex { return sha256Str(l + r); }
5
+
6
+ export function buildMerkleTree(leaves: HashHex[]): { root: HashHex; layers: HashHex[][] } {
7
+ if (!leaves.length) throw new Error('Empty leaf set');
8
+ if (leaves.length === 1) return { root: leaves[0], layers: [leaves] };
9
+ const layers: HashHex[][] = [[...leaves]];
10
+ let cur = leaves;
11
+ while (cur.length > 1) {
12
+ const next: HashHex[] = [];
13
+ for (let i = 0; i < cur.length; i += 2) {
14
+ next.push(pair(cur[i], i + 1 < cur.length ? cur[i + 1] : cur[i]));
15
+ }
16
+ layers.push(next);
17
+ cur = next;
18
+ }
19
+ return { root: cur[0], layers };
20
+ }
21
+
22
+ export function inclusionProof(leaves: HashHex[], idx: number): MerkleInclusionProof {
23
+ if (idx < 0 || idx >= leaves.length) throw new RangeError(`Index ${idx} out of [0,${leaves.length})`);
24
+ const { root, layers } = buildMerkleTree(leaves);
25
+ const siblings: MerkleInclusionProof['siblings'] = [];
26
+ let ci = idx;
27
+ for (let L = 0; L < layers.length - 1; L++) {
28
+ const layer = layers[L];
29
+ const isRight = ci % 2 === 1;
30
+ const si = isRight ? ci - 1 : (ci + 1 < layer.length ? ci + 1 : ci);
31
+ siblings.push({ hash: layer[si], position: isRight ? 'left' : 'right' });
32
+ ci = Math.floor(ci / 2);
33
+ }
34
+ return { leafHash: leaves[idx], leafIndex: idx, siblings, root };
35
+ }
36
+
37
+ export function verifyProof(proof: MerkleInclusionProof): boolean {
38
+ let h = proof.leafHash;
39
+ for (const s of proof.siblings) {
40
+ h = s.position === 'left' ? pair(s.hash, h) : pair(h, s.hash);
41
+ }
42
+ return h === proof.root;
43
+ }
@@ -0,0 +1,18 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { bytesToHex } from '@noble/hashes/utils';
3
+ import { sha256Cat } from './hash.js';
4
+ import type { SaltHex, SaltedCommitment, HashHex } from './types.js';
5
+
6
+ const enc = new TextEncoder();
7
+
8
+ export function generateSalt(): SaltHex { return bytesToHex(randomBytes(16)); }
9
+
10
+ export function saltedCommitment(content: Uint8Array | string, salt?: SaltHex): SaltedCommitment {
11
+ const s = salt ?? generateSalt();
12
+ const c = typeof content === 'string' ? enc.encode(content) : content;
13
+ return { commitment: sha256Cat(c, s), salt: s };
14
+ }
15
+
16
+ export function verifySaltedCommitment(content: Uint8Array | string, salt: SaltHex, expected: HashHex): boolean {
17
+ return saltedCommitment(content, salt).commitment === expected;
18
+ }
@@ -0,0 +1,35 @@
1
+ import * as ed from '@noble/ed25519';
2
+ import { sha512 } from '@noble/hashes/sha512';
3
+ import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
4
+ import type { KeyPair, Signature, SignatureBase64 } from './types.js';
5
+
6
+ // Set sha512 sync ONCE at module load
7
+ ed.etc.sha512Sync = (...m: Uint8Array[]) => {
8
+ const total = m.reduce((n, a) => n + a.length, 0);
9
+ const buf = new Uint8Array(total);
10
+ let off = 0;
11
+ for (const a of m) { buf.set(a, off); off += a.length; }
12
+ return sha512(buf);
13
+ };
14
+
15
+ const enc = new TextEncoder();
16
+
17
+ export function generateKeyPair(): KeyPair {
18
+ const secretKey = ed.utils.randomPrivateKey();
19
+ return { publicKey: ed.getPublicKey(secretKey), secretKey };
20
+ }
21
+
22
+ export function sign(msg: Uint8Array, sk: Uint8Array): Signature { return ed.sign(msg, sk); }
23
+ export function signStr(msg: string, sk: Uint8Array): Signature { return sign(enc.encode(msg), sk); }
24
+
25
+ export function verify(sig: Signature, msg: Uint8Array, pk: Uint8Array): boolean {
26
+ try { return ed.verify(sig, msg, pk); } catch { return false; }
27
+ }
28
+ export function verifyStr(sig: Signature, msg: string, pk: Uint8Array): boolean {
29
+ return verify(sig, enc.encode(msg), pk);
30
+ }
31
+
32
+ export const sigToB64 = (s: Signature): SignatureBase64 => Buffer.from(s).toString('base64');
33
+ export const b64ToSig = (b: SignatureBase64): Signature => new Uint8Array(Buffer.from(b, 'base64'));
34
+ export const pkToHex = (pk: Uint8Array): string => bytesToHex(pk);
35
+ export const hexToPk = (h: string): Uint8Array => hexToBytes(h);
@@ -0,0 +1,19 @@
1
+ export type PublicKey = Uint8Array;
2
+ export type SecretKey = Uint8Array;
3
+ export interface KeyPair { publicKey: PublicKey; secretKey: SecretKey; }
4
+ export type Signature = Uint8Array;
5
+ export type HashHex = string;
6
+ export type SignatureBase64 = string;
7
+ export type SaltHex = string;
8
+
9
+ export interface SaltedCommitment {
10
+ commitment: HashHex;
11
+ salt: SaltHex;
12
+ }
13
+
14
+ export interface MerkleInclusionProof {
15
+ leafHash: HashHex;
16
+ leafIndex: number;
17
+ siblings: Array<{ hash: HashHex; position: 'left' | 'right' }>;
18
+ root: HashHex;
19
+ }
package/src/index.ts ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { createAGAServer } from './server.js';
4
+
5
+ async function main() {
6
+ const server = await createAGAServer();
7
+ const transport = new StdioServerTransport();
8
+ await server.connect(transport);
9
+ console.error('AGA MCP Server running on stdio');
10
+ }
11
+
12
+ main().catch(e => { console.error('Fatal:', e); process.exit(1); });