diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/RIGHTS.md b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/RIGHTS.md new file mode 100644 index 0000000..27e31f4 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/RIGHTS.md @@ -0,0 +1,14 @@ +# Submission rights declaration + +Project: `BHRIGU Bitcoin Temporal Evidence` +Submission slug: `bhrigu-bitcoin-research-state-api` +Submitter: `Yulchiev A.Kh` +Date: `2026-09-10` + +The submitter confirms that they own, or have sufficient authorization for, the source code, service, frozen public research baselines, durable evidence records, BHRIGU branding used in this package, and other materials submitted in this pull request. + +Subject to the official program terms, the submitter authorizes X-Agent to retain, reproduce, audit, test, archive, and publish the submitted program artifact for judging, fraud prevention, dispute handling, ecosystem submission, and post-award accountability. Closing the pull request, deleting a fork, or deleting an external repository does not revoke the official archive rights attached to an accepted and rewarded entry. + +Third-party components and their licenses: no bundled runtime dependencies. The service uses the Node.js runtime and calls public Binance market-data and mempool.space endpoints subject to their respective terms. See `source/THIRD_PARTY.md`. + +Exceptions or restrictions: authorization covers only the bounded source and materials actually present in this submission directory. ORION, private prompts, planners, evaluators, private corpora, unpublished research methods, credentials, wallet/payment code, and other protected BHRIGU internals are not included in the artifact and are not submitted. diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/SUBMISSION.md b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/SUBMISSION.md new file mode 100644 index 0000000..f732141 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/SUBMISSION.md @@ -0,0 +1,56 @@ +# BHRIGU Bitcoin Temporal Evidence + +## Capability + +- **One-line description:** Lets an AI agent read what Bitcoin evidence was fixed before a declared future boundary, compare it with live reality after the boundary, and inspect durable hash-bound evidence without rewriting the past. +- **Who it helps:** AI agents and researchers that need reproducible temporal evidence rather than only a live-price snapshot. +- **Capability boundary:** Read-only Bitcoin research. It does not predict price, trade, place orders, access wallets, move funds, read private account data, or accept credentials. + +## Live API + +- **API base URL:** https://bhrigu-bitcoin-research-state-api.vercel.app/v1 +- **Health-check URL:** https://bhrigu-bitcoin-research-state-api.vercel.app/health +- **Authentication:** none +- **Rate limits / known limits:** BTCUSDT only; public upstream services impose their own limits; market calls fail closed when fresh evidence is unavailable; no SLA is claimed. +- **API contract:** `GET /v1/state`, `GET /v1/windows`, `GET /v1/windows/{id}`, `POST /mcp`, and `GET /openapi.json`. The MCP endpoint exposes four read-only tools and supports modern `2026-07-28` stateless discovery plus legacy `2025-11-25` / `2025-03-26` compatibility. + +## Source and reproducibility + +- **Source repository:** https://github.com/AiBhrigu/bhrigu-bitcoin-research-state-api +- **Review commit:** `905adc26632e4595d998c01da26b3ccd88bf8a6f` +- **Source submitted in this PR:** `source/` +- **Run tests:** `npm ci && npm test` (106 deterministic checks: acceptance 18 + temporal 17 + MCP 56 + integrity 15) +- **Run locally:** `npm ci && npm start`, then call `http://localhost:3000/v1/state`, `/v1/windows`, or `/mcp`. +- **Deploy:** deploy the exact review commit to Vercel with Node.js 22+; no environment variables or secrets are required. +- **Version binding:** `/health` and `/.well-known/xagent-verification.json` expose the exact deployed review commit. + +## Verification + +Repeatable commands and expected results are in `verification/README.md`. + +- **Health-check result:** HTTP 200 with `status: ok` and exact review commit. +- **Capability call:** an agent can `DISCOVER → READ_LOCKED_PAST → COMPARE_LIVE_REALITY` using the four read-only MCP tools or equivalent HTTP endpoints. +- **Expected error behavior:** unsupported symbols return HTTP 400; write methods are rejected; unsupported modern MCP versions and header/body mismatches fail closed; unavailable market evidence is not fabricated. + +## Security and data handling + +- **Data collected:** none from users. The service is stateless with respect to user identity and accepts no account, wallet, or credential data. +- **Purpose and retention:** frozen precommit records and committed post-boundary evidence are public research artifacts retained in source; no personal data is retained. +- **Third parties / outbound network calls:** Binance public Spot BTCUSDT market data and mempool.space public Bitcoin tip height. +- **Secrets:** none required; none committed. +- **Known risks / restrictions:** public upstream availability and rate limits affect live evidence. `SEP_10_2026` has one durable post-boundary evidence record; `SEP_17_2026` is a genuine second precommit and remains pre-boundary until its declared UTC boundary. + +## Temporal-evidence proof + +`SEP_10_2026` was committed before its `2026-09-10T00:00:00Z` boundary. The original baseline remains hash-pinned and unchanged, and the reviewed source contains a durable post-boundary observation. `SEP_17_2026` provides a second future window. The public registry exposes append-only intent, evidence counts, phases, and artifact hashes so reviewers can distinguish frozen past evidence from live current state. + +## MCP productization + +`POST /mcp` is shipped, not proposed. It provides four read-only tools for current Bitcoin state, temporal-window discovery, frozen-window retrieval, and live comparison. Modern `2026-07-28` requests are stateless and handshake-free via `server/discover`; legacy clients retain `initialize` compatibility. No MCP tool creates observations or carries trading, wallet, payment, transfer, withdrawal, credential, or private-account authority. + +## Support + +- **Team / builder:** BHRIGU / AiBhrigu +- **Contact:** https://x.com/bhrigu_io +- **Canonical project surface:** https://www.bhrigu.io/ +- **License / rights:** no general open-source license is granted. X-Agent review/archive rights are limited to the bounded submitted artifact and are declared in `RIGHTS.md`. diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/.github/workflows/ci.yml b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/.github/workflows/ci.yml new file mode 100644 index 0000000..3ecda26 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/.github/workflows/ci.yml @@ -0,0 +1,49 @@ +name: CI + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + verify: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - run: npm ci + - run: npm run check + - name: Local HTTP and MCP smoke + run: | + BHRIGU_COMMIT="$GITHUB_SHA" npm start > /tmp/bhrigu.log 2>&1 & + SERVER_PID=$! + trap 'kill $SERVER_PID || true' EXIT + for n in $(seq 1 20); do + curl -fsS http://127.0.0.1:3000/health > /tmp/health.json && break + sleep 1 + done + node --input-type=module -e 'const h=JSON.parse(await (await fetch("http://127.0.0.1:3000/health")).text()); if(h.commit!==process.env.GITHUB_SHA) process.exit(1)' + curl -fsS http://127.0.0.1:3000/v1/windows > /tmp/windows.json + curl -fsS -X POST http://127.0.0.1:3000/mcp \ + -H 'content-type: application/json' \ + -H 'MCP-Protocol-Version: 2026-07-28' \ + -H 'Mcp-Method: server/discover' \ + --data '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{},"io.modelcontextprotocol/clientInfo":{"name":"ci","version":"1.0.0"}}}}' > /tmp/discover.json + curl -fsS -X POST http://127.0.0.1:3000/mcp \ + -H 'content-type: application/json' \ + -H 'MCP-Protocol-Version: 2026-07-28' \ + -H 'Mcp-Method: tools/list' \ + --data '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}' > /tmp/mcp-modern.json + curl -fsS -X POST http://127.0.0.1:3000/mcp \ + -H 'content-type: application/json' \ + -H 'MCP-Protocol-Version: 2026-07-28' \ + -H 'Mcp-Method: tools/call' \ + -H 'Mcp-Name: bhrigu_get_temporal_window' \ + --data '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"bhrigu_get_temporal_window","arguments":{"window_id":"SEP_10_2026"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}' > /tmp/mcp-call.json + node --input-type=module -e 'import fs from "node:fs"; const w=JSON.parse(fs.readFileSync("/tmp/windows.json")); const d=JSON.parse(fs.readFileSync("/tmp/discover.json")); const l=JSON.parse(fs.readFileSync("/tmp/mcp-modern.json")); const c=JSON.parse(fs.readFileSync("/tmp/mcp-call.json")); if(w.window_count!==2||w.durable_evidence_count!==1||d.result.resultType!=="complete"||!d.result.supportedVersions.includes("2026-07-28")||l.result.tools.length!==4||l.result.ttlMs!==300000||c.result.structuredContent.window.id!=="SEP_10_2026") process.exit(1)' diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/.gitignore b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/.gitignore new file mode 100644 index 0000000..0183d71 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +.vercel/ +.env* +.DS_Store +npm-debug.log* +.vercel diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/IP_BOUNDARY.md b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/IP_BOUNDARY.md new file mode 100644 index 0000000..eef865a --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/IP_BOUNDARY.md @@ -0,0 +1,28 @@ +# IP Boundary + +## Public artifact + +This repository intentionally contains only: + +- the read-only HTTP adapter; +- deterministic state-shaping logic; +- one frozen public observation baseline; +- public-source fetchers; +- tests and deployment metadata. + +## Explicitly excluded + +The following are not part of this artifact and must not be added during hackathon packaging: + +- ORION core or private services; +- private prompts, planners, evaluators, or routing contracts; +- private or unpublished corpora; +- unpublished reconstruction or forecasting methods; +- credentials, secrets, customer/account data; +- wallet, payment, transfer, withdrawal, or trade execution logic. + +## Law + +`EXPOSE MEANING / PROTECT MECHANISM` + +Any future submission must copy only the source already present in this bounded public repository unless separately reviewed and authorized. diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/README.md b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/README.md new file mode 100644 index 0000000..349cb40 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/README.md @@ -0,0 +1,64 @@ +# BHRIGU Bitcoin Temporal Evidence + +A bounded, read-only Bitcoin research capability for AI agents. + +It turns public Bitcoin evidence into a repeatable temporal record: + +`FIELD → WINDOW → REALITY → MEMORY → NEXT WINDOW` + +## Why this is different + +A live-price endpoint tells an agent what is true now. BHRIGU also preserves what was fixed **before a declared future boundary**, then lets the agent compare that immutable precommit with later reality. + +The first real experiment, `SEP_10_2026`, crossed its boundary without rewriting the baseline. A durable post-boundary observation is included. `SEP_17_2026` is the second genuine future precommit. + +## Public interfaces + +- `GET /v1/state` — live BTCUSDT + protocol-time state and temporal summary +- `GET /v1/windows` — list precommitted windows +- `GET /v1/windows/{id}` — one frozen window and durable evidence +- `POST /mcp` — stateless Streamable HTTP MCP JSON-RPC +- `GET /openapi.json` — HTTP contract +- `GET /health` — exact deployed commit +- `GET /.well-known/xagent-verification.json` — slug + exact deployed commit + +## MCP tools + +- `bhrigu_get_bitcoin_research_state` +- `bhrigu_list_temporal_windows` +- `bhrigu_get_temporal_window` +- `bhrigu_compare_window_to_reality` + +The MCP endpoint serves both lifecycle eras on the same URL: + +- modern `2026-07-28`: handshake-free `server/discover`, per-request protocol/capability envelope, `Mcp-Method`/`Mcp-Name` header validation, complete-result discrimination, and explicit cache hints; +- legacy `2025-11-25` / `2025-03-26`: `initialize` compatibility for existing clients. + +See `docs/MCP_PROTOCOL.md` for the exact transport contract. All tools are read-only. There is no trading, wallet, payment, transfer, withdrawal, credential, or private-account authority. + +## Verification + +```bash +npm ci +npm run check +npm start +``` + +For review, follow `docs/AGENT_WORKFLOW.md` for the exact three-step agent path and `docs/OPERATING_PROOF.md` for commit binding, failure behavior, and the reviewer challenge. See `docs/TEMPORAL_EVIDENCE.md` for the immutable-window contract and `docs/SCORECARD.md` for scorecard evidence. + +## Public data dependencies + +- Binance public Spot BTCUSDT 24h ticker +- mempool.space public Bitcoin tip height + +Market-source failure is fail-closed. Protocol-height failure is exposed as unavailable rather than silently substituted. + +## IP boundary + +This repository contains only the bounded public adapter and public evidence records. It does not contain ORION, private prompts, planners, evaluators, private corpora, unpublished research methods, credentials, account state, wallet code, payment code, or trading execution. + +See `IP_BOUNDARY.md`. + +## License / rights + +No general open-source license is granted by this repository. X-Agent review/archive rights apply only to the bounded submitted artifact when explicitly declared. diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/THIRD_PARTY.md b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/THIRD_PARTY.md new file mode 100644 index 0000000..7901e47 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/THIRD_PARTY.md @@ -0,0 +1,17 @@ +# Third-party public data + +## Binance Spot public market data + +Endpoint class: public market data, security type `NONE`. + +Used for BTCUSDT 24-hour ticker fields only. No Binance account authentication, API key, trading endpoint, wallet endpoint, transfer endpoint, or private account endpoint is used. + +## mempool.space public Bitcoin tip height + +Used only to retrieve the current public Bitcoin block height and derive position within the current halving epoch. + +If this source is unavailable, the API exposes the source as unavailable and does not substitute hidden data. + +## Runtime dependencies + +The project has no npm runtime dependencies. It uses only Node.js built-ins and the platform-provided `fetch` implementation. diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/about.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/about.mjs new file mode 100644 index 0000000..a3d3d12 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/about.mjs @@ -0,0 +1,16 @@ +import { methodGate, sendJson } from "../lib/http.mjs"; + +export default function handler(req, res) { + if (!methodGate(req, res)) return; + sendJson(res, 200, { + name: "BHRIGU Bitcoin Temporal Evidence", + capability: "read-only precommit → reality → memory for Bitcoin research", + endpoint: "/v1/state", + windows: "/v1/windows", + mcp: "/mcp", + openapi: "/openapi.json", + health: "/health", + verification: "/.well-known/xagent-verification.json", + boundary: "RESEARCH_STATE_NOT_TRADE" + }, "public, max-age=60"); +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/health.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/health.mjs new file mode 100644 index 0000000..1eadced --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/health.mjs @@ -0,0 +1,7 @@ +import { healthPayload } from "../lib/runtime.mjs"; +import { methodGate, sendJson } from "../lib/http.mjs"; + +export default function handler(req, res) { + if (!methodGate(req, res)) return; + sendJson(res, 200, healthPayload(), "public, max-age=30"); +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/mcp.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/mcp.mjs new file mode 100644 index 0000000..f3b5296 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/mcp.mjs @@ -0,0 +1,37 @@ +import { sendJson } from "../lib/http.mjs"; +import { handleMcpRpc } from "../lib/mcp.mjs"; + +async function readBody(req) { + if (req.body && typeof req.body === "object") return req.body; + let raw = ""; + for await (const chunk of req) raw += chunk; + return raw ? JSON.parse(raw) : null; +} + +function headerValue(req, name) { + const headers = req.headers; + if (headers?.get) return headers.get(name); + const value = headers?.[name.toLowerCase()] ?? headers?.[name]; + return Array.isArray(value) ? value[0] : value ?? null; +} + +export default async function handler(req, res) { + if (req.method !== "POST") return sendJson(res, 405, { error: "METHOD_NOT_ALLOWED", allowed: ["POST"] }); + try { + const result = await handleMcpRpc(await readBody(req), { + transportMeta: { + requireHeaders: true, + protocolVersion: headerValue(req, "MCP-Protocol-Version"), + method: headerValue(req, "Mcp-Method"), + name: headerValue(req, "Mcp-Name") + } + }); + if (result.status === 202) { + res.statusCode = 202; + return res.end(); + } + sendJson(res, result.status, result.body, "no-store"); + } catch { + sendJson(res, 400, { jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } }); + } +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/openapi.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/openapi.mjs new file mode 100644 index 0000000..8f54a91 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/openapi.mjs @@ -0,0 +1,7 @@ +import { methodGate, sendJson } from "../lib/http.mjs"; +import { openapiPayload } from "../lib/openapi.mjs"; + +export default function handler(req, res) { + if (!methodGate(req, res)) return; + sendJson(res, 200, openapiPayload(), "public, max-age=300"); +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/state.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/state.mjs new file mode 100644 index 0000000..7fb5586 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/state.mjs @@ -0,0 +1,23 @@ +import { buildState } from "../lib/state.mjs"; +import { methodGate, sendJson } from "../lib/http.mjs"; + +export default async function handler(req, res) { + if (!methodGate(req, res)) return; + const url = new URL(req.url || "/v1/state", "http://localhost"); + const symbol = String(url.searchParams.get("symbol") || "BTCUSDT").toUpperCase(); + if (symbol !== "BTCUSDT") { + sendJson(res, 400, { error: "UNSUPPORTED_SYMBOL", supported: ["BTCUSDT"] }); + return; + } + try { + const state = await buildState(); + sendJson(res, 200, state, "public, max-age=10, s-maxage=10"); + } catch (error) { + sendJson(res, 502, { + error: "PUBLIC_MARKET_SOURCE_UNAVAILABLE", + source: "Binance Spot BTCUSDT", + detail: String(error.message || error), + trading_authority: false + }); + } +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/verification.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/verification.mjs new file mode 100644 index 0000000..13e7b12 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/verification.mjs @@ -0,0 +1,7 @@ +import { verificationPayload } from "../lib/runtime.mjs"; +import { methodGate, sendJson } from "../lib/http.mjs"; + +export default function handler(req, res) { + if (!methodGate(req, res)) return; + sendJson(res, 200, verificationPayload(), "public, max-age=30"); +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/window.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/window.mjs new file mode 100644 index 0000000..8243cf0 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/window.mjs @@ -0,0 +1,11 @@ +import { methodGate, sendJson } from "../lib/http.mjs"; +import { getWindow } from "../lib/windows.mjs"; + +export default function handler(req, res) { + if (!methodGate(req, res)) return; + const url = new URL(req.url || "/", "http://localhost"); + const id = String(url.searchParams.get("id") || ""); + const record = getWindow(id, new Date()); + if (!record) return sendJson(res, 404, { error: "WINDOW_NOT_FOUND", supported: ["SEP_10_2026", "SEP_17_2026"] }); + sendJson(res, 200, record, "public, max-age=30"); +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/windows.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/windows.mjs new file mode 100644 index 0000000..490af23 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/api/windows.mjs @@ -0,0 +1,8 @@ +import { methodGate, sendJson } from "../lib/http.mjs"; +import { listWindows, temporalSummary } from "../lib/windows.mjs"; + +export default function handler(req, res) { + if (!methodGate(req, res)) return; + const now = new Date(); + sendJson(res, 200, { ...temporalSummary(now), windows: listWindows(now) }, "public, max-age=30"); +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/AGENT_WORKFLOW.md b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/AGENT_WORKFLOW.md new file mode 100644 index 0000000..bd74d11 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/AGENT_WORKFLOW.md @@ -0,0 +1,51 @@ +# Three-step agent workflow + +BHRIGU is useful when an agent needs to distinguish **what was fixed before a future boundary** from **what is true now** without letting later reality rewrite the earlier record. + +The canonical workflow is: + +`DISCOVER → READ_LOCKED_PAST → COMPARE_LIVE_REALITY` + +All calls below are read-only. They do not create observations, trade, sign, pay, transfer, withdraw, or access private account data. + +## 1. DISCOVER + +Call `server/discover` on `POST /mcp` using protocol revision `2026-07-28`, the matching `MCP-Protocol-Version` and `Mcp-Method` headers, and the required per-request `_meta` envelope. + +Expected proof: + +- `resultType = complete` +- `supportedVersions` contains `2026-07-28` +- server identity is present in `_meta.io.modelcontextprotocol/serverInfo` + +Then call `tools/list`. The server exposes exactly four read-only tools. + +## 2. READ_LOCKED_PAST + +Call `bhrigu_get_temporal_window` with: + +```json +{"window_id":"SEP_10_2026"} +``` + +Expected proof: + +- baseline BTCUSDT = `78474` +- boundary = `2026-09-10T00:00:00Z` +- durable post-boundary evidence count = `1` +- precommit SHA-256 = `fd92dc8a578a2f5f393b87d3f0e65bdf2f8b9ff828ddccf21eabce66d6d39998` +- retroactive rewrite = `forbidden` + +This answers: **what did the system actually know before the boundary?** + +## 3. COMPARE_LIVE_REALITY + +Call `bhrigu_compare_window_to_reality` with the same `window_id`. + +The response reads fresh public Bitcoin evidence and returns the current BTCUSDT value and current-vs-baseline delta while preserving the locked baseline. The call does not append or mutate evidence. + +For a second temporal cycle, repeat the same workflow with `SEP_17_2026`. Until its boundary, it remains a genuine future precommit with zero post-boundary evidence. + +## Failure behavior + +Malformed modern metadata fails with JSON-RPC `-32602`; header/body mismatches fail with `-32020`; unsupported protocol revisions fail with `-32022`; unknown windows return a structured `WINDOW_NOT_FOUND` tool error; live market-source failure fails closed rather than fabricating a comparison. diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/MCP_PROTOCOL.md b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/MCP_PROTOCOL.md new file mode 100644 index 0000000..40d6063 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/MCP_PROTOCOL.md @@ -0,0 +1,29 @@ +# MCP protocol contract + +BHRIGU serves the same four read-only tools across the modern and legacy MCP lifecycle eras. + +## Modern era — 2026-07-28 + +The modern path is stateless and handshake-free. `server/discover` is available for up-front discovery, but tools can be called directly when the client already knows the contract. + +Every modern non-notification HTTP request carries: + +- `MCP-Protocol-Version: 2026-07-28` +- `Mcp-Method` matching the JSON-RPC method +- `Mcp-Name` where the method mirrors a `params.name` value, including `tools/call` +- `_meta.io.modelcontextprotocol/protocolVersion = 2026-07-28` +- `_meta.io.modelcontextprotocol/clientCapabilities` + +`_meta.io.modelcontextprotocol/clientInfo` is recommended but optional; if present it must be well formed. Notification POSTs are exempt from the standard-header presence check. + +`server/discover` advertises every protocol revision this endpoint supports so a client can negotiate the modern era or deliberately fall back to a legacy initialize-capable revision. Modern complete results carry `resultType: "complete"`; server identity is stamped in `_meta.io.modelcontextprotocol/serverInfo`, and cacheable discovery/list results carry explicit `ttlMs` and `cacheScope` hints. + +The server fails closed on malformed or missing required `_meta` fields (`-32602`), header/body mismatches (`-32020`), and unsupported protocol versions (`-32022`). `-32022` errors return both the requested revision and the supported-version set. The current BHRIGU tools require no optional client capability beyond the mandatory per-request `clientCapabilities` envelope, so they do not emit `-32021` in ordinary use. Modern `initialize` and `ping` are not served because they belong to the handshake-era lifecycle. + +## Legacy era — 2025-11-25 / 2025-03-26 + +Legacy clients can still use `initialize` and the same read-only tools. BHRIGU uses the stateless legacy HTTP form: it does not create a protocol session because these tools never require server-to-client requests or hidden transport state. + +## Safety boundary + +MCP calls never create observations, rewrite precommits, trade, sign, pay, transfer, withdraw, read credentials, or access private account data. Temporal evidence is committed separately and exposed read-only. diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/OPERATING_PROOF.md b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/OPERATING_PROOF.md new file mode 100644 index 0000000..7ac3d78 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/OPERATING_PROOF.md @@ -0,0 +1,54 @@ +# Operating proof and failure contract + +This document defines what a reviewer or agent can verify without credentials. + +## Version binding + +A review deployment is valid only when all three surfaces agree on one exact 40-character source commit: + +1. the declared review commit in the submission package; +2. `GET /health` → `status: ok|healthy` plus that commit; +3. `GET /.well-known/xagent-verification.json` → the BHRIGU slug plus that commit. + +A mismatch is a release blocker, not a warning. + +## Deterministic source gate + +`npm run check` executes four suites: + +- original acceptance behavior; +- temporal-window behavior; +- MCP protocol/tool behavior; +- immutable-artifact and authority-boundary integrity. + +CI then boots the HTTP server and performs live local HTTP/MCP smoke checks, including modern `server/discover`, `tools/list`, and a temporal-window tool call. + +## Public runtime dependencies + +BHRIGU reads public Binance Spot BTCUSDT market data and public Bitcoin tip-height evidence from mempool.space. No API key, wallet, user account, or private credential is required. + +## Failure contract + +- Market data unavailable → fail closed; do not fabricate a live comparison. +- Protocol-height source unavailable → expose the unavailable state; do not silently substitute a private value. +- Invalid/unknown temporal window → structured `WINDOW_NOT_FOUND` tool error. +- Malformed modern MCP metadata → JSON-RPC `-32602`. +- MCP header/body mismatch → `-32020`. +- Unsupported MCP revision → `-32022` with requested/supported versions. +- No MCP call writes evidence or changes a precommit. + +## Operating boundary + +The service is intentionally narrow: public Bitcoin temporal evidence for agents. Trading, order placement, wallet access, payment, transfer, withdrawal, credentials, private account data, ORION internals, private prompts, private evaluators, and unpublished research methods remain outside this artifact. + +## Reviewer challenge + +A reviewer can challenge the service by asking it to: + +1. expose the frozen `SEP_10_2026` record and its integrity hash; +2. compare that record with live Bitcoin reality; +3. expose `SEP_17_2026` as the next precommitted window; +4. reject a malformed MCP envelope or unsupported version; +5. prove the running review deployment is bound to the exact declared commit. + +If any one of these fails, the first-place upgrade is not release-ready. diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/SCORECARD.md b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/SCORECARD.md new file mode 100644 index 0000000..bbed564 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/SCORECARD.md @@ -0,0 +1,41 @@ +# X-Agent scorecard evidence + +## Real agent/user value + +BHRIGU gives agents a compact answer to a problem ordinary live-price tools cannot solve: **what was known before a declared future boundary, what is true now, and what changed without rewriting the past?** The loop is reusable across multiple windows. + +## Demonstrated capability quality + +- live Binance BTCUSDT market evidence; +- Bitcoin protocol-time coordinates; +- source freshness; +- frozen precommit baselines; +- durable post-boundary evidence; +- explicit evidence limitations; +- fail-closed market-source behavior; +- no prediction or trading claim. + +## Engineering and maintainability + +- zero npm runtime dependencies; +- exact deployment commit binding; +- CI on push and pull request; +- acceptance, temporal, MCP, and immutable-baseline tests; +- pinned SHA-256 for the original SEP_10 source file and committed evidence artifacts; +- public OpenAPI contract; +- typed JSON-RPC errors and bounded tool schemas; +- header/body mismatch checks for modern MCP traffic. + +## MCP productization + +The same stateless `/mcp` endpoint serves both MCP lifecycle eras. Modern `2026-07-28` requests use handshake-free `server/discover`, per-request protocol/capability metadata, header-based routing validation, `resultType: complete`, and explicit cache hints. Existing `2025-11-25` / `2025-03-26` clients retain `initialize` compatibility. + +Four tools expose live state, window discovery, durable evidence retrieval, and live comparison. Every tool is read-only and explicitly non-destructive. See `docs/MCP_PROTOCOL.md` for the exact contract. + +## Operational and adoption potential + +The capability requires no user credential, wallet, API key, or account state. Agents can integrate it as a public evidence service. A second precommit (`SEP_17_2026`) proves the method is repeatable rather than a one-off demonstration. + +## Boundary + +The public artifact exposes only the bounded evidence adapter. ORION, private prompts, planners, evaluators, private corpora, unpublished research methods, credentials, wallets, payments, transfers, withdrawals, and trading execution remain excluded. diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/TEMPORAL_EVIDENCE.md b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/TEMPORAL_EVIDENCE.md new file mode 100644 index 0000000..23e380c --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/docs/TEMPORAL_EVIDENCE.md @@ -0,0 +1,31 @@ +# Temporal evidence contract + +BHRIGU treats time as evidence, not as a prediction claim. + +`FIELD → WINDOW → REALITY → MEMORY → NEXT WINDOW` + +## SEP_10_2026 + +The original `lib/window.mjs` was committed before the boundary and remains byte-identical. CI pins its SHA-256: + +`fd92dc8a578a2f5f393b87d3f0e65bdf2f8b9ff828ddccf21eabce66d6d39998` + +Boundary: `2026-09-10T00:00:00Z`. + +A post-boundary reality observation is now stored in `lib/evidence.mjs` and mirrored as `evidence/SEP_10_2026_POSTBOUNDARY.json`. CI pins the evidence artifact SHA-256 `80bc4e19efa6858371559815a08fbc6224a34c751658d410d6aa7d6ad3b57027`. It records the live runtime observation, exact runtime commit, direct Binance cross-check, and the limitation that an independent protocol-height probe timed out. + +## SEP_17_2026 + +`lib/window-sep17.mjs` is the second genuine future precommit. Its public proof artifact `evidence/SEP_17_2026_PRECOMMIT.json` is pinned to SHA-256 `19a27baa6c5f55efbfda84782cf4920374c82323f13f6eabce7d63ed2f0a13f2`. Its baseline was captured on 2026-09-10, seven days before the boundary. No post-boundary evidence exists yet. After the boundary, any evidence must be appended; the baseline must not be rewritten. + +## Agent value + +An agent can ask: + +1. What was fixed before the boundary? +2. What is true now? +3. What changed relative to the precommit? +4. What durable evidence exists? +5. What future precommit is next? + +The server remains read-only. It never writes observations during an MCP call and has zero trading, wallet, payment, transfer, or private-account authority. diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/evidence/SEP_10_2026_POSTBOUNDARY.json b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/evidence/SEP_10_2026_POSTBOUNDARY.json new file mode 100644 index 0000000..792ee03 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/evidence/SEP_10_2026_POSTBOUNDARY.json @@ -0,0 +1,17 @@ +{ + "schema": "bhrigu_temporal_evidence_v0_1", + "id": "SEP_10_2026__2026-09-10T04:49:49.136Z", + "window_id": "SEP_10_2026", + "kind": "post_boundary_reality_observation", + "observed_at_utc": "2026-09-10T04:49:49.136Z", + "boundary_utc": "2026-09-10T00:00:00Z", + "baseline_btcusdt": 78474, + "observed_btcusdt": 78348.09, + "current_vs_baseline_pct": -0.1604, + "runtime_commit": "05a455ba1407f7b07de226f6c78eefda15b24880", + "market_crosscheck_btcusdt": 78348.10, + "protocol_tip_height": 966302, + "protocol_crosscheck": "runtime_source_status_live; independent ORION probe timed out", + "retroactive_rewrite": "forbidden", + "trading_signal": false +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/evidence/SEP_17_2026_PRECOMMIT.json b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/evidence/SEP_17_2026_PRECOMMIT.json new file mode 100644 index 0000000..e76d32b --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/evidence/SEP_17_2026_PRECOMMIT.json @@ -0,0 +1,16 @@ +{ + "schema": "bhrigu_temporal_precommit_v0_1", + "window_id": "SEP_17_2026", + "boundary_utc": "2026-09-17T00:00:00Z", + "captured_at_utc": "2026-09-10T04:49:49.136Z", + "btcusdt_last_price": 78348.09, + "btcusdt_24h_change_pct": -0.983, + "btcusdt_24h_high": 79760, + "btcusdt_24h_low": 77770, + "bitcoin_tip_height": 966302, + "source_runtime_commit": "05a455ba1407f7b07de226f6c78eefda15b24880", + "market_crosscheck_last_price_usdt": 78348.10, + "retroactive_rewrite": "forbidden", + "price_target": false, + "trading_signal": false +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/evidence.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/evidence.mjs new file mode 100644 index 0000000..4c697bd --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/evidence.mjs @@ -0,0 +1,38 @@ +export const SEP_10_POSTBOUNDARY_EVIDENCE = Object.freeze({ + schema: "bhrigu_temporal_evidence_v0_1", + id: "SEP_10_2026__2026-09-10T04:49:49.136Z", + window_id: "SEP_10_2026", + kind: "post_boundary_reality_observation", + observed_at_utc: "2026-09-10T04:49:49.136Z", + boundary_utc: "2026-09-10T00:00:00Z", + baseline: Object.freeze({ + captured_at_utc: "2026-09-08T11:25:23Z", + btcusdt_last_price: 78474 + }), + observation: Object.freeze({ + btcusdt_last_price: 78348.09, + current_vs_baseline_pct: -0.1604, + btcusdt_24h_change_pct: -0.983, + btcusdt_24h_high: 79760, + btcusdt_24h_low: 77770, + volume_24h_btc: 13960.82618, + bitcoin_tip_height: 966302 + }), + provenance: Object.freeze({ + runtime_endpoint: "https://bhrigu-bitcoin-research-state-api.vercel.app/v1/state", + runtime_commit: "05a455ba1407f7b07de226f6c78eefda15b24880", + market_source: "https://data-api.binance.vision/api/v3/ticker/24hr?symbol=BTCUSDT", + market_crosscheck_last_price_usdt: 78348.10, + market_crosscheck_abs_diff_usdt: 0.01, + protocol_source: "https://mempool.space/api/blocks/tip/height", + protocol_crosscheck: "runtime_source_status_live; independent ORION probe timed out" + }), + verdict: "POST_BOUNDARY_REALITY_CAPTURED", + invariants: Object.freeze({ + append_only: true, + retroactive_rewrite: "forbidden", + trading_signal: false + }) +}); + +export const EVIDENCE_LEDGER = Object.freeze([SEP_10_POSTBOUNDARY_EVIDENCE]); diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/http.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/http.mjs new file mode 100644 index 0000000..214d88f --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/http.mjs @@ -0,0 +1,14 @@ +export function sendJson(res, status, payload, cache = "no-store") { + res.statusCode = status; + res.setHeader("content-type", "application/json; charset=utf-8"); + res.setHeader("cache-control", cache); + res.setHeader("access-control-allow-origin", "*"); + res.setHeader("x-content-type-options", "nosniff"); + res.end(JSON.stringify(payload)); +} + +export function methodGate(req, res) { + if (req.method === "GET") return true; + sendJson(res, 405, { error: "METHOD_NOT_ALLOWED", allowed: ["GET"] }); + return false; +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/integrity.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/integrity.mjs new file mode 100644 index 0000000..e13aab6 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/integrity.mjs @@ -0,0 +1,17 @@ +export const WINDOW_INTEGRITY = Object.freeze({ + SEP_10_2026: Object.freeze({ + artifact_path: "lib/window.mjs", + sha256: "fd92dc8a578a2f5f393b87d3f0e65bdf2f8b9ff828ddccf21eabce66d6d39998" + }), + SEP_17_2026: Object.freeze({ + artifact_path: "evidence/SEP_17_2026_PRECOMMIT.json", + sha256: "19a27baa6c5f55efbfda84782cf4920374c82323f13f6eabce7d63ed2f0a13f2" + }) +}); + +export const EVIDENCE_INTEGRITY = Object.freeze({ + SEP_10_2026: Object.freeze({ + artifact_path: "evidence/SEP_10_2026_POSTBOUNDARY.json", + sha256: "80bc4e19efa6858371559815a08fbc6224a34c751658d410d6aa7d6ad3b57027" + }) +}); diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/live.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/live.mjs new file mode 100644 index 0000000..b17c125 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/live.mjs @@ -0,0 +1,42 @@ +const BINANCE_TICKER = "https://data-api.binance.vision/api/v3/ticker/24hr?symbol=BTCUSDT"; +const MEMPOOL_TIP = "https://mempool.space/api/blocks/tip/height"; + +async function timedFetch(url, fetchImpl = fetch) { + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), 8000); + try { + const response = await fetchImpl(url, { signal: controller.signal, headers: { accept: "application/json,text/plain" } }); + if (!response.ok) throw new Error(`HTTP_${response.status}`); + return response; + } finally { + clearTimeout(timer); + } +} + +export async function fetchMarket(fetchImpl = fetch) { + const response = await timedFetch(BINANCE_TICKER, fetchImpl); + const d = await response.json(); + return { + venue: "Binance Spot", + symbol: "BTCUSDT", + last_price_usdt: Number(d.lastPrice), + change_24h_pct: Number(d.priceChangePercent), + high_24h_usdt: Number(d.highPrice), + low_24h_usdt: Number(d.lowPrice), + volume_24h_btc: Number(d.volume), + source_close_time_ms: Number(d.closeTime), + source: BINANCE_TICKER, + security_type: "NONE" + }; +} + +export async function fetchProtocol(fetchImpl = fetch) { + try { + const response = await timedFetch(MEMPOOL_TIP, fetchImpl); + const height = Number(await response.text()); + if (!Number.isInteger(height) || height < 840000) throw new Error("INVALID_HEIGHT"); + return { height, source: MEMPOOL_TIP, status: "live" }; + } catch (error) { + return { height: null, source: MEMPOOL_TIP, status: "unavailable", error: String(error.message || error) }; + } +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/mcp.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/mcp.mjs new file mode 100644 index 0000000..4524201 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/mcp.mjs @@ -0,0 +1,267 @@ +import { buildState } from "./state.mjs"; +import { getWindow, listWindows } from "./windows.mjs"; + +export const MCP_MODERN_PROTOCOL_VERSION = "2026-07-28"; +export const MCP_LEGACY_PROTOCOL_VERSION = "2025-11-25"; +export const MCP_SUPPORTED_PROTOCOL_VERSIONS = Object.freeze([ + MCP_MODERN_PROTOCOL_VERSION, + MCP_LEGACY_PROTOCOL_VERSION, + "2025-03-26" +]); +export const MCP_PROTOCOL_VERSION = MCP_LEGACY_PROTOCOL_VERSION; + +const SERVER_INFO = Object.freeze({ + name: "bhrigu-bitcoin-research-state-api", + title: "BHRIGU Bitcoin Temporal Evidence", + version: "0.2.0" +}); +const SERVER_CAPABILITIES = Object.freeze({ tools: Object.freeze({ listChanged: false }) }); +const SERVER_INSTRUCTIONS = "Use frozen windows to ask what was known then, compare with public reality now, and inspect durable evidence. Read-only research only; no trading or financial authority."; +const CACHE_HINT = Object.freeze({ ttlMs: 300000, cacheScope: "public" }); +const PROTOCOL_META = "io.modelcontextprotocol/protocolVersion"; +const CLIENT_INFO_META = "io.modelcontextprotocol/clientInfo"; +const CLIENT_CAPS_META = "io.modelcontextprotocol/clientCapabilities"; +const SERVER_INFO_META = "io.modelcontextprotocol/serverInfo"; + +export const MCP_TOOLS = Object.freeze([ + { + name: "bhrigu_get_bitcoin_research_state", + title: "Get live Bitcoin research state", + description: "Read the current BTCUSDT market state, Bitcoin protocol-time coordinates, source freshness, and temporal-evidence summary. Read-only; never trades, signs, pays, transfers, or accesses private account data.", + inputSchema: { type: "object", additionalProperties: false, properties: {} }, + annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true } + }, + { + name: "bhrigu_list_temporal_windows", + title: "List BHRIGU temporal windows", + description: "List public precommitted Bitcoin observation windows with phase, boundary, immutable-rewrite law, and durable evidence count.", + inputSchema: { type: "object", additionalProperties: false, properties: {} }, + annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false } + }, + { + name: "bhrigu_get_temporal_window", + title: "Get one temporal window and evidence", + description: "Read one frozen precommit together with durable post-boundary evidence already committed for that window.", + inputSchema: { + type: "object", additionalProperties: false, required: ["window_id"], + properties: { window_id: { type: "string", enum: ["SEP_10_2026", "SEP_17_2026"] } } + }, + annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false } + }, + { + name: "bhrigu_compare_window_to_reality", + title: "Compare a precommit with live reality", + description: "Read live public Bitcoin evidence and compare BTCUSDT against the selected precommitted baseline. No observation is written and no trading authority exists.", + inputSchema: { + type: "object", additionalProperties: false, required: ["window_id"], + properties: { window_id: { type: "string", enum: ["SEP_10_2026", "SEP_17_2026"] } } + }, + annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true } + } +]); + +const rpcResult = (id, result) => ({ jsonrpc: "2.0", id, result }); +const rpcError = (id, code, message, data) => ({ + jsonrpc: "2.0", id, error: { code, message, ...(data === undefined ? {} : { data }) } +}); +const modernMeta = () => ({ [SERVER_INFO_META]: SERVER_INFO }); +const completeResult = (value = {}, modern = false, cacheable = false) => modern + ? { resultType: "complete", ...value, ...(cacheable ? CACHE_HINT : {}), _meta: modernMeta() } + : value; +const toolResult = (value, modern = false) => completeResult({ + content: [{ type: "text", text: JSON.stringify(value) }], + structuredContent: value, + isError: false +}, modern); +const toolError = (code, message, modern = false) => completeResult({ + content: [{ type: "text", text: JSON.stringify({ error: { code, message } }) }], + structuredContent: { error: { code, message } }, + isError: true +}, modern); + +function parseRpc(body) { + if (!body || typeof body !== "object" || Array.isArray(body) || body.jsonrpc !== "2.0" || typeof body.method !== "string") return null; + if (body.id !== undefined && body.id !== null && typeof body.id !== "string" && typeof body.id !== "number") return null; + return body; +} + +function parseWindowId(args) { + const id = args?.window_id; + return typeof id === "string" ? id : null; +} + +function bodyProtocolVersion(rpc) { + return rpc.params?._meta?.[PROTOCOL_META] ?? null; +} + +function unsupportedVersion(rpc, requested) { + return rpcError(rpc.id ?? null, -32022, "Unsupported protocol version", { + supported: MCP_SUPPORTED_PROTOCOL_VERSIONS, + requested + }); +} + +function classifyEra(rpc, transportMeta = {}) { + const bodyVersion = bodyProtocolVersion(rpc); + const headerVersion = transportMeta.protocolVersion ?? null; + + if (bodyVersion && !MCP_SUPPORTED_PROTOCOL_VERSIONS.includes(bodyVersion)) { + return { error: unsupportedVersion(rpc, bodyVersion) }; + } + if (headerVersion && !MCP_SUPPORTED_PROTOCOL_VERSIONS.includes(headerVersion)) { + return { error: unsupportedVersion(rpc, headerVersion) }; + } + + const modern = rpc.method === "server/discover" + || bodyVersion !== null + || headerVersion === MCP_MODERN_PROTOCOL_VERSION; + return { modern, bodyVersion, headerVersion }; +} + +function validImplementation(value) { + return value + && typeof value === "object" + && !Array.isArray(value) + && typeof value.name === "string" + && value.name.length > 0 + && typeof value.version === "string" + && value.version.length > 0; +} + +function validateModernRequest(rpc, transportMeta = {}, classification) { + const envelope = rpc.params?._meta; + if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) { + return rpcError(rpc.id ?? null, -32602, "Invalid params", { + missing: [PROTOCOL_META, CLIENT_CAPS_META] + }); + } + + const version = envelope[PROTOCOL_META]; + if (typeof version !== "string" || version.length === 0) { + return rpcError(rpc.id ?? null, -32602, "Invalid params", { missing: [PROTOCOL_META] }); + } + if (version !== MCP_MODERN_PROTOCOL_VERSION) return unsupportedVersion(rpc, version); + + const clientCapabilities = envelope[CLIENT_CAPS_META]; + if (!clientCapabilities || typeof clientCapabilities !== "object" || Array.isArray(clientCapabilities)) { + return rpcError(rpc.id ?? null, -32602, "Invalid params", { missing: [CLIENT_CAPS_META] }); + } + + const clientInfo = envelope[CLIENT_INFO_META]; + if (clientInfo !== undefined && !validImplementation(clientInfo)) { + return rpcError(rpc.id ?? null, -32602, "Invalid params", { malformed: [CLIENT_INFO_META] }); + } + + const isNotification = rpc.method.startsWith("notifications/"); + if (transportMeta.requireHeaders && !isNotification) { + if (classification.headerVersion !== version || transportMeta.method !== rpc.method) { + return rpcError(rpc.id ?? null, -32020, "MCP header/body mismatch", { + expectedProtocolVersion: version, + expectedMethod: rpc.method + }); + } + if (rpc.method === "tools/call" && transportMeta.name !== rpc.params?.name) { + return rpcError(rpc.id ?? null, -32020, "MCP header/body mismatch", { + expectedName: rpc.params?.name ?? null + }); + } + } + return null; +} + +async function compareWindow(windowId, options) { + const record = getWindow(windowId, options.now); + if (!record) return null; + const state = await buildState(options); + const baseline = record.window.baseline.btcusdt_last_price; + const current = state.market.last_price_usdt; + return { + window_id: windowId, + boundary_utc: record.window.boundary_utc, + phase: record.phase, + observed_at_utc: state.observed_at_utc, + baseline_btcusdt: baseline, + current_btcusdt: current, + current_vs_baseline_pct: Number((((current - baseline) / baseline) * 100).toFixed(4)), + market_source: state.market.source, + market_freshness: state.market.freshness, + trading_authority: false + }; +} + +export async function handleMcpRpc(body, { fetchImpl = fetch, now = new Date(), transportMeta = {} } = {}) { + const rpc = parseRpc(body); + if (!rpc) return { status: 400, body: rpcError(null, -32600, "Invalid Request") }; + const id = rpc.id ?? null; + const classification = classifyEra(rpc, transportMeta); + if (classification.error) return { status: 400, body: classification.error }; + const modern = classification.modern; + + if (modern) { + const validationError = validateModernRequest(rpc, transportMeta, classification); + if (validationError) return { status: 400, body: validationError }; + if (rpc.method === "initialize" || rpc.method === "ping") { + return { status: 404, body: rpcError(id, -32601, "Method not found") }; + } + } + + if (rpc.method.startsWith("notifications/")) return { status: 202, body: null }; + if (rpc.method === "ping") return { status: 200, body: rpcResult(id, {}) }; + if (rpc.method === "server/discover") { + return { + status: 200, + body: rpcResult(id, completeResult({ + supportedVersions: MCP_SUPPORTED_PROTOCOL_VERSIONS, + capabilities: SERVER_CAPABILITIES, + instructions: SERVER_INSTRUCTIONS + }, true, true)) + }; + } + if (rpc.method === "initialize") { + const requested = rpc.params?.protocolVersion; + const protocolVersion = requested === "2025-03-26" ? "2025-03-26" : MCP_LEGACY_PROTOCOL_VERSION; + return { + status: 200, + body: rpcResult(id, { + protocolVersion, + capabilities: SERVER_CAPABILITIES, + serverInfo: SERVER_INFO, + instructions: SERVER_INSTRUCTIONS + }) + }; + } + if (rpc.method === "tools/list") { + return { status: 200, body: rpcResult(id, completeResult({ tools: MCP_TOOLS }, modern, modern)) }; + } + if (rpc.method !== "tools/call") return { status: 404, body: rpcError(id, -32601, "Method not found") }; + + const name = rpc.params?.name; + const args = rpc.params?.arguments ?? {}; + if (typeof name !== "string" || !args || typeof args !== "object" || Array.isArray(args)) { + return { status: 400, body: rpcError(id, -32602, "Invalid params") }; + } + + try { + if (name === "bhrigu_get_bitcoin_research_state") { + return { status: 200, body: rpcResult(id, toolResult(await buildState({ fetchImpl, now }), modern)) }; + } + if (name === "bhrigu_list_temporal_windows") { + return { status: 200, body: rpcResult(id, toolResult({ windows: listWindows(now) }, modern)) }; + } + if (name === "bhrigu_get_temporal_window") { + const windowId = parseWindowId(args); + const record = windowId ? getWindow(windowId, now) : null; + if (!record) return { status: 200, body: rpcResult(id, toolError("WINDOW_NOT_FOUND", "Unknown or missing window_id.", modern)) }; + return { status: 200, body: rpcResult(id, toolResult(record, modern)) }; + } + if (name === "bhrigu_compare_window_to_reality") { + const windowId = parseWindowId(args); + const comparison = windowId ? await compareWindow(windowId, { fetchImpl, now }) : null; + if (!comparison) return { status: 200, body: rpcResult(id, toolError("WINDOW_NOT_FOUND", "Unknown or missing window_id.", modern)) }; + return { status: 200, body: rpcResult(id, toolResult(comparison, modern)) }; + } + return { status: 200, body: rpcResult(id, toolError("TOOL_NOT_FOUND", `Unknown tool: ${name}`, modern)) }; + } catch (error) { + return { status: 200, body: rpcResult(id, toolError("PUBLIC_SOURCE_UNAVAILABLE", String(error.message || error), modern)) }; + } +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/openapi.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/openapi.mjs new file mode 100644 index 0000000..fb9f17a --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/openapi.mjs @@ -0,0 +1,27 @@ +import { runtimeCommit } from "./runtime.mjs"; + +export function openapiPayload() { + return { + openapi: "3.1.0", + info: { + title: "BHRIGU Bitcoin Temporal Evidence API", + version: "0.2.0", + description: "Read-only Bitcoin state and precommitted temporal evidence for AI agents." + }, + servers: [{ url: "https://bhrigu-bitcoin-research-state-api.vercel.app" }], + paths: { + "/v1/state": { get: { summary: "Live Bitcoin research state" } }, + "/v1/windows": { get: { summary: "List precommitted temporal windows" } }, + "/v1/windows/{id}": { get: { summary: "Get one window and durable evidence" } }, + "/mcp": { post: { summary: "Stateless Streamable HTTP MCP JSON-RPC endpoint" } }, + "/health": { get: { summary: "Health and exact commit binding" } } + }, + "x-bhrigu": { + commit: runtimeCommit(), + boundary: "RESEARCH_STATE_NOT_TRADE", + trading: false, + wallet: false, + payment: false + } + }; +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/runtime.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/runtime.mjs new file mode 100644 index 0000000..e421625 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/runtime.mjs @@ -0,0 +1,14 @@ +export const SLUG = "bhrigu-bitcoin-research-state-api"; +export const SCHEMA = "bhrigu_bitcoin_research_state_v0_1"; + +export function runtimeCommit() { + return process.env.BHRIGU_COMMIT || process.env.VERCEL_GIT_COMMIT_SHA || "LOCAL_DEV"; +} + +export function healthPayload() { + return { status: "ok", commit: runtimeCommit() }; +} + +export function verificationPayload() { + return { schemaVersion: 1, slug: SLUG, commit: runtimeCommit() }; +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/state.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/state.mjs new file mode 100644 index 0000000..03cfebc --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/state.mjs @@ -0,0 +1,62 @@ +import { fetchMarket, fetchProtocol } from "./live.mjs"; +import { WINDOW } from "./window.mjs"; +import { SCHEMA, runtimeCommit } from "./runtime.mjs"; +import { temporalSummary } from "./windows.mjs"; + +export async function buildState({ fetchImpl = fetch, now = new Date() } = {}) { + const [market, protocol] = await Promise.all([ + fetchMarket(fetchImpl), fetchProtocol(fetchImpl) + ]); + const observedAt = now.toISOString(); + const sourceAgeMs = Math.max(0, now.getTime() - market.source_close_time_ms); + const freshness = sourceAgeMs <= 120000 ? "FRESH" : "STALE"; + const epochStart = 840000; + const nextEpoch = 1050000; + const height = protocol.height; + const progress = height === null ? null : Math.max(0, Math.min(1, (height - epochStart) / (nextEpoch - epochStart))); + const boundary = new Date(WINDOW.boundary_utc); + const phase = now < boundary ? "PRE_BOUNDARY" : "POST_BOUNDARY"; + const baseline = WINDOW.baseline.btcusdt_last_price; + const deltaPct = ((market.last_price_usdt - baseline) / baseline) * 100; + + return { + schema: SCHEMA, + commit: runtimeCommit(), + observed_at_utc: observedAt, + boundary: "RESEARCH_STATE_NOT_TRADE", + market: { ...market, freshness, source_age_ms: sourceAgeMs }, + protocol_time: { + halving_epoch: 4, + epoch_start_height: epochStart, + next_epoch_height: nextEpoch, + block_subsidy_btc: 3.125, + live_tip_height: height, + epoch_progress_pct: progress === null ? null : Number((progress * 100).toFixed(4)), + source: protocol.source, + source_status: protocol.status + }, + window: { + ...WINDOW, + phase, + current_vs_baseline_pct: Number(deltaPct.toFixed(4)), + comparison_status: phase === "PRE_BOUNDARY" ? "NOT_FINAL_BEFORE_BOUNDARY" : "REALITY_COMPARISON_OPEN" + }, + temporal_evidence: temporalSummary(now), + memory: { + law: "FIELD → WINDOW → REALITY → MEMORY", + append_only: true, + retroactive_rewrite: "forbidden" + }, + authority: { + trading: false, wallet: false, payment: false, withdrawal: false, + transfer: false, private_account_data: false, credentials_read: false + }, + limits: { + method: "GET", + symbol: "BTCUSDT only", + auth: "none", + market_source: "public Binance Spot", + protocol_source: "public mempool.space tip height" + } + }; +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/window-sep17.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/window-sep17.mjs new file mode 100644 index 0000000..4f385ef --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/window-sep17.mjs @@ -0,0 +1,24 @@ +export const SEP_17_2026 = Object.freeze({ + id: "SEP_17_2026", + boundary_utc: "2026-09-17T00:00:00Z", + role: "precommitted_observation_boundary", + baseline: Object.freeze({ + captured_at_utc: "2026-09-10T04:49:49.136Z", + btcusdt_last_price: 78348.09, + btcusdt_24h_change_pct: -0.983, + btcusdt_24h_high: 79760, + btcusdt_24h_low: 77770, + bitcoin_tip_height: 966302 + }), + provenance: Object.freeze({ + source_runtime_commit: "05a455ba1407f7b07de226f6c78eefda15b24880", + market_crosscheck_last_price_usdt: 78348.10, + market_crosscheck_abs_diff_usdt: 0.01, + note: "Captured after SEP_10 boundary and committed before SEP_17 boundary." + }), + invariants: Object.freeze({ + retroactive_rewrite: "forbidden", + price_target: false, + trading_signal: false + }) +}); diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/window.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/window.mjs new file mode 100644 index 0000000..da05e97 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/window.mjs @@ -0,0 +1,18 @@ +export const WINDOW = Object.freeze({ + id: "SEP_10_2026", + boundary_utc: "2026-09-10T00:00:00Z", + role: "precommitted_observation_boundary", + baseline: { + captured_at_utc: "2026-09-08T11:25:23Z", + btcusdt_last_price: 78474, + btcusdt_24h_change_pct: -1.226, + btcusdt_24h_high: 79643.5, + btcusdt_24h_low: 78179.98, + bitcoin_tip_height: 966060 + }, + invariants: { + retroactive_rewrite: "forbidden", + price_target: false, + trading_signal: false + } +}); diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/windows.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/windows.mjs new file mode 100644 index 0000000..1b95216 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/lib/windows.mjs @@ -0,0 +1,56 @@ +import { WINDOW as SEP_10_2026 } from "./window.mjs"; +import { SEP_17_2026 } from "./window-sep17.mjs"; +import { EVIDENCE_LEDGER } from "./evidence.mjs"; +import { WINDOW_INTEGRITY, EVIDENCE_INTEGRITY } from "./integrity.mjs"; + +export const WINDOWS = Object.freeze([SEP_10_2026, SEP_17_2026]); + +export function phaseForWindow(window, now = new Date()) { + return now < new Date(window.boundary_utc) ? "PRE_BOUNDARY" : "POST_BOUNDARY"; +} + +export function evidenceForWindow(windowId) { + return EVIDENCE_LEDGER.filter((item) => item.window_id === windowId); +} + +export function listWindows(now = new Date()) { + return WINDOWS.map((window) => ({ + id: window.id, + boundary_utc: window.boundary_utc, + baseline_captured_at_utc: window.baseline.captured_at_utc, + phase: phaseForWindow(window, now), + durable_evidence_count: evidenceForWindow(window.id).length, + precommit_sha256: WINDOW_INTEGRITY[window.id]?.sha256 ?? null, + retroactive_rewrite: window.invariants.retroactive_rewrite, + trading_signal: window.invariants.trading_signal + })); +} + +export function getWindow(windowId, now = new Date()) { + const window = WINDOWS.find((item) => item.id === windowId); + if (!window) return null; + return { + window, + phase: phaseForWindow(window, now), + integrity: { + precommit: WINDOW_INTEGRITY[windowId] ?? null, + evidence: EVIDENCE_INTEGRITY[windowId] ?? null + }, + evidence: evidenceForWindow(windowId) + }; +} + +export function temporalSummary(now = new Date()) { + const windows = listWindows(now); + const next = windows.find((item) => item.phase === "PRE_BOUNDARY") || null; + return { + schema: "bhrigu_temporal_evidence_index_v0_1", + law: "FIELD → WINDOW → REALITY → MEMORY → NEXT WINDOW", + append_only: true, + hash_bound_artifacts: true, + durable_evidence_count: EVIDENCE_LEDGER.length, + window_count: windows.length, + next_window_id: next?.id ?? null, + next_boundary_utc: next?.boundary_utc ?? null + }; +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/package-lock.json b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/package-lock.json new file mode 100644 index 0000000..625fafe --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/package-lock.json @@ -0,0 +1,15 @@ +{ + "name": "bhrigu-bitcoin-research-state-api", + "version": "0.2.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bhrigu-bitcoin-research-state-api", + "version": "0.2.0", + "engines": { + "node": ">=22" + } + } + } +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/package.json b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/package.json new file mode 100644 index 0000000..2ebdb21 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/package.json @@ -0,0 +1,14 @@ +{ + "name": "bhrigu-bitcoin-research-state-api", + "version": "0.2.0", + "type": "module", + "description": "IP-safe read-only Bitcoin temporal-evidence API and MCP server for X-Agent Open Innovation.", + "scripts": { + "start": "node server.mjs", + "test": "node tests/acceptance.mjs && node tests/temporal.mjs && node tests/mcp.mjs && node tests/integrity.mjs", + "check": "npm test" + }, + "engines": { + "node": ">=22" + } +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/server.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/server.mjs new file mode 100644 index 0000000..b6c88fe --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/server.mjs @@ -0,0 +1,70 @@ +import http from "node:http"; +import { buildState } from "./lib/state.mjs"; +import { healthPayload, verificationPayload } from "./lib/runtime.mjs"; +import { getWindow, listWindows, temporalSummary } from "./lib/windows.mjs"; +import { handleMcpRpc } from "./lib/mcp.mjs"; +import { openapiPayload } from "./lib/openapi.mjs"; + +const port = Number(process.env.PORT || 3000); +const json = (res, status, body) => { + res.writeHead(status, { "content-type": "application/json", "access-control-allow-origin": "*" }); + res.end(body === null ? "" : JSON.stringify(body)); +}; +const readJson = (req) => new Promise((resolve, reject) => { + let raw = ""; + req.on("data", (chunk) => { + raw += chunk; + if (raw.length > 65536) reject(new Error("BODY_TOO_LARGE")); + }); + req.on("end", () => { + try { resolve(raw ? JSON.parse(raw) : null); } catch (error) { reject(error); } + }); + req.on("error", reject); +}); + +http.createServer(async (req, res) => { + const url = new URL(req.url, `http://${req.headers.host}`); + + if (url.pathname === "/mcp") { + if (req.method !== "POST") return json(res, 405, { error: "METHOD_NOT_ALLOWED", allowed: ["POST"] }); + try { + const result = await handleMcpRpc(await readJson(req), { + transportMeta: { + requireHeaders: true, + protocolVersion: req.headers["mcp-protocol-version"] ?? null, + method: req.headers["mcp-method"] ?? null, + name: req.headers["mcp-name"] ?? null + } + }); + if (result.status === 202) return json(res, 202, null); + return json(res, result.status, result.body); + } catch { + return json(res, 400, { jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } }); + } + } + + if (req.method !== "GET") return json(res, 405, { error: "METHOD_NOT_ALLOWED" }); + if (url.pathname === "/health") return json(res, 200, healthPayload()); + if (url.pathname === "/.well-known/xagent-verification.json") return json(res, 200, verificationPayload()); + if (url.pathname === "/openapi.json") return json(res, 200, openapiPayload()); + if (url.pathname === "/v1/windows") return json(res, 200, { ...temporalSummary(), windows: listWindows() }); + if (url.pathname.startsWith("/v1/windows/")) { + const id = decodeURIComponent(url.pathname.slice("/v1/windows/".length)); + const record = getWindow(id); + return record ? json(res, 200, record) : json(res, 404, { error: "WINDOW_NOT_FOUND" }); + } + if (url.pathname === "/") return json(res, 200, { + name: "BHRIGU Bitcoin Temporal Evidence", + endpoint: "/v1/state", + windows: "/v1/windows", + mcp: "/mcp", + openapi: "/openapi.json", + boundary: "RESEARCH_STATE_NOT_TRADE" + }); + if (url.pathname !== "/v1/state") return json(res, 404, { error: "NOT_FOUND" }); + if ((url.searchParams.get("symbol") || "BTCUSDT").toUpperCase() !== "BTCUSDT") { + return json(res, 400, { error: "UNSUPPORTED_SYMBOL", supported: ["BTCUSDT"] }); + } + try { return json(res, 200, await buildState()); } + catch (error) { return json(res, 502, { error: "PUBLIC_MARKET_SOURCE_UNAVAILABLE", detail: String(error.message || error), trading_authority: false }); } +}).listen(port, () => console.log(`BHRIGU temporal evidence API listening on ${port}`)); diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/tests/acceptance.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/tests/acceptance.mjs new file mode 100644 index 0000000..7846afe --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/tests/acceptance.mjs @@ -0,0 +1,75 @@ +import assert from "node:assert/strict"; +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { buildState } from "../lib/state.mjs"; +import { healthPayload, verificationPayload, SLUG } from "../lib/runtime.mjs"; + +process.env.BHRIGU_COMMIT = "a".repeat(40); + +const fakeFetch = async (url) => { + if (String(url).includes("data-api.binance.vision")) { + return new Response(JSON.stringify({ + lastPrice: "79000.00", + priceChangePercent: "1.25", + highPrice: "80000.00", + lowPrice: "77000.00", + volume: "12345.67", + closeTime: Date.parse("2026-09-08T12:00:00Z") + }), { status: 200, headers: { "content-type": "application/json" } }); + } + if (String(url).includes("mempool.space")) return new Response("966100", { status: 200 }); + throw new Error("UNEXPECTED_URL"); +}; + +const health = healthPayload(); +assert.equal(health.status, "ok"); +assert.match(health.commit, /^[a-f0-9]{40}$/); +assert.deepEqual(verificationPayload(), { schemaVersion: 1, slug: SLUG, commit: "a".repeat(40) }); + +const pre = await buildState({ fetchImpl: fakeFetch, now: new Date("2026-09-08T12:00:30Z") }); +assert.equal(pre.market.symbol, "BTCUSDT"); +assert.equal(pre.market.last_price_usdt, 79000); +assert.equal(pre.market.freshness, "FRESH"); +assert.equal(pre.protocol_time.halving_epoch, 4); +assert.equal(pre.protocol_time.live_tip_height, 966100); +assert.equal(pre.window.phase, "PRE_BOUNDARY"); +assert.equal(pre.window.comparison_status, "NOT_FINAL_BEFORE_BOUNDARY"); +assert.equal(pre.memory.append_only, true); +assert.equal(pre.memory.retroactive_rewrite, "forbidden"); +assert.deepEqual(pre.authority, { + trading: false, + wallet: false, + payment: false, + withdrawal: false, + transfer: false, + private_account_data: false, + credentials_read: false +}); + +const post = await buildState({ fetchImpl: fakeFetch, now: new Date("2026-09-10T01:00:00Z") }); +assert.equal(post.window.phase, "POST_BOUNDARY"); +assert.equal(post.window.comparison_status, "REALITY_COMPARISON_OPEN"); +assert.equal(Number.isFinite(post.window.current_vs_baseline_pct), true); + +const here = path.dirname(fileURLToPath(import.meta.url)); +const root = path.resolve(here, ".."); +const liveSource = fs.readFileSync(path.join(root, "lib/live.mjs"), "utf8"); +const urls = [...liveSource.matchAll(/https:\/\/[^"\s]+/g)].map((m) => m[0]); +assert.deepEqual(urls.sort(), [ + "https://data-api.binance.vision/api/v3/ticker/24hr?symbol=BTCUSDT", + "https://mempool.space/api/blocks/tip/height" +].sort()); +const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8")); +assert.equal(pkg.dependencies, undefined); + +await assert.rejects( + () => buildState({ fetchImpl: async () => { throw new Error("OFFLINE"); } }), + /OFFLINE/ +); + +console.log(JSON.stringify({ + schema: "bhrigu_bitcoin_research_state_acceptance_v0_1", + status: "PASS", + checks: 18 +}, null, 2)); diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/tests/integrity.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/tests/integrity.mjs new file mode 100644 index 0000000..9a2c79e --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/tests/integrity.mjs @@ -0,0 +1,39 @@ +import assert from "node:assert/strict"; +import crypto from "node:crypto"; +import fs from "node:fs"; +import { SEP_10_POSTBOUNDARY_EVIDENCE } from "../lib/evidence.mjs"; +import { SEP_17_2026 } from "../lib/window-sep17.mjs"; +import { WINDOW_INTEGRITY, EVIDENCE_INTEGRITY } from "../lib/integrity.mjs"; + +const sha256 = (path) => crypto.createHash("sha256").update(fs.readFileSync(new URL(path, import.meta.url))).digest("hex"); + +assert.equal(sha256("../lib/window.mjs"), WINDOW_INTEGRITY.SEP_10_2026.sha256, "SEP_10_2026 precommit changed"); +assert.equal(sha256("../evidence/SEP_17_2026_PRECOMMIT.json"), WINDOW_INTEGRITY.SEP_17_2026.sha256, "SEP_17_2026 precommit proof changed"); +assert.equal(sha256("../evidence/SEP_10_2026_POSTBOUNDARY.json"), EVIDENCE_INTEGRITY.SEP_10_2026.sha256, "SEP_10_2026 evidence changed"); + +const sep10Json = JSON.parse(fs.readFileSync(new URL("../evidence/SEP_10_2026_POSTBOUNDARY.json", import.meta.url), "utf8")); +assert.equal(sep10Json.window_id, SEP_10_POSTBOUNDARY_EVIDENCE.window_id); +assert.equal(sep10Json.observed_btcusdt, SEP_10_POSTBOUNDARY_EVIDENCE.observation.btcusdt_last_price); +assert.equal(sep10Json.runtime_commit, SEP_10_POSTBOUNDARY_EVIDENCE.provenance.runtime_commit); + +const sep17Json = JSON.parse(fs.readFileSync(new URL("../evidence/SEP_17_2026_PRECOMMIT.json", import.meta.url), "utf8")); +assert.equal(sep17Json.window_id, SEP_17_2026.id); +assert.equal(sep17Json.boundary_utc, SEP_17_2026.boundary_utc); +assert.equal(sep17Json.btcusdt_last_price, SEP_17_2026.baseline.btcusdt_last_price); + +const stateSource = fs.readFileSync(new URL("../lib/state.mjs", import.meta.url), "utf8"); +const mcpSource = fs.readFileSync(new URL("../lib/mcp.mjs", import.meta.url), "utf8"); +const forbidden = [/apiKey/i, /secretKey/i, /withdraw/i, /placeOrder/i, /privateKey/i]; +for (const pattern of forbidden) assert.equal(pattern.test(mcpSource), false, `MCP source contains forbidden authority token ${pattern}`); +assert.match(stateSource, /trading: false/); +assert.match(stateSource, /wallet: false/); +assert.match(stateSource, /payment: false/); + +console.log(JSON.stringify({ + schema: "bhrigu_integrity_tests_v0_2", + status: "PASS", + sep10_window_sha256: WINDOW_INTEGRITY.SEP_10_2026.sha256, + sep10_evidence_sha256: EVIDENCE_INTEGRITY.SEP_10_2026.sha256, + sep17_precommit_sha256: WINDOW_INTEGRITY.SEP_17_2026.sha256, + checks: 15 +})); diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/tests/mcp.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/tests/mcp.mjs new file mode 100644 index 0000000..4b52ed1 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/tests/mcp.mjs @@ -0,0 +1,143 @@ +import assert from "node:assert/strict"; +import { + handleMcpRpc, + MCP_TOOLS, + MCP_MODERN_PROTOCOL_VERSION, + MCP_SUPPORTED_PROTOCOL_VERSIONS +} from "../lib/mcp.mjs"; + +let checks = 0; +const eq = (actual, expected, message) => { assert.equal(actual, expected, message); checks += 1; }; +const deep = (actual, expected, message) => { assert.deepEqual(actual, expected, message); checks += 1; }; + +const fakeFetch = async (url) => { + if (String(url).includes("data-api.binance.vision")) { + return new Response(JSON.stringify({ + lastPrice: "79000.00", priceChangePercent: "1.25", highPrice: "80000.00", + lowPrice: "77000.00", volume: "12345.67", closeTime: Date.parse("2026-09-16T12:00:00Z") + }), { status: 200 }); + } + if (String(url).includes("mempool.space")) return new Response("967000", { status: 200 }); + throw new Error("UNEXPECTED_URL"); +}; +const now = new Date("2026-09-16T12:00:30Z"); +const modernMeta = { + "io.modelcontextprotocol/protocolVersion": MCP_MODERN_PROTOCOL_VERSION, + "io.modelcontextprotocol/clientCapabilities": {}, + "io.modelcontextprotocol/clientInfo": { name: "bhrigu-test", version: "1.0.0" } +}; +const modernTransport = (method, name = null) => ({ requireHeaders: true, protocolVersion: MCP_MODERN_PROTOCOL_VERSION, method, name }); + +const init = await handleMcpRpc({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2025-11-25" } }, { fetchImpl: fakeFetch, now }); +eq(init.status, 200); +eq(init.body.result.protocolVersion, "2025-11-25"); +eq(init.body.result.serverInfo.version, "0.2.0"); +eq(init.body.result.resultType, undefined); + +const legacyList = await handleMcpRpc({ jsonrpc: "2.0", id: 2, method: "tools/list" }, { fetchImpl: fakeFetch, now }); +eq(legacyList.status, 200); +eq(legacyList.body.result.tools.length, 4); +eq(legacyList.body.result.ttlMs, undefined); + +const discover = await handleMcpRpc({ jsonrpc: "2.0", id: 3, method: "server/discover", params: { _meta: modernMeta } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("server/discover") }); +eq(discover.status, 200); +eq(discover.body.result.resultType, "complete"); +eq(discover.body.result.ttlMs, 300000); +eq(discover.body.result.cacheScope, "public"); +deep(discover.body.result.supportedVersions, MCP_SUPPORTED_PROTOCOL_VERSIONS); +eq(discover.body.result.serverInfo, undefined); +eq(discover.body.result._meta["io.modelcontextprotocol/serverInfo"].name, "bhrigu-bitcoin-research-state-api"); + +const list = await handleMcpRpc({ jsonrpc: "2.0", id: 4, method: "tools/list", params: { _meta: modernMeta } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/list") }); +eq(list.status, 200); +eq(list.body.result.resultType, "complete"); +eq(list.body.result.tools.length, 4); +deep(list.body.result.tools.map((t) => t.name), MCP_TOOLS.map((t) => t.name)); +eq(list.body.result.tools.every((t) => t.annotations.readOnlyHint === true), true); +eq(list.body.result.ttlMs, 300000); +eq(list.body.result.cacheScope, "public"); + +const noClientInfo = await handleMcpRpc({ jsonrpc: "2.0", id: 41, method: "tools/list", params: { _meta: { + "io.modelcontextprotocol/protocolVersion": MCP_MODERN_PROTOCOL_VERSION, + "io.modelcontextprotocol/clientCapabilities": {} +} } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/list") }); +eq(noClientInfo.status, 200); + +const malformedClientInfo = await handleMcpRpc({ jsonrpc: "2.0", id: 42, method: "tools/list", params: { _meta: { + ...modernMeta, "io.modelcontextprotocol/clientInfo": { name: "missing-version" } +} } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/list") }); +eq(malformedClientInfo.status, 400); +eq(malformedClientInfo.body.error.code, -32602); + +const windowResult = await handleMcpRpc({ jsonrpc: "2.0", id: 5, method: "tools/call", params: { + name: "bhrigu_get_temporal_window", arguments: { window_id: "SEP_10_2026" }, _meta: modernMeta +} }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/call", "bhrigu_get_temporal_window") }); +eq(windowResult.status, 200); +eq(windowResult.body.result.resultType, "complete"); +eq(windowResult.body.result.isError, false); +eq(windowResult.body.result.structuredContent.window.id, "SEP_10_2026"); +eq(windowResult.body.result.structuredContent.evidence.length, 1); + +const compare = await handleMcpRpc({ jsonrpc: "2.0", id: 6, method: "tools/call", params: { + name: "bhrigu_compare_window_to_reality", arguments: { window_id: "SEP_17_2026" }, _meta: modernMeta +} }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/call", "bhrigu_compare_window_to_reality") }); +eq(compare.body.result.isError, false); +eq(compare.body.result.resultType, "complete"); +eq(compare.body.result.structuredContent.current_btcusdt, 79000); +eq(compare.body.result.structuredContent.baseline_btcusdt, 78348.09); +eq(compare.body.result.structuredContent.trading_authority, false); + +const headerMismatch = await handleMcpRpc({ jsonrpc: "2.0", id: 7, method: "tools/list", params: { _meta: modernMeta } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/call") }); +eq(headerMismatch.status, 400); +eq(headerMismatch.body.error.code, -32020); + +const missingCaps = await handleMcpRpc({ jsonrpc: "2.0", id: 8, method: "server/discover", params: { _meta: { + "io.modelcontextprotocol/protocolVersion": MCP_MODERN_PROTOCOL_VERSION +} } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("server/discover") }); +eq(missingCaps.status, 400); +eq(missingCaps.body.error.code, -32602); + +const missingVersion = await handleMcpRpc({ jsonrpc: "2.0", id: 81, method: "server/discover", params: { _meta: { + "io.modelcontextprotocol/clientCapabilities": {} +} } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("server/discover") }); +eq(missingVersion.status, 400); +eq(missingVersion.body.error.code, -32602); + +const unsupported = await handleMcpRpc({ jsonrpc: "2.0", id: 9, method: "server/discover", params: { _meta: { + ...modernMeta, "io.modelcontextprotocol/protocolVersion": "2099-01-01" +} } }, { fetchImpl: fakeFetch, now, transportMeta: { ...modernTransport("server/discover"), protocolVersion: "2099-01-01" } }); +eq(unsupported.status, 400); +eq(unsupported.body.error.code, -32022); +eq(unsupported.body.error.data.requested, "2099-01-01"); +deep(unsupported.body.error.data.supported, MCP_SUPPORTED_PROTOCOL_VERSIONS); + +const unsupportedOrdinary = await handleMcpRpc({ jsonrpc: "2.0", id: 10, method: "tools/list", params: { _meta: { + ...modernMeta, "io.modelcontextprotocol/protocolVersion": "2099-01-01" +} } }, { fetchImpl: fakeFetch, now, transportMeta: { ...modernTransport("tools/list"), protocolVersion: "2099-01-01" } }); +eq(unsupportedOrdinary.status, 400); +eq(unsupportedOrdinary.body.error.code, -32022); + +const unsupportedHeaderOnly = await handleMcpRpc({ jsonrpc: "2.0", id: 101, method: "tools/list" }, { fetchImpl: fakeFetch, now, + transportMeta: { requireHeaders: true, protocolVersion: "2099-01-01", method: "tools/list", name: null } }); +eq(unsupportedHeaderOnly.status, 400); +eq(unsupportedHeaderOnly.body.error.code, -32022); + +const modernPing = await handleMcpRpc({ jsonrpc: "2.0", id: 102, method: "ping", params: { _meta: modernMeta } }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("ping") }); +eq(modernPing.status, 404); +eq(modernPing.body.error.code, -32601); + +const modernNotification = await handleMcpRpc({ jsonrpc: "2.0", method: "notifications/example", params: { _meta: modernMeta } }, { fetchImpl: fakeFetch, now, transportMeta: { requireHeaders: true } }); +eq(modernNotification.status, 202); +eq(modernNotification.body, null); + +const bad = await handleMcpRpc({ jsonrpc: "2.0", id: 11, method: "tools/call", params: { + name: "bhrigu_get_temporal_window", arguments: { window_id: "NOPE" }, _meta: modernMeta +} }, { fetchImpl: fakeFetch, now, transportMeta: modernTransport("tools/call", "bhrigu_get_temporal_window") }); +eq(bad.body.result.isError, true); +eq(bad.body.result.structuredContent.error.code, "WINDOW_NOT_FOUND"); + +const invalid = await handleMcpRpc({ hello: "world" }); +eq(invalid.status, 400); +eq(invalid.body.error.code, -32600); + +console.log(JSON.stringify({ schema: "bhrigu_mcp_tests_v0_4", status: "PASS", checks })); diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/tests/temporal.mjs b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/tests/temporal.mjs new file mode 100644 index 0000000..d36b031 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/tests/temporal.mjs @@ -0,0 +1,35 @@ +import assert from "node:assert/strict"; +import { getWindow, listWindows, temporalSummary } from "../lib/windows.mjs"; +import { SEP_10_POSTBOUNDARY_EVIDENCE } from "../lib/evidence.mjs"; + +const before = new Date("2026-09-16T23:59:59Z"); +const after = new Date("2026-09-17T00:00:01Z"); + +const windowsBefore = listWindows(before); +assert.equal(windowsBefore.length, 2); +assert.equal(windowsBefore[0].id, "SEP_10_2026"); +assert.equal(windowsBefore[0].phase, "POST_BOUNDARY"); +assert.equal(windowsBefore[0].durable_evidence_count, 1); +assert.equal(windowsBefore[1].id, "SEP_17_2026"); +assert.equal(windowsBefore[1].phase, "PRE_BOUNDARY"); + +const sep10 = getWindow("SEP_10_2026", before); +assert.equal(sep10.window.baseline.btcusdt_last_price, 78474); +assert.equal(sep10.evidence.length, 1); +assert.equal(sep10.evidence[0].id, SEP_10_POSTBOUNDARY_EVIDENCE.id); +assert.equal(sep10.evidence[0].observation.btcusdt_last_price, 78348.09); +assert.equal(sep10.evidence[0].invariants.append_only, true); + +const sep17 = getWindow("SEP_17_2026", before); +assert.equal(sep17.window.baseline.captured_at_utc, "2026-09-10T04:49:49.136Z"); +assert.equal(sep17.window.baseline.btcusdt_last_price, 78348.09); +assert.equal(sep17.evidence.length, 0); +assert.equal(getWindow("SEP_17_2026", after).phase, "POST_BOUNDARY"); + +const summary = temporalSummary(before); +assert.equal(summary.window_count, 2); +assert.equal(summary.durable_evidence_count, 1); +assert.equal(summary.next_window_id, "SEP_17_2026"); +assert.equal(summary.append_only, true); + +console.log(JSON.stringify({ schema: "bhrigu_temporal_tests_v0_1", status: "PASS", checks: 17 })); diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/vercel.json b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/vercel.json new file mode 100644 index 0000000..9cebdc1 --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/source/vercel.json @@ -0,0 +1,12 @@ +{ + "rewrites": [ + { "source": "/", "destination": "/api/about" }, + { "source": "/health", "destination": "/api/health" }, + { "source": "/.well-known/xagent-verification.json", "destination": "/api/verification" }, + { "source": "/openapi.json", "destination": "/api/openapi" }, + { "source": "/mcp", "destination": "/api/mcp" }, + { "source": "/v1/state", "destination": "/api/state" }, + { "source": "/v1/windows", "destination": "/api/windows" }, + { "source": "/v1/windows/:id", "destination": "/api/window?id=:id" } + ] +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/submission.json b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/submission.json new file mode 100644 index 0000000..3d97f2d --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/submission.json @@ -0,0 +1,10 @@ +{ + "schemaVersion": 1, + "name": "BHRIGU Bitcoin Temporal Evidence", + "slug": "bhrigu-bitcoin-research-state-api", + "sourceRepository": "https://github.com/AiBhrigu/bhrigu-bitcoin-research-state-api", + "reviewCommit": "905adc26632e4595d998c01da26b3ccd88bf8a6f", + "apiBaseUrl": "https://bhrigu-bitcoin-research-state-api.vercel.app/v1", + "healthCheckUrl": "https://bhrigu-bitcoin-research-state-api.vercel.app/health", + "deploymentProofUrl": "https://bhrigu-bitcoin-research-state-api.vercel.app/.well-known/xagent-verification.json" +} diff --git a/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/verification/README.md b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/verification/README.md new file mode 100644 index 0000000..e79b28b --- /dev/null +++ b/submissions/mcp-hackathon/bhrigu-bitcoin-research-state-api/verification/README.md @@ -0,0 +1,68 @@ +# Verification evidence + +## Prerequisites + +- Review commit: `905adc26632e4595d998c01da26b3ccd88bf8a6f` +- API origin: `https://bhrigu-bitcoin-research-state-api.vercel.app` +- Authentication: none + +## 1. Exact deployment binding + +```bash +curl --fail --silent --show-error https://bhrigu-bitcoin-research-state-api.vercel.app/health +curl --fail --silent --show-error https://bhrigu-bitcoin-research-state-api.vercel.app/.well-known/xagent-verification.json +``` + +Expected: HTTP 200; both surfaces expose commit `905adc26632e4595d998c01da26b3ccd88bf8a6f`; verification also exposes slug `bhrigu-bitcoin-research-state-api`. + +## 2. Temporal registry + +```bash +curl --fail --silent --show-error https://bhrigu-bitcoin-research-state-api.vercel.app/v1/windows +curl --fail --silent --show-error https://bhrigu-bitcoin-research-state-api.vercel.app/v1/windows/SEP_10_2026 +``` + +Expected: two windows; `SEP_10_2026` is post-boundary with one durable evidence record and `retroactive_rewrite: forbidden`; `SEP_17_2026` is the next precommitted window before `2026-09-17T00:00:00Z`. + +## 3. Live state + +```bash +curl --fail --silent --show-error 'https://bhrigu-bitcoin-research-state-api.vercel.app/v1/state?symbol=BTCUSDT' +``` + +Expected properties: exact review commit; `market.symbol = BTCUSDT`; public-source freshness; Bitcoin protocol-time coordinates; temporal evidence summary; every financial/private field under `authority` is `false`. + +## 4. Modern MCP discovery + +```bash +curl --fail --silent --show-error -X POST \ + https://bhrigu-bitcoin-research-state-api.vercel.app/mcp \ + -H 'content-type: application/json' \ + -H 'MCP-Protocol-Version: 2026-07-28' \ + -H 'Mcp-Method: server/discover' \ + --data '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}' +``` + +Expected: HTTP 200, `resultType: complete`, supported modern version `2026-07-28`, and read-only server capabilities. + +## 5. MCP locked-past read + +Call `tools/call` with `Mcp-Name: bhrigu_get_temporal_window`, `window_id: SEP_10_2026`, the same protocol metadata, and matching `Mcp-Method: tools/call`. Expected: the frozen SEP10 window plus its durable post-boundary evidence, with no write side effect. + +## 6. Safe failure behavior + +- `GET /v1/state?symbol=ETHUSDT` → HTTP 400 `UNSUPPORTED_SYMBOL`. +- write methods on read-only HTTP surfaces → rejected. +- unsupported modern MCP protocol version → fail-closed protocol error. +- modern MCP header/body method or tool-name mismatch → fail closed. +- unavailable Binance market evidence → no fabricated live market state. + +## 7. Reproducible source verification + +```bash +cd source +npm ci +npm test +``` + +Expected deterministic suites: acceptance 18 + temporal 17 + MCP 56 + integrity 15 = 106 PASS. Integrity tests pin the original SEP10 source hash and committed evidence artifacts.