@kernel.chat/kbot-finance 0.2.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 (100) hide show
  1. package/LICENSE +19 -0
  2. package/README.md +188 -0
  3. package/RFC-content-addressed-mcp.md +240 -0
  4. package/dist/adapters/edgar/client.d.ts +11 -0
  5. package/dist/adapters/edgar/client.d.ts.map +1 -0
  6. package/dist/adapters/edgar/client.js +56 -0
  7. package/dist/adapters/edgar/client.js.map +1 -0
  8. package/dist/adapters/edgar/commands.d.ts +27 -0
  9. package/dist/adapters/edgar/commands.d.ts.map +1 -0
  10. package/dist/adapters/edgar/commands.js +56 -0
  11. package/dist/adapters/edgar/commands.js.map +1 -0
  12. package/dist/adapters/edgar/index.d.ts +4 -0
  13. package/dist/adapters/edgar/index.d.ts.map +1 -0
  14. package/dist/adapters/edgar/index.js +4 -0
  15. package/dist/adapters/edgar/index.js.map +1 -0
  16. package/dist/adapters/edgar/types.d.ts +70 -0
  17. package/dist/adapters/edgar/types.d.ts.map +1 -0
  18. package/dist/adapters/edgar/types.js +23 -0
  19. package/dist/adapters/edgar/types.js.map +1 -0
  20. package/dist/adapters/polymarket/client.d.ts +7 -0
  21. package/dist/adapters/polymarket/client.d.ts.map +1 -0
  22. package/dist/adapters/polymarket/client.js +58 -0
  23. package/dist/adapters/polymarket/client.js.map +1 -0
  24. package/dist/adapters/polymarket/commands.d.ts +30 -0
  25. package/dist/adapters/polymarket/commands.d.ts.map +1 -0
  26. package/dist/adapters/polymarket/commands.js +67 -0
  27. package/dist/adapters/polymarket/commands.js.map +1 -0
  28. package/dist/adapters/polymarket/index.d.ts +4 -0
  29. package/dist/adapters/polymarket/index.d.ts.map +1 -0
  30. package/dist/adapters/polymarket/index.js +4 -0
  31. package/dist/adapters/polymarket/index.js.map +1 -0
  32. package/dist/adapters/polymarket/types.d.ts +58 -0
  33. package/dist/adapters/polymarket/types.d.ts.map +1 -0
  34. package/dist/adapters/polymarket/types.js +12 -0
  35. package/dist/adapters/polymarket/types.js.map +1 -0
  36. package/dist/audit-log.d.ts +65 -0
  37. package/dist/audit-log.d.ts.map +1 -0
  38. package/dist/audit-log.js +96 -0
  39. package/dist/audit-log.js.map +1 -0
  40. package/dist/cli.d.ts +3 -0
  41. package/dist/cli.d.ts.map +1 -0
  42. package/dist/cli.js +44 -0
  43. package/dist/cli.js.map +1 -0
  44. package/dist/demo.d.ts +11 -0
  45. package/dist/demo.d.ts.map +1 -0
  46. package/dist/demo.js +133 -0
  47. package/dist/demo.js.map +1 -0
  48. package/dist/envelope.d.ts +71 -0
  49. package/dist/envelope.d.ts.map +1 -0
  50. package/dist/envelope.js +83 -0
  51. package/dist/envelope.js.map +1 -0
  52. package/dist/exporters/annex-iv.d.ts +40 -0
  53. package/dist/exporters/annex-iv.d.ts.map +1 -0
  54. package/dist/exporters/annex-iv.js +154 -0
  55. package/dist/exporters/annex-iv.js.map +1 -0
  56. package/dist/governance.d.ts +55 -0
  57. package/dist/governance.d.ts.map +1 -0
  58. package/dist/governance.js +73 -0
  59. package/dist/governance.js.map +1 -0
  60. package/dist/index.d.ts +32 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +32 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/kbot-tool.d.ts +31 -0
  65. package/dist/kbot-tool.d.ts.map +1 -0
  66. package/dist/kbot-tool.js +325 -0
  67. package/dist/kbot-tool.js.map +1 -0
  68. package/dist/mcp-server.d.ts +25 -0
  69. package/dist/mcp-server.d.ts.map +1 -0
  70. package/dist/mcp-server.js +80 -0
  71. package/dist/mcp-server.js.map +1 -0
  72. package/dist/tools/edgar-query.d.ts +36 -0
  73. package/dist/tools/edgar-query.d.ts.map +1 -0
  74. package/dist/tools/edgar-query.js +108 -0
  75. package/dist/tools/edgar-query.js.map +1 -0
  76. package/dist/tools/polymarket-query.d.ts +55 -0
  77. package/dist/tools/polymarket-query.d.ts.map +1 -0
  78. package/dist/tools/polymarket-query.js +128 -0
  79. package/dist/tools/polymarket-query.js.map +1 -0
  80. package/dist/verifier/eu-rts6.d.ts +3 -0
  81. package/dist/verifier/eu-rts6.d.ts.map +1 -0
  82. package/dist/verifier/eu-rts6.js +45 -0
  83. package/dist/verifier/eu-rts6.js.map +1 -0
  84. package/dist/verifier/index.d.ts +67 -0
  85. package/dist/verifier/index.d.ts.map +1 -0
  86. package/dist/verifier/index.js +22 -0
  87. package/dist/verifier/index.js.map +1 -0
  88. package/dist/verifier/kelly-cap.d.ts +19 -0
  89. package/dist/verifier/kelly-cap.d.ts.map +1 -0
  90. package/dist/verifier/kelly-cap.js +64 -0
  91. package/dist/verifier/kelly-cap.js.map +1 -0
  92. package/dist/verifier/model-version.d.ts +3 -0
  93. package/dist/verifier/model-version.d.ts.map +1 -0
  94. package/dist/verifier/model-version.js +28 -0
  95. package/dist/verifier/model-version.js.map +1 -0
  96. package/dist/verifier/position-limit.d.ts +21 -0
  97. package/dist/verifier/position-limit.d.ts.map +1 -0
  98. package/dist/verifier/position-limit.js +42 -0
  99. package/dist/verifier/position-limit.js.map +1 -0
  100. package/package.json +101 -0
package/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+
17
+ Copyright 2026 kernel.chat contributors
18
+
19
+ Full license text: https://www.apache.org/licenses/LICENSE-2.0
package/README.md ADDED
@@ -0,0 +1,188 @@
1
+ # @kernel.chat/kbot-finance
2
+
3
+ **Audit-grade AI infrastructure for capital markets.**
4
+
5
+ The AI Intelligence Layer never produces the number. The deterministic engine does.
6
+ Every action is content-addressed, every step is hash-chained, every approval is signed.
7
+
8
+ Apache 2.0. Node 22+. Replit-importable.
9
+
10
+ ---
11
+
12
+ ## What this is
13
+
14
+ A reference implementation of three layers that together form an
15
+ AI-Native Capital Markets Operating System:
16
+
17
+ 1. **Deterministic engine adapters** — call known-good engines (Polymarket
18
+ Gamma in v0.1; QuantLib, NautilusTrader, Aeron, alts-NAV in later versions).
19
+ The AI agent cannot compute the number — it can only request one inside a
20
+ content-addressed envelope.
21
+
22
+ 2. **Regulatory verifier** — Norm-AI-pattern rules-as-code. Every action
23
+ passes through before reaching the engine. Failures emit adverse-action
24
+ reason codes. Jurisdiction-aware (US, EU, UK, SG, HK, UAE, GLOBAL).
25
+
26
+ 3. **Hash-chained audit log** — append-only, WORM-compatible. Every
27
+ verifier check, engine request, engine response, approval, and incident
28
+ is recorded with a hash linking it to the previous entry. Tampering
29
+ anywhere invalidates everything after.
30
+
31
+ Plus a **material-gate approval substrate** for actions that require a signed
32
+ human approver token before execution.
33
+
34
+ ## Try it on Replit
35
+
36
+ This subdirectory is self-contained. Import the repo into Replit and the
37
+ first `Run` will:
38
+
39
+ 1. `npm install`
40
+ 2. `npm run demo` — runs the end-to-end flow against the live Polymarket
41
+ Gamma API, prints the audit log, verifies the hash chain.
42
+
43
+ No keys, no setup. Public API only.
44
+
45
+ ## Run locally
46
+
47
+ ```bash
48
+ cd packages/kbot-finance
49
+ npm install
50
+ npm run demo # live end-to-end
51
+ npm test # unit + integration
52
+ npm run test:live # explicit live-smoke against Gamma
53
+ KBOT_FINANCE_OFFLINE=1 npm test # CI without network
54
+ ```
55
+
56
+ ## Architecture (one diagram)
57
+
58
+ ```
59
+ ┌──────────────────────────────────────────────────────────────────┐
60
+ │ AI Intelligence Layer (kbot agent calls polymarketQuery(...)) │
61
+ └─────────────┬────────────────────────────────────────────────────┘
62
+ │ content-addressed request envelope
63
+
64
+ ┌──────────────────────────────────────────────────────────────────┐
65
+ │ Regulatory Verifier (rules-as-code, jurisdiction-aware) │
66
+ └─────────────┬────────────────────────────────────────────────────┘
67
+ │ pass / adverse-action reason code
68
+
69
+ ┌──────────────────────────────────────────────────────────────────┐
70
+ │ Material-Gate Approval (signed token, if action is material) │
71
+ └─────────────┬────────────────────────────────────────────────────┘
72
+
73
+
74
+ ┌──────────────────────────────────────────────────────────────────┐
75
+ │ Deterministic Engine Adapter (Polymarket Gamma in v0.1) │
76
+ └─────────────┬────────────────────────────────────────────────────┘
77
+ │ sealed envelope: { request_hash, engine_version, value, ... }
78
+
79
+ ┌──────────────────────────────────────────────────────────────────┐
80
+ │ Hash-Chained Audit Log (append-only, replayable, WORM-ready) │
81
+ └──────────────────────────────────────────────────────────────────┘
82
+ ```
83
+
84
+ ## Public API
85
+
86
+ ```ts
87
+ import {
88
+ // Content addressing
89
+ canonicalize,
90
+ requestHash,
91
+ sealEnvelope,
92
+ // Audit
93
+ AppendOnlyAuditLog,
94
+ // Governance
95
+ Approver,
96
+ verifyApproval,
97
+ // Verifier
98
+ runVerifier,
99
+ makePositionLimitRule,
100
+ makeKellyCapRule,
101
+ // Engines
102
+ polymarket,
103
+ // Tools
104
+ polymarketQuery,
105
+ } from "@kernel.chat/kbot-finance";
106
+ ```
107
+
108
+ ## What v0.1 demonstrates
109
+
110
+ - **Content addressing.** Two calls with logically identical inputs produce
111
+ byte-identical `request_hash`. Independent of object key order.
112
+ - **Audit-log integrity.** Tampering with any entry is detectable by
113
+ `AppendOnlyAuditLog.verify()`. Concurrent appends serialize correctly.
114
+ - **Verifier short-circuit.** A rule rejection prevents the engine call
115
+ entirely; the failure is logged with an adverse-action code.
116
+ - **Honesty primitive.** `byte_identical_replayable: false` on the Polymarket
117
+ envelope — markets move; the live Gamma API is not deterministic at the
118
+ block level. A future adapter that pins to a Goldsky/Graph snapshot will
119
+ flip this flag to `true`.
120
+ - **Approval tokens.** HMAC-signed (Ed25519 in v0.2), bound to the exact
121
+ request_hash + materiality + summary the approver saw.
122
+
123
+ ## What v0.1 deliberately does NOT do
124
+
125
+ - No trading / signing / order placement on Polymarket. Read-only. Write
126
+ comes after the audit primitives are proven.
127
+ - No deterministic floating-point. QuantLib + CRlibm integration lands in
128
+ v0.2 when the rates/alts adapters arrive.
129
+ - No on-chain proofs. zk-STARK-verified compute against a Goldsky subgraph
130
+ is the v3 audit primitive; v0.1 is HTTPS + content-hash.
131
+ - No MCP server wrapper. v0.2 ships an MCP server that exposes
132
+ `polymarket_query` to any MCP client (Claude Code, Cursor, kbot core).
133
+
134
+ ## Layout
135
+
136
+ ```
137
+ src/
138
+ envelope.ts # canonical JSON + SHA-256 + sealEnvelope()
139
+ audit-log.ts # hash-chained append-only log + verify()
140
+ governance.ts # Approver + verifyApproval()
141
+ verifier/
142
+ index.ts # Rule + VerifierContext + runVerifier()
143
+ position-limit.ts # Pre-trade size + notional caps (Rule 15c3-5 echo)
144
+ kelly-cap.ts # Half-Kelly position-sizing cap
145
+ adapters/
146
+ polymarket/
147
+ types.ts # Gamma API + outcome union types
148
+ client.ts # HTTPS client; never throws across boundary
149
+ commands.ts # listMarkets / getMarket / listEvents
150
+ index.ts
151
+ tools/
152
+ polymarket-query.ts # The kbot-shaped tool wiring all layers
153
+ demo.ts # End-to-end script (npm run demo)
154
+ index.ts # Public surface
155
+ test/
156
+ envelope.test.ts
157
+ audit-log.test.ts
158
+ verifier.test.ts
159
+ governance.test.ts
160
+ polymarket.live.test.ts # LIVE SMOKE — hits real Gamma
161
+ ```
162
+
163
+ ## Strategic positioning
164
+
165
+ This is the open-source counter to Palantir AIP: same architectural pattern
166
+ (deterministic substrate + AI orchestration + governance), but MIT/Apache
167
+ core, BYOK, MCP-native, lower price floor, developer-first.
168
+
169
+ Bloomberg ASKB shipped the "AI emits engine query, engine produces number"
170
+ pattern (BQL emission) in Feb 2026. That pattern, generalized, is the
171
+ content-addressed envelope. ASKB picked their own proprietary engine; this
172
+ package picks open ones and ships the **deterministic-replay MCP extension
173
+ spec MCP currently lacks**.
174
+
175
+ The 12-18 month window is the gap between *Bloomberg validates the pattern*
176
+ (done) and *first nine-figure AI enforcement action lands* (H2 2026 - H1 2027).
177
+ After that, the spec freezes around whoever shipped first.
178
+
179
+ ## License
180
+
181
+ Apache 2.0. Built to underpin commercial premium offerings (SOC 2, hosted
182
+ replay-retention, certified determinism) — the Aeron / PyKX dual-shape.
183
+
184
+ ## Status
185
+
186
+ v0.1 reference implementation. Not yet certified for production trading.
187
+ Not investment advice. Not affiliated with Polymarket, Bloomberg, FINOS,
188
+ ISDA, or any regulator.
@@ -0,0 +1,240 @@
1
+ # RFC: Content-Addressed Request Envelope for MCP
2
+
3
+ **Status:** Draft 0.1
4
+ **Author:** kbot-finance contributors (@kernel.chat)
5
+ **Date:** 2026-05-10
6
+ **Reference implementation:** `@kernel.chat/kbot-finance` v0.2.0
7
+
8
+ ## Abstract
9
+
10
+ This RFC proposes a small, optional extension to the Model Context Protocol
11
+ (MCP) that gives MCP tool calls **deterministic replay semantics**.
12
+
13
+ Every MCP request/response pair carries an opaque envelope containing a
14
+ content-addressed hash over canonicalized inputs, a pinned engine version,
15
+ and a data-as-of timestamp. Identical envelopes resolve to identical
16
+ responses, byte-for-byte, when the underlying engine is deterministic.
17
+
18
+ The envelope is **additive**: clients and servers that don't implement
19
+ the extension continue to work. Servers that opt in expose a `replay(hash)`
20
+ tool and emit envelope metadata alongside every tool result.
21
+
22
+ ## Motivation
23
+
24
+ MCP is on track to be the agent-tool protocol that wins (~9,400 servers,
25
+ adopted by Anthropic, OpenAI, Microsoft, Google as of April 2026). It has
26
+ the right shape for tool-use composition across models and clients.
27
+
28
+ It lacks one primitive: **auditable, replayable tool calls**. This matters
29
+ for any deployment in a regulated industry — capital markets, healthcare,
30
+ legal, defense, drug discovery, tax. Today, an MCP client invoking a tool
31
+ gets back a result with no canonical replay key. If a regulator later asks
32
+ "what did the agent see when it made that decision," the answer is
33
+ "we have a log, sort of, but we can't deterministically reconstruct the
34
+ exact tool call." That's insufficient for SR 26-02, EU AI Act Annex IV,
35
+ MiFID II RTS 6, FINRA 2026 ROR, FCA SS1/23, and the converging US AI
36
+ oversight regime that follows the inter-agency RFI on agentic AI.
37
+
38
+ Bloomberg ASKB (Feb 2026) ships this pattern internally: agents emit BQL
39
+ code, the BQL engine produces the number, and the output is replayable
40
+ inside the Terminal. Closed, proprietary. This RFC is the open
41
+ equivalent.
42
+
43
+ ## Non-goals
44
+
45
+ - Replace MCP's existing tool schema or JSON-RPC transport.
46
+ - Mandate determinism in the tool implementation. Tools may emit
47
+ `byte_identical_replayable: false` truthfully — the envelope still
48
+ carries the request hash for audit, just without a replay guarantee.
49
+ - Specify cryptographic algorithms beyond SHA-256. Implementations
50
+ may upgrade to BLAKE3, SHA-3, or post-quantum hashes by emitting
51
+ a hash-algorithm tag.
52
+
53
+ ## Specification
54
+
55
+ ### Envelope structure
56
+
57
+ Servers implementing the extension expose two metadata fields on every
58
+ tool response:
59
+
60
+ ```jsonc
61
+ {
62
+ // ...standard MCP CallToolResult fields...
63
+ "_meta": {
64
+ "kbot-finance/content-addressed": {
65
+ "version": "0.1",
66
+ "request_hash": "<64-hex SHA-256>",
67
+ "engine_version": "<vendor-defined string>",
68
+ "schema_hash": "<64-hex SHA-256 over the tool's JSON schema>",
69
+ "data_as_of": "<ISO 8601 UTC timestamp>",
70
+ "produced_at": "<ISO 8601 UTC timestamp>",
71
+ "byte_identical_replayable": true | false,
72
+ "deterministic_seed": "<optional hex string>"
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ ### Canonical hashing
79
+
80
+ `request_hash` is computed as:
81
+
82
+ ```
83
+ SHA-256(canonicalize({
84
+ operation: <tool name>,
85
+ engine_version,
86
+ schema_hash,
87
+ inputs: <tool args>,
88
+ data_as_of,
89
+ deterministic_seed? // present iff supplied
90
+ }))
91
+ ```
92
+
93
+ `canonicalize()` is RFC 8785 JSON Canonicalization Scheme (JCS), with the
94
+ additional constraint that **non-finite numbers (NaN, ±Infinity) and
95
+ `undefined` values MUST cause hashing to fail**, not be silently elided.
96
+
97
+ ### `replay` tool
98
+
99
+ Servers implementing the extension SHOULD expose a tool named `replay`:
100
+
101
+ ```jsonc
102
+ {
103
+ "name": "replay",
104
+ "description": "Re-execute a prior request by hash and return the byte-identical result, or report a mismatch.",
105
+ "inputSchema": {
106
+ "type": "object",
107
+ "properties": {
108
+ "request_hash": { "type": "string", "description": "The hash returned by a prior call." }
109
+ },
110
+ "required": ["request_hash"]
111
+ }
112
+ }
113
+ ```
114
+
115
+ Replay returns either:
116
+
117
+ - The original sealed envelope, byte-identical to the prior call, when the
118
+ server's audit log retains the request and the engine is deterministic
119
+ for that request; or
120
+ - A `replay_mismatch` error with details when the request is known but the
121
+ current engine cannot reproduce it (e.g., the engine version was rotated,
122
+ the data snapshot expired).
123
+
124
+ ### `byte_identical_replayable: false` is normative, not a bug
125
+
126
+ A truthful `false` declaration is part of the audit story. Live HTTPS APIs
127
+ (Polymarket Gamma, SEC EDGAR's `recent` table), non-deterministic GPU
128
+ inference, and any tool whose backing engine isn't bit-stable MUST emit
129
+ `byte_identical_replayable: false`. The audit log still records the hash
130
+ and the response; replay is just not byte-guaranteed.
131
+
132
+ The "honesty primitive" is a hard rule: a server claiming `true` when it
133
+ cannot deliver byte-identical replay is non-conformant.
134
+
135
+ ### Audit log compatibility
136
+
137
+ The extension does not require a particular audit log shape. The reference
138
+ implementation uses a hash-chained append-only JSONL log with the
139
+ following entry shape:
140
+
141
+ ```jsonc
142
+ {
143
+ "seq": <monotonic>,
144
+ "timestamp": "<ISO 8601>",
145
+ "action": "engine_request" | "engine_response" | "verifier_check" | "incident" | "replay_request" | "replay_verified" | "replay_mismatch" | "approval_granted" | "approval_denied",
146
+ "subject": "<tool name>",
147
+ "session_id": "<client-chosen>",
148
+ "payload": { ... },
149
+ "prev_hash": "<64-hex SHA-256 of the previous entry, or all-zeros for genesis>",
150
+ "self_hash": "<64-hex SHA-256 of this entry without self_hash>"
151
+ }
152
+ ```
153
+
154
+ Tampering with any entry breaks the chain at that entry and at every
155
+ subsequent entry, detectable in `O(n)` time by walking the log.
156
+
157
+ ### Capability advertisement
158
+
159
+ Servers implementing the extension advertise via the standard MCP
160
+ capabilities negotiation:
161
+
162
+ ```jsonc
163
+ {
164
+ "capabilities": {
165
+ "tools": {},
166
+ "experimental": {
167
+ "kbot-finance/content-addressed": { "version": "0.1" }
168
+ }
169
+ }
170
+ }
171
+ ```
172
+
173
+ Clients that don't recognise the experimental capability ignore the
174
+ `_meta` block harmlessly.
175
+
176
+ ## Reference implementation
177
+
178
+ `@kernel.chat/kbot-finance` v0.2.0 ships:
179
+
180
+ - `sealEnvelope()` — wraps an engine call, computes the hash, returns
181
+ the envelope.
182
+ - `AppendOnlyAuditLog` — hash-chained log with `verify()` for integrity
183
+ checks.
184
+ - `mcp-server.ts` — MCP server that exposes audit-grade tools
185
+ (`polymarket_query`, `edgar_query`, `annex_iv_export`,
186
+ `audit_log_verify`) using this envelope shape.
187
+
188
+ Install: `npm install @kernel.chat/kbot-finance`
189
+ Run: `npx @kernel.chat/kbot-finance mcp`
190
+
191
+ ## Security considerations
192
+
193
+ - **Hash collisions.** SHA-256 collision resistance is ~2^128. Adequate
194
+ for the audit horizon of regulated industries (10 years per EU AI Act
195
+ Art. 19). Post-quantum upgrades should swap to SHA-3-256 or BLAKE3
196
+ via an explicit `hash_algorithm` field.
197
+ - **Replay attacks.** The envelope is a *content identifier*, not an
198
+ authentication token. Replay of a known hash in a different session
199
+ is not a security issue at the envelope layer — session authentication
200
+ remains the client's responsibility.
201
+ - **Privacy.** Canonicalized inputs may contain sensitive data. Audit
202
+ log storage MUST respect the same access controls as the inputs
203
+ themselves. The hash itself reveals nothing about the inputs.
204
+ - **Side-channel determinism.** Bit-identical replay across hardware
205
+ (x86 vs ARM, AVX-512 vs not, GPU vs CPU) requires pinned-architecture
206
+ execution or correctly-rounded math (CRlibm, sleef). Servers that
207
+ cannot pin their execution environment MUST emit
208
+ `byte_identical_replayable: false`.
209
+
210
+ ## Backwards compatibility
211
+
212
+ The extension is purely additive. MCP clients that don't recognise the
213
+ `_meta.kbot-finance/content-addressed` block ignore it. Servers that
214
+ don't implement the extension are fully conformant MCP servers.
215
+
216
+ ## Open questions
217
+
218
+ 1. **Hash algorithm agility.** Should the spec require a `hash_algorithm`
219
+ tag from day one, even if v0.1 only supports SHA-256?
220
+ 2. **Replay tool naming.** Is `replay` too generic? Alternatives:
221
+ `audit_replay`, `__replay`, `mcp.replay`.
222
+ 3. **Audit log shape standardization.** Should the audit log entry
223
+ format be in the spec, or left to implementations?
224
+ 4. **Capability negotiation.** Does the `experimental.` prefix slow
225
+ adoption, or is it the right caution for v0.1?
226
+
227
+ ## Acknowledgements
228
+
229
+ - Anthropic, for MCP itself.
230
+ - Bloomberg ASKB, for shipping the pattern in closed form and proving the
231
+ buyer demand.
232
+ - Adaptive Financial Consulting (Aeron), whose deterministic-replay
233
+ primitives in financial messaging inspired the audit log shape.
234
+ - The FINOS AI Governance Framework v2.0 working group, whose risk
235
+ catalog informed the audit log entry types.
236
+
237
+ ## License
238
+
239
+ This RFC is published under CC BY 4.0. The reference implementation is
240
+ Apache 2.0.
@@ -0,0 +1,11 @@
1
+ import { type EdgarOutcome } from "./types.js";
2
+ /**
3
+ * EDGAR HTTPS client. Returns discriminated unions; never throws across
4
+ * the boundary. SEC requires a User-Agent that identifies the requester;
5
+ * we send one by default and let operators override via env.
6
+ */
7
+ export declare function edgarGet<T>(path: string, options?: {
8
+ baseUrl?: string;
9
+ timeoutMs?: number;
10
+ }): Promise<EdgarOutcome<T>>;
11
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/adapters/edgar/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,KAAK,YAAY,EAAmB,MAAM,YAAY,CAAC;AAEtG;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACrD,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CA6C1B"}
@@ -0,0 +1,56 @@
1
+ import { EDGAR_SUBMISSIONS_BASE, getUserAgent } from "./types.js";
2
+ /**
3
+ * EDGAR HTTPS client. Returns discriminated unions; never throws across
4
+ * the boundary. SEC requires a User-Agent that identifies the requester;
5
+ * we send one by default and let operators override via env.
6
+ */
7
+ export async function edgarGet(path, options = {}) {
8
+ const base = options.baseUrl ?? EDGAR_SUBMISSIONS_BASE;
9
+ const url = new URL(path.startsWith("/") ? path : "/" + path, base);
10
+ const userAgent = getUserAgent();
11
+ if (!userAgent || userAgent.trim().length === 0) {
12
+ return err({
13
+ code: "missing_user_agent",
14
+ message: "Set KBOT_FINANCE_SEC_UA to a descriptive contact string per SEC fair-use policy.",
15
+ });
16
+ }
17
+ const controller = new AbortController();
18
+ const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? 15_000);
19
+ try {
20
+ const res = await fetch(url, {
21
+ method: "GET",
22
+ headers: {
23
+ Accept: "application/json",
24
+ "User-Agent": userAgent,
25
+ "Accept-Encoding": "gzip, deflate",
26
+ },
27
+ signal: controller.signal,
28
+ });
29
+ if (res.status === 404) {
30
+ return err({ code: "not_found", message: `404 ${url.pathname}`, status: 404 });
31
+ }
32
+ if (res.status === 429) {
33
+ return err({ code: "rate_limited", message: "429 from EDGAR", status: 429 });
34
+ }
35
+ if (!res.ok) {
36
+ return err({ code: "http", message: `HTTP ${res.status}`, status: res.status });
37
+ }
38
+ try {
39
+ const value = (await res.json());
40
+ return { ok: true, value };
41
+ }
42
+ catch (parseErr) {
43
+ return err({ code: "parse", message: `JSON parse failed: ${parseErr.message}` });
44
+ }
45
+ }
46
+ catch (netErr) {
47
+ return err({ code: "network", message: netErr.message });
48
+ }
49
+ finally {
50
+ clearTimeout(timeout);
51
+ }
52
+ }
53
+ function err(error) {
54
+ return { ok: false, error };
55
+ }
56
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/adapters/edgar/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAsC,MAAM,YAAY,CAAC;AAEtG;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAAY,EACZ,UAAoD,EAAE;IAEtD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,IAAI,sBAAsB,CAAC;IACvD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC;IAEpE,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IACjC,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,GAAG,CAAC;YACT,IAAI,EAAE,oBAAoB;YAC1B,OAAO,EAAE,kFAAkF;SAC5F,CAAC,CAAC;IACL,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC,CAAC;IAElF,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC3B,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,MAAM,EAAE,kBAAkB;gBAC1B,YAAY,EAAE,SAAS;gBACvB,iBAAiB,EAAE,eAAe;aACnC;YACD,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACjF,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAC;YACtC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAC7B,CAAC;QAAC,OAAO,QAAQ,EAAE,CAAC;YAClB,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,sBAAuB,QAAkB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAG,MAAgB,CAAC,OAAO,EAAE,CAAC,CAAC;IACtE,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED,SAAS,GAAG,CAAC,KAAiB;IAC5B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { type EdgarOutcome, type EdgarSubmissionsResponse, type EdgarCompanyFactsResponse } from "./types.js";
2
+ /**
3
+ * Read-only commands against SEC EDGAR.
4
+ *
5
+ * Filings are immutable by SEC policy — every filing has a stable accession
6
+ * number — so content-addressing is essentially native. The adapter returns
7
+ * raw responses; the kbot tool layer computes envelopes over them.
8
+ */
9
+ export declare function getSubmissions(cik: string | number): Promise<EdgarOutcome<EdgarSubmissionsResponse>>;
10
+ export declare function getCompanyFacts(cik: string | number): Promise<EdgarOutcome<EdgarCompanyFactsResponse>>;
11
+ export interface NormalizedFiling {
12
+ readonly accession_number: string;
13
+ readonly filing_date: string | null;
14
+ readonly report_date: string | null;
15
+ readonly form: string;
16
+ readonly primary_document: string | null;
17
+ readonly description: string | null;
18
+ readonly is_xbrl: boolean;
19
+ readonly archive_url: string;
20
+ }
21
+ /**
22
+ * Flatten EDGAR's column-oriented `recent` table into rows. Filings are
23
+ * presented oldest-last in EDGAR's response; we preserve that order so the
24
+ * caller can pick recent N consistently.
25
+ */
26
+ export declare function normalizeRecentFilings(response: EdgarSubmissionsResponse, cik: string | number, limit?: number): ReadonlyArray<NormalizedFiling>;
27
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../src/adapters/edgar/commands.ts"],"names":[],"mappings":"AACA,OAAO,EAAU,KAAK,YAAY,EAAE,KAAK,wBAAwB,EAAE,KAAK,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAEtH;;;;;;GAMG;AAEH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,GAAG,MAAM,GACnB,OAAO,CAAC,YAAY,CAAC,wBAAwB,CAAC,CAAC,CAGjD;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,GAAG,MAAM,GACnB,OAAO,CAAC,YAAY,CAAC,yBAAyB,CAAC,CAAC,CAGlD;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,wBAAwB,EAClC,GAAG,EAAE,MAAM,GAAG,MAAM,EACpB,KAAK,SAAK,GACT,aAAa,CAAC,gBAAgB,CAAC,CA8BjC"}
@@ -0,0 +1,56 @@
1
+ import { edgarGet } from "./client.js";
2
+ import { padCik } from "./types.js";
3
+ /**
4
+ * Read-only commands against SEC EDGAR.
5
+ *
6
+ * Filings are immutable by SEC policy — every filing has a stable accession
7
+ * number — so content-addressing is essentially native. The adapter returns
8
+ * raw responses; the kbot tool layer computes envelopes over them.
9
+ */
10
+ export async function getSubmissions(cik) {
11
+ const padded = padCik(cik);
12
+ return edgarGet(`/submissions/CIK${padded}.json`);
13
+ }
14
+ export async function getCompanyFacts(cik) {
15
+ const padded = padCik(cik);
16
+ return edgarGet(`/api/xbrl/companyfacts/CIK${padded}.json`);
17
+ }
18
+ /**
19
+ * Flatten EDGAR's column-oriented `recent` table into rows. Filings are
20
+ * presented oldest-last in EDGAR's response; we preserve that order so the
21
+ * caller can pick recent N consistently.
22
+ */
23
+ export function normalizeRecentFilings(response, cik, limit = 25) {
24
+ const recent = response.filings?.recent;
25
+ if (!recent)
26
+ return [];
27
+ const accs = recent.accessionNumber ?? [];
28
+ const dates = recent.filingDate ?? [];
29
+ const reports = recent.reportDate ?? [];
30
+ const forms = recent.form ?? [];
31
+ const docs = recent.primaryDocument ?? [];
32
+ const descs = recent.primaryDocDescription ?? [];
33
+ const xbrl = recent.isXBRL ?? [];
34
+ const cikStr = padCik(cik).replace(/^0+/, "");
35
+ const out = [];
36
+ const count = Math.min(accs.length, limit);
37
+ for (let i = 0; i < count; i++) {
38
+ const acc = accs[i];
39
+ if (!acc)
40
+ continue;
41
+ const accNoDashes = acc.replace(/-/g, "");
42
+ const doc = docs[i] ?? "";
43
+ out.push({
44
+ accession_number: acc,
45
+ filing_date: dates[i] ?? null,
46
+ report_date: reports[i] ?? null,
47
+ form: forms[i] ?? "",
48
+ primary_document: doc.length > 0 ? doc : null,
49
+ description: descs[i] ?? null,
50
+ is_xbrl: (xbrl[i] ?? 0) === 1,
51
+ archive_url: `https://www.sec.gov/Archives/edgar/data/${cikStr}/${accNoDashes}/${doc}`,
52
+ });
53
+ }
54
+ return out;
55
+ }
56
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../../src/adapters/edgar/commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,MAAM,EAAoF,MAAM,YAAY,CAAC;AAEtH;;;;;;GAMG;AAEH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAoB;IAEpB,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,QAAQ,CAA2B,mBAAmB,MAAM,OAAO,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAoB;IAEpB,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,QAAQ,CAA4B,6BAA6B,MAAM,OAAO,CAAC,CAAC;AACzF,CAAC;AAaD;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAAkC,EAClC,GAAoB,EACpB,KAAK,GAAG,EAAE;IAEV,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACxC,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IACvB,MAAM,IAAI,GAAG,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;IACtC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,qBAAqB,IAAI,EAAE,CAAC;IACjD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;IACjC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAuB,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1B,GAAG,CAAC,IAAI,CAAC;YACP,gBAAgB,EAAE,GAAG;YACrB,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI;YAC7B,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI;YAC/B,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;YACpB,gBAAgB,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI;YAC7C,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI;YAC7B,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;YAC7B,WAAW,EAAE,2CAA2C,MAAM,IAAI,WAAW,IAAI,GAAG,EAAE;SACvF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from "./types.js";
2
+ export * from "./commands.js";
3
+ export { edgarGet } from "./client.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/edgar/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from "./types.js";
2
+ export * from "./commands.js";
3
+ export { edgarGet } from "./client.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/edgar/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}