mcpField
Q
qeaas-mcp

qeaas-mcp

远程服务
qeaas.eu安全2今天更新

关于 qeaas-mcp

qeaas-mcp 是面向需要随机数、密码学种子或 ML-KEM-768 密钥材料的应用的 FastAPI 服务。它以导入的 QRNG 熵为 HMAC-DRBG 提供种子,并为输出附上可验证的签名来源凭证。

主要功能

  1. 01导入并加密存储 QRNG 熵
  2. 02使用 HMAC-DRBG 生成随机字节
  3. 03提供掷骰结果和密码学种子
  4. 04生成及封装 ML-KEM-768 密钥
  5. 05签发 Ed25519 来源凭证

适用场景

  1. 01为应用获取随机字节
  2. 02生成密码学工作流所需的种子
  3. 03创建后量子 ML-KEM-768 密钥
  4. 04验证所获输出的来源

MCP 相关

输入将 qeaas-mcp 标记为服务端,但没有说明 MCP 接口或相关能力。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://api.qeaas.eu/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

6
参数类型必填说明
bytesinteger否

详细介绍

量子熵即服务(Q-EaaS)— API 参考

需要 API 密钥?请发送邮件至 [email protected]。

FastAPI 服务,可将预加载的 **QRNG(量子随机数生成器)**比特转换为提供的随机数、骰子点数、加密种子和后量子 ML-KEM 密钥材料——每次生成都会附带一份经过签名、可离线验证的来源凭证。

单体仓库布局:api/(本文档 — FastAPI 服务)、web/(Next.js 说明与演示)、shared/(文档、实验项目)、claude/(史诗级构建计划)。Web 应用是 API 上的轻量客户端;所有实质性工作都在这里完成。

坦诚说明一次,并适用于所有内容。 QRNG 不会“击败量子攻击者”。原始 QRNG 比特绝不会直接提供。它们是用于为符合标准的 HMAC-DRBG(NIST SP 800-90A)提供种子的熵。本 API 返回的每个字节——/random、/dice、/v1/random/bytes、ML-KEM 种子——都是 DRBG 输出。量子部分是熵源;任何量子抗性都来自 ML-KEM-768(FIPS 203),而非所谓“量子”随机性。


1. 架构一览

             ┌──────────── admin (X-Admin-Token) ────────────┐
             │                                                │
   QRNG .txt │  POST /admin/ingest                            │  POST /admin/keys
  (0/1 bits) ▼                                                ▼  POST /admin/keys/revoke
        ┌─────────────┐   AES-256-GCM    ┌───────────────────────────────┐
        │ pool.parse  │ ───────────────▶ │  Postgres (Neon)              │
        │ + encrypt   │                  │   entropy_pool  (ciphertext)  │
        └─────────────┘                  │   drbg_root     (ciphertext)  │
                                         │   api_keys / usage_log /      │
                                         │   issue_log                   │
                                         └───────────────┬───────────────┘
                                                         │ decrypt slice on reseed
                                                         ▼
   client                    ┌───────────────────────────────────────┐
  ─────────▶  entropy gate   │  keyed_drbg.output(n)                  │
  request     (503 if low)   │   root_key  ← reseeded from pool       │
             + rate limit ──▶│   counter   ← Redis atomic INCR        │──▶ HMAC-DRBG(SHA-256)
             + API key       │   HMAC-DRBG(root_key, counter) → bytes │      = served bytes
                             └───────────────────────────────────────┘
                                                         │
                             ┌───────────────────────────┴───────────┐
                             │  Redis (Upstash)                       │
                             │   drbg:counter   (output uniqueness)   │
                             │   rl:* / quota:* / anon:* (throttling) │
                             └────────────────────────────────────────┘
  • 无状态 / 无服务器。 每个请求都会打开并关闭一个 Postgres 连接(db.connect);不会创建长期运行的连接池对象。DRBG 状态不会在每个请求中执行读取—修改—写入操作——参见 §4。
  • 两个数据存储,各司其职——参见 §3。
  • CORS 仅允许 WEB_ORIGIN 中列出的来源(以逗号分隔)。
  • 每个响应都带有 X-Quantum-Entropy: healthy|degraded 标头(由 main.py 中间件添加)。

源代码映射(api/qeaas/):

模块职责
main.pyFastAPI 应用、所有路由处理程序、CORS、熵标头中间件
generation.py唯一的随机数输出入口 + 来源元数据构建器
keyed_drbg.py适用于无服务器环境的 DRBG 封装:重新播种计划、Redis 计数器混合
drbg.py纯 NIST SP 800-90A HMAC-DRBG(SHA-256)
pool.py熵池:解析 0/1、AES-256-GCM 加密/解密、HKDF 子密钥、burn()
db.py为全部五张表提供参数化 psycopg 辅助函数
redis_client.py延迟初始化的 Upstash 客户端:原子计数器 + 速率限制操作
gate.py低熵门控(entropy_level、require_entropy 依赖项)
auth.py管理员令牌校验、API 密钥哈希 + 验证
ratelimit.py按 IP / 密钥实施速率限制、匿名用户每日上限、按密钥配额
dice.py采用拒绝采样的骰子点数(无模运算偏差)
kem.py由 QRNG 播种的 ML-KEM-768 密钥生成 + 封装
receipts.pyEd25519 凭证签名 + 验证
errors.py所有失败均使用扁平的 {"error": "<slug>"} 封装格式
schemas.pyPydantic 请求/响应模型

2. 随机数流水线(触发顺序)

每个输出字节都流经同一个关口:generation.random_bytes(n) → keyed_drbg.output(n)。没有任何路径可以绕过它。

A. 写入(管理员操作,不在请求路径中)。 POST /admin/ingest → pool.ingest_bits_bytes() → pool.parse_bits_bytes() 将 0/1 文本按最高有效位优先的顺序打包为字节(丢弃末尾不完整的字节,拒绝任何非 0/1 字符)→ pool.encrypt_chunk() 使用 AES-256-GCM 加密 → db.insert_pool_chunk() 将 (ciphertext, nonce, tag, plaintext_len, source_label) 存入 entropy_pool。明文不会接触磁盘;上传缓冲区会被 burn()。

B. 服务(每个请求)。 keyed_drbg.output(n):

  1. maybe_reseed() — 加载预热的根密钥缓存(_load_cache),首次使用时从池中引导生成根密钥(_bootstrap_root_key)。如果到了重新播种时间(§4),pool.pull_reseed_material(32) 会从 entropy_pool 解密下一个尚未使用的 32 字节切片,将其加密为新的 drbg_root 行,推进 consumed_offset,并对明文执行 burn()。
  2. redis_client.incr_counter() — 原子执行 INCR drbg:counter,返回一个全局唯一整数。
  3. 使用解密后的 root_key 实例化新的 HmacDrbg,并调用 generate(n, additional = counter.to_bytes(8) + additional) — 计数器确保即使根密钥相同,并发请求也绝不可能生成相同输出。
  4. db.bump_outputs_since_reseed() 增加重新播种里程计。

C. 封装(每个端点)。 generation.new_issue_meta(size) 生成一个 request_id(uuid4),读取 entropy_epoch(= drbg_root.reseed_counter),记录时间戳,并调用 receipts.sign(...) 生成 Ed25519 回执。随后,使用密钥的端点会写入 db.insert_usage_log()(用于发现滥用)和 db.insert_issue_log()(仅元数据溯源 — 绝不会存储输出字节)。

有关精确的调用图,请参阅本文件末尾的深入分析注释 / 聊天分析。


3. 为什么使用两个数据库

它们用于防范完全不同的故障模式,并且对一致性的需求也截然相反。

Postgres(Neon)——持久化密钥库和审计账本

存储所有必须保留且必须具备事务性和持久性的数据。共五张表:

表存储内容备注
entropy_poolQRNG 位流的 AES-256-GCM 密文,以及 nonce、tag、plaintext_len、consumed_offset、source_label密库。不存在明文字节列。consumed_offset 记录每个数据块已消耗的部分。
drbg_root当前 DRBG 根种子的 AES-256-GCM 密文,以及 reseed_counter、outputs_since_reseed、rotated_at当前 DRBG 密钥,按计划从池中轮换(“重新播种”)。reseed_counter == 回执中的 entropy_epoch,也等于 /health 中的 drbg_reseeds。
api_keyskey_hash(加盐的 HMAC-SHA256)、owner、tier、daily_quota_bytes、revoked、created_at从不存储明文密钥。每个请求都会重新读取,因此撤销会立即生效。
usage_log(ts, principal, endpoint, nbytes)用于发现带密钥请求中滥用行为的账本。匿名的 /random//dice 不会记录在此。
issue_log(request_id, principal, endpoint, size, epoch_id, ts)仅元数据溯源。从来不存在输出字节列——验证溯源信息,而不是秘密本身。

持久性至关重要:如果丢失池密文或根密钥,服务将无法再证明溯源信息或重新播种。Postgres 符合 ACID;正确性由它保障。

Redis (Upstash) — 临时原子计数器与限流器

仅保存快速、可丢弃、以原子方式修改的计数器;在无服务器并发场景下,若将它们存放在 Postgres 中会带来正确性风险:

KeyPurposeOp
drbg:counter输出唯一性。 每次 DRBG 调用都会混入一个单调递增的整数,确保两个并发的无服务器调用不会生成相同字节。INCR
rl:ip:{ip}:{minute}按 IP 限制速率(匿名路由)INCR + EXPIRE 60
rl:key:{hash}:{minute}按密钥限制速率INCR + EXPIRE 60
anon:daily:{day}匿名输出全局上限(每天 5 MB)INCRBY + EXPIRE,退款时使用 DECRBY
quota:key:{hash}:{day}按密钥设置每日字节配额INCRBY + EXPIRE,退款时使用 DECRBY

为什么不把这些数据放在 Postgres 中?在无状态的无服务器环境中,无法安全地为每个请求对共享状态执行读取-修改-写入——两个并发请求会产生竞争。Redis 的 INCR/INCRBY 是原子操作,因此无需读取-修改-写入。这些值本就应该过期(按分钟、按天),丢失它们也无妨——Redis 故障时,限流会默认放行(记录警告日志,并允许请求),因为重新播种频率下限(§4)仍能确保池不会被耗尽。

一句话总结: Postgres = 必须永久保持正确的持久化密钥与审计数据;Redis = 必须快速且避免竞争、但可丢弃的临时原子计数器。


4. DRBG 与比特耗尽防护

  • HMAC-DRBG(SHA-256),NIST SP 800-90A §10.1.2(drbg.py)。非线程安全——每个请求都会获得自己的实例。
  • 适用于无服务器环境的封装器(keyed_drbg.py):output(n) = HMAC-DRBG(root_key, INCR(drbg:counter), n)。
  • 重新播种计划。 root_key 在以下条件中先触发时,从池中轮换:
    • 固定的 15 分钟间隔(RESEED_INTERVAL_SECONDS),或
    • 输出计数 ≥ RESEED_OUTPUT_LIMIT(100 000),但仅当 ≥ RESEED_MIN_INTERVAL_SECONDS(5 分钟)已经过去时。 每次重新播种都会从池中提取 RESEED_PULL_BYTES(32)字节。
  • 无法通过流量耗尽比特。 输出的字节始终是 DRBG 输出,而不是池中的原始比特;5 分钟下限意味着无论请求量多大,都无法比实际时间更快地轮换密钥。池的消耗取决于时间,而非流量。
  • 低熵门控。 未消耗的池字节低于 THRESHOLD(64 KiB)时,/health 会报告 degraded,所有受门控的路由都会返回 503 low_quantum_entropy(gate.require_entropy)。

5. 加密密钥层级

一个由环境变量持有的 MASTER_KEY(256 位十六进制)。pool.derive_subkey(name)(HKDF-SHA256,RFC 5869 单块 Expand)恰好派生四个具名子密钥——没有其他密钥:

MASTER_KEY  (env / KMS only — never written to Postgres)
  └── HKDF-SHA256
       ├── "pool-encryption-key"       → entropy_pool  AES-256-GCM
       ├── "drbg-root-encryption-key"  → drbg_root.root_key AES-256-GCM
       ├── "api-key-pepper"            → API-key hashing  (HMAC-SHA256)
       └── "receipt-signing-key"       → Ed25519 receipt signing seed

AES-256-GCM 带有身份验证:密文中任意字节被翻转都会导致标签检查失败并引发解密错误——服务会对被篡改的存储拒绝放行。敏感明文(解密后的切片、预热的根密钥缓存、上传缓冲区)会存放在 bytearray 中,并在使用后尽力通过 burn() 擦除(CPython 无法保证将数据完全清零;无服务器环境的拆除机制会按设计缩短进程内密钥的存续时间)。


6. 身份验证

MechanismHeaderApplies to
无(匿名)—/health、/random、/dice、/v1/verify、/v1/pubkey
API 密钥X-API-Key: <plaintext>/v1/random/bytes、/v1/kem/*
管理员令牌X-Admin-Token: <token>/admin/*
  • API 密钥:hash_api_key(key) = HMAC-SHA256(pepper, key);仅存储哈希值。require_api_key 每次请求都会读取最新记录,因此 revoked = true 会立即生效。缺少请求头 → 401 missing_api_key;未知或已撤销 → 401 invalid_api_key。
  • 管理员令牌:使用常量时间比较(hmac.compare_digest)与 ADMIN_TOKEN 进行校验。错误或缺失 → 401 unauthorized。

7. 速率限制、配额与层级

所有计数器均为原子 Redis 操作;Redis 出错时故障放行。

  • 匿名用户(按 IP): /random 和 /dice 每分钟 60 次请求(ANON_IP_PER_MIN)。

  • 匿名用户(全局每日): /random 的每日输出上限为 5 MB(ANON_DAILY_BYTES)。

  • 按密钥(/v1/*),由层级决定:

    层级每日配额速率限制
    default256 KB/天120 次请求/分钟
    iot10 MB/天600 次请求/分钟
    trusted500 MB/天1 200 次请求/分钟

    密钥的显式 daily_quota_bytes 会覆盖层级默认值;NULL 则回退至默认值。先检查速率,再检查配额(拒绝成本更低)。超出配额的请求所计字节会退还(DECRBY),因此拒绝请求不会消耗其未使用的配额。

  • 每个 429 响应都包含 Retry-After 标头(窗口重置前的秒数)。


8. 错误封装

每个失败响应都会返回扁平 JSON 正文:{"error": "<slug>"}(参见 errors.py)。常见错误标识:

状态码错误标识含义
401unauthorized / missing_api_key / invalid_api_key身份验证失败
404not_found例如,撤销未知密钥哈希
413file_too_large摄取上传超过 10 MB
422bad_request验证失败 / 输入格式错误(也包括 FastAPI 验证错误)
429rate_limited / daily_limit_reached / quota_exceeded请求受限(包含 Retry-After)
503low_quantum_entropy池低于 64 KiB,受门控的路由被阻止
500dice_sampling_failed拒绝采样耗尽抽取上限(极不可能发生)

9. 端点参考

GET /health — 匿名

用途:用于正常运行时间检查和监控仪表板 — 确认依赖的池/DRBG 未降级。 存活状态 + 池/DRBG 状态。始终不受门控。

{ "status": "ok", "quantum_entropy_level": "healthy",  // or "degraded"
  "pool_bytes_remaining": 699000, "drbg_reseeds": 3, "uptime": 1234.5 }

触发:db.get_root_key、db.pool_bytes_remaining、gate.entropy_level。

GET /random?bytes=<1..64> — 匿名,不受门控

用途:无需注册即可快速获取随机字节,适用于演示、小型脚本或其他无需密钥的轻量用途。 由 DRBG 生成的随机字节,以 base64 编码。池处于 degraded 状态时仍可用。按 IP 限速,并受匿名用户每日配额限制。

{ "bytes": 32, "format": "base64", "data": "<base64>" }

触发:ratelimit.check_ip_rate → ratelimit.check_anon_daily → generation.random_bytes。 错误:422(字节数超出范围)、429 rate_limited / daily_limit_reached。

POST /dice — 匿名,不受门控

用途:为桌面游戏机器人和赠品活动提供公平的掷骰结果,玩家可审计每次掷骰背后抽取的每个 DRBG 字节。 采用拒绝采样的掷骰(无模偏差)。按 IP 限速。 请求:{ "sides": 2..100 (default 6), "count": 1..6 (default 1) }

{ "sides": 6, "count": 2, "rolls": [3, 6], "format": "base64",
  "bytes_used": "<base64>", "bytes_count": 2 }

bytes_used / bytes_count 会回显该次掷骰抽取的每个 DRBG 字节,包括接受和拒绝的字节,因此网页掷骰工具中的“此掷骰背后的字节”开关名副其实。输出仍是 DRBG 生成的内容,绝不是原始 QRNG 比特。触发:ratelimit.check_ip_rate → dice.roll(循环调用 keyed_drbg.output(1))。 错误:422(超出范围)、429、500 dice_sampling_failed。

GET /v1/random/bytes?size=<32..4096>&format=<hex|base64> — API 密钥,受门控

用途:主要的开发者集成接口 — 提供生产级随机字节,并附带签名回执,以便日后证明其来源。 规范的开发者端点。先执行按密钥的速率限制和每日配额检查,然后写入使用记录和签发日志。

{ "request_id": "…", "format": "hex", "data": "…",
  "entropy_epoch": 3, "timestamp": "2026-…Z", "receipt": "qeaas1.<payload>.<sig>" }

触发:require_entropy(门控)→ require_api_key → ratelimit.enforce_key → generation.issue_v1(→ random_bytes + new_issue_meta + receipts.sign)→ db.insert_usage_log + db.insert_issue_log。 错误:401、429 rate_limited/quota_exceeded、503 low_quantum_entropy、422。

POST /v1/verify — 匿名,每个 IP 单独限速

用途:证明给定的输出确实来自此服务,适用于审计或争议处理,且不会再次暴露底层字节。 验证来源,而非秘密。请求:{ "request_id"?: str, "receipt"?: str }(至少需要提供 一项,否则返回 422)。

  • 提供 receipt:对签名进行密码学验证;响应会解析出 size、 entropy_epoch、timestamp 和池的 qrng_source_labels。
  • 仅提供 request_id:只查询 issue_log(note 会如实说明这一点)。
  • 收据遭篡改或伪造 → verified: false、provenance: null。
{ "request_id": "…", "verified": true,
  "provenance": { "size": 64, "entropy_epoch": 3, "timestamp": "…",
                  "qrng_source_labels": ["fez", "marrakesh"] },
  "note": "receipt signature verified cryptographically" }

触发:ratelimit.check_ip_rate → receipts.verify(→ receipts.verify_receipt 和/或 db.get_issue_log、db.get_pool_source_labels)。绝不是预言机——永远不会接受或比较输出值。

GET /v1/pubkey — 匿名

用途:使用已发布的签名密钥完全离线验证收据,无需回调此服务。 已发布的 Ed25519 收据签名公钥,供外部离线验证使用。

{ "algorithm": "Ed25519", "format": "base64", "public_key": "<base64 32-byte raw>" }
POST /v1/kem/keypair — 需要 API 密钥,受限

用途:生成后量子 ML-KEM-768 密钥材料以供测试;实际部署应在客户端生成密钥,此路由仅用于演示。 由 QRNG 播种的 ML-KEM-768(FIPS 203)密钥生成。请求:{ "include_secret_key"?: false }。 始终返回 public_key(ek);仅在演示流程中返回 secret_key(dk),并醒目标注 “仅供演示”(实际密钥生成在客户端进行;密钥持有者不会泄露密钥)。

{ "request_id": "…", "algorithm": "ML-KEM-768", "format": "base64",
  "public_key": "<ek base64>", "secret_key": null,
  "entropy_epoch": 3, "timestamp": "…", "receipt": "…", "note": null }

触发:gate → require_api_key → ratelimit.enforce_key → kem.generate_keypair (generation.random_bytes(64) → ML_KEM_768.key_derive)→ new_issue_meta → 使用情况/签发日志。

POST /v1/kem/encapsulate — 需要 API 密钥,受限

用途:针对你已持有的公钥演示 ML-KEM-768 的封装部分;服务端不存在解封装路由。 针对提供的 public_key 进行封装。请求: { "public_key": "<ek base64>", "include_shared_secret"?: false }。 始终返回 ciphertext;仅在 include_shared_secret 为真时返回 shared_secret 和示例性的 HKDF 派生 demo_key。 服务端不存在解封装路由——解封装由持有 dk 的客户端完成。

{ "request_id": "…", "algorithm": "ML-KEM-768", "format": "base64",
  "ciphertext": "<base64>", "shared_secret": null, "demo_key": null,
  "entropy_epoch": 3, "timestamp": "…", "receipt": "…", "note": null }

触发:gate → require_api_key → ratelimit.enforce_key → kem.encapsulate (generation.random_bytes(32) → ML_KEM_768._encaps_internal)→ new_issue_meta → 日志。 格式错误或长度不正确的 ek → 422 bad_request。

kyber-py 仅用于教学,且不是恒定时间实现——适用于论文演示,不适用于生产环境 (生产环境应在持久化主机上使用 liboqs)。

POST /admin/ingest — 管理员令牌

用途:操作人员用一批新的原始 QRNG 比特为熵池补充数据,这批数据在接触磁盘前就会加密。 上传包含 0/1 字符的多部分 .txt 文件(≤ 10 MB)→ 为池补充数据。在内存中解析、 加密并存储;明文绝不会接触磁盘;上传缓冲区会被清除。

{ "ingested": true, "bytes_added": 87500, "pool_bytes_remaining": 786500 }

触发:require_admin → pool.ingest_bits_bytes(→ parse_bits_bytes → encrypt_chunk → db.insert_pool_chunk)→ pool.burn。错误:401、413 file_too_large、422(非 .txt 或 内容包含非 0/1 字符)。

POST /admin/purge — 管理员令牌

用途:操作人员清空熵池,以便轮换、响应安全事件或重置测试——此操作不可逆。 删除所有存储的池块。不可逆——之后必须重新为池补充数据。

{ "purged": true, "chunks_removed": 42, "pool_bytes_remaining": 0 }

触发:require_admin → db.purge_pool()。

POST /admin/keys — 管理员令牌

用途:操作人员为开发者或客户签发全新的 API 密钥;密钥只会在生成时显示一次。 生成 API 密钥(逻辑与 scripts/mint_key.py 相同)。明文密钥仅返回一次。 请求:{ "owner": str, "tier"?: "default", "daily_quota_bytes"?: int|null }。

{ "api_key": "<plaintext — shown once>", "owner": "devtest",
  "tier": "default", "daily_quota_bytes": null }

触发:require_admin → secrets.token_urlsafe(32) → auth.hash_api_key → db.insert_api_key。

POST /admin/keys/revoke — 管理员令牌

用途:供运营人员立即停用已泄露或已退役的密钥,并从下一次请求起生效。 即时撤销。请求:{ "key_hash": str }。

{ "key_hash": "…", "revoked": true }

触发:require_admin → db.revoke_api_key。哈希未知 → 404 not_found。


10. 本地开发

cd api
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env         # fill DATABASE_URL, REDIS_URL, MASTER_KEY, ADMIN_TOKEN

每个路由都会访问 Postgres,大多数路由还会访问 Redis——.env 值为空时,每个请求都会返回 500。 要启动一次性本地后端(Docker Postgres + Redis,并自动应用所有 SQL 迁移):

eval "$(./scripts/dev_db_up.sh --print-env)"    # starts qeaas-pg + qeaas-redis, exports env
uvicorn main:app --reload --port 8000 --env-file .env

填充数据池(任何 0/1 文本都可在本地走通流水线——实际部署会采集真实 QRNG 输出):

python3 -c "import random; random.seed(1); open('/tmp/bits.txt','w').write(''.join(random.choice('01') for _ in range(700000)))"
python scripts/ingest_bits.py /tmp/bits.txt seed
python -m scripts.mint_key --owner devtest --tier default    # prints the plaintext key once
uvicorn main:app --port 8000

冒烟测试:

curl -s localhost:8000/health
curl -s "localhost:8000/random?bytes=32"
curl -s -X POST localhost:8000/dice -H 'content-type: application/json' -d '{"sides":6,"count":2}'
curl -s -H "X-API-Key: <key>" "localhost:8000/v1/random/bytes?size=64&format=hex"
open localhost:8000/docs     # interactive Swagger UI, every route typed

拆除:pkill -f "uvicorn main:app" && ./scripts/dev_db_down.sh。

环境变量
键用途
DATABASE_URLNeon 池化 Postgres 连接字符串
REDIS_URLUpstash rediss://(TLS)连接字符串
MASTER_KEY256 位十六进制值(secrets.token_hex(32))——子密钥层级的根密钥(§5)
ADMIN_TOKEN/admin/* 的 Bearer 令牌(secrets.token_urlsafe(32))
WEB_ORIGIN以逗号分隔的 CORS 允许来源(默认 http://localhost:3000)

速率限制、配额、层级和重新播种时间均为模块常量(ratelimit.py、keyed_drbg.py),而非环境变量。

运维脚本(api/scripts/)
脚本功能
ingest_bits.py解析、加密并将 0/1 .txt 文件存入数据池
mint_key.py / revoke_key.pyCLI 密钥生命周期管理(与管理员路由对应)
kem_roundtrip.py / kem_handshake.py验证对实时 API 执行 keygen → encaps → decaps 后能还原相同的共享密钥
scan_persistence.py只读不变量扫描:未持久化明文敏感列或值
dev_db_up.sh / dev_db_down.sh用于本地开发的一次性 Docker Postgres + Redis

11. 部署(摘要)

生产环境使用两个独立的 Vercel 项目(qeaas-api → qrng-eaas/api、qeaas-web → qrng-eaas/web),而非一个——GET /dice(网页)和 POST /dice(API)在同一域名下会发生冲突,基于路径的重写无法根据 HTTP 方法进行路由。qrng-eaas/api/vercel.json 固定使用 Python 3.13 运行时,并将所有路径重写到 main.py。配置 Neon(按顺序运行 sql/001…005)、Upstash(区域性部署,rediss:// TCP URL),然后设置各项目的环境变量(§10)。完整操作手册、故障排查,以及 EPIC 7–11 的说明文档(种子质量报告、网络演示、来源追溯、安全存储销毁生命周期、主题设置)位于 claude/plans/ 和 shared/docs/。


12. Agent 优先集成(EPIC 13)

AI Agent 可以发现此服务,并且传统爬虫和大模型爬虫都能正确索引此服务。 规范域名:Web:https://qeaas.eu,API:https://api.qeaas.eu。

发现文档(API):

URL内容
/.well-known/agent.json机器可读的 Agent 清单:定位、身份验证、功能、交叉链接
/.well-known/ai-plugin.json精简的 ChatGPT 插件风格清单 → /openapi.json
/.well-known/mcp.jsonMCP 端点、传输方式、协议版本
/v1/agent/tools工具描述符——每个可调用端点一个,包含 JSON Schema(来自 qeaas/schemas.py)
/v1/agent/manifest完整的入门文档;使用 ?profile=<http|openai-tools|anthropic-tools|mcp> 获取适配相应框架的快速入门
/openapi.json + /docs增强版 OpenAPI(标签、服务器、ApiKeyAuth 请求头方案)
POST /mcp完整的 MCP 服务(Streamable-HTTP JSON-RPC 2.0):tools、resources、prompts、握手

Web 地图:/llms.txt、/llms-full.txt、/agents 页面、sitemap.xml、robots.txt (完整的 AI 爬虫允许列表)、manifest.webmanifest,以及全站 JSON-LD。

**获取密钥:**公共端点(health、random、dice、verify、pubkey)无需密钥。 开发者/KEM 端点需要请求头 X-API-Key(由管理员签发、可撤销、按配额计量)。

一个目录,确保一致:qeaas/agent.py 中包含唯一的 ENDPOINTS 目录;agent.json、 工具描述符、清单和 MCP 工具列表均由此生成,架构则来自 model_json_schema()。

**从环境变量获取基础 URL:**API 读取 PUBLIC_API_URL / PUBLIC_WEB_URL(localhost 默认值, qeaas/urls.py);Web 读取 NEXT_PUBLIC_API_URL / NEXT_PUBLIC_WEB_URL(lib/urls.ts)。 WEB_ORIGIN(CORS)必须包含 https://qeaas.eu。

示例:

# 1. an agent finds the manifest
curl -s https://api.qeaas.eu/.well-known/agent.json | jq

# 2. follows to its framework-shaped quickstart
curl -s "https://api.qeaas.eu/v1/agent/manifest?profile=openai-tools" | jq

# 3. calls a public endpoint, or (with a key) a developer one
curl -s "https://api.qeaas.eu/random?bytes=32"
curl -s -H "X-API-Key: $QEAAS_API_KEY" "https://api.qeaas.eu/v1/random/bytes?size=64&format=hex"

# or connect an MCP client to POST https://api.qeaas.eu/mcp
curl -s -X POST https://api.qeaas.eu/mcp -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。