Skip to main content
Glama

JevLens

Jev 在你 Agent 运行的每一步上判了什么,全都看得见。

中文 · English · 日本語

JevLens 是一个本地 MCP 服务器,外加一个查看 TypeSafe Jev 决策的网页面板。它不做决策,不做工具路由,也不碰你 Agent 的上下文。它包住每一次 systemOne 调用,把完整的 state、问题、答案、概率分布、置信度与延迟写入一个只追加的 JSONL 文件,并呈现为一条时间线,让你能分辨某个古怪的 Agent 行为究竟出自 Jev 的判断,还是出自 LLM 的生成。

面向单人、副业项目、没有运维预算的开发者:

  • 无外部服务。 没有数据库、没有云端、没有 Docker。每天一个 JSONL 文件,用 grep 和 jq 就能查。

  • 无前端构建。 面板就是一个 HTML 文件;图表库来自 CDN。

  • 无鉴权。 面板绑定 127.0.0.1,其他 Host 头一律拒绝。它是开发者工具,不是 SaaS。

  • 无 harness 锁定。 标准 MCP over stdio,因此 Claude Code、Codex、Cursor、OpenCode 以及任何其它 MCP 客户端都能用。

  • 无额外模型开销。 JevLens 只转发你本来就要发出的调用,从不自行调用 LLM。

  • 按 fail-open 设计。 若 Jev API 不可达,jev_ask 返回 undecided 结果,你的 Agent 继续运行。

state + questions ──▶ [jev_ask] ──▶ TypeSafe Jev API ──▶ answers + probabilities + confidence
                          │
                          ├──▶ .jevlens/trace-YYYY-MM-DD.jsonl   (append-only)
                          │
                    [jevlens ui] ──▶ http://127.0.0.1:8787       (3s polling, same file)

MCP 服务器与面板是两个独立进程,除 JSONL 文件外不共享任何东西。Agent 干活时开着服务器;只在调试时才启动面板。


快速开始(约 5 分钟)

# 1. Register it with your coding agent (Claude Code shown; see "Wiring" below for others)
claude mcp add jevlens --env TYPESAFE_API_KEY=$TYPESAFE_API_KEY -- npx -y jevlens mcp

# 2. Ask your agent to call the tool, e.g.
#    "Use the jevlens jev_ask tool to classify this support ticket: I was charged twice, fix it today."

# 3. Look at what Jev actually returned
npx -y jevlens ui          # then open http://127.0.0.1:8787

还没有 API key?整套流程照样能对着一个确定性的离线 provider 端到端跑通,所以你可以先试面板和工具的调用形态:

npx -y jevlens ui --mock --port 8787

此时面板会在每条记录上显示 mock provider 徽标(mock),你绝不会把演示数据误当成真实决策。


Related MCP server: Jev MCP

接入

JevLens 是一个普通的 stdio MCP 服务器。唯一的密钥 TYPESAFE_API_KEY 只从环境变量读取,绝不写入配置文件、trace 或导出文件。

claude mcp add jevlens --env TYPESAFE_API_KEY="$TYPESAFE_API_KEY" -- npx -y jevlens mcp

或写进项目根目录的 .mcp.json:

{
  "mcpServers": {
    "jevlens": {
      "command": "npx",
      "args": ["-y", "jevlens", "mcp"],
      "env": { "TYPESAFE_API_KEY": "${TYPESAFE_API_KEY}" }
    }
  }
}

写在 ~/.codex/config.toml 里:

[mcp_servers.jevlens]
command = "npx"
args = ["-y", "jevlens", "mcp"]
env = { TYPESAFE_API_KEY = "tsk_live_..." }

写在 .cursor/mcp.json 里:

{
  "mcpServers": {
    "jevlens": {
      "command": "npx",
      "args": ["-y", "jevlens", "mcp"],
      "env": { "TYPESAFE_API_KEY": "tsk_live_..." }
    }
  }
}

写在 opencode.json 里:

{
  "mcp": {
    "jevlens": {
      "type": "local",
      "command": ["npx", "-y", "jevlens", "mcp"],
      "environment": { "TYPESAFE_API_KEY": "tsk_live_..." },
      "enabled": true
    }
  }
}

命令:npx -y jevlens mcp(全局安装后也可以是 jevlens mcp),传输方式:stdio,并在子进程环境里给出 TYPESAFE_API_KEY。


工具

jev_ask — 向 Jev 提问,并记录一切

{
  "label": "support-triage",
  "state": { "subject": "I was charged twice, please fix this today", "channel": "email" },
  "questions": {
    "category": {
      "type": "choice",
      "instructions": "What is this ticket about?",
      "criteria": { "billing": "money charged wrongly", "technical": "a feature does not work", "other": null }
    },
    "urgency": {
      "type": "score",
      "instructions": "How urgent is it?",
      "criteria": ["routine", "within a day", "right now"]
    }
  }
}

type 取 choice、score 或 noul 之一。noul 问题没有选项集,只是一次「这话有多真」的判断 — { "type": "noul", "instructions": "Does this diff look risky to merge?" },可选地再带一个 criteria: { true, false } 给两端命名。它的回答是 { "type": "noul", "noul": 0.87 },其置信度不由接口返回而是推导得出:|noul − 0.5| × 2,因此 0.5 读作最大模糊,0 和 1 读作确定;该值同其它问题一样进入 confidence.min 与 belowThreshold。当 provider 返回 legend 时,score 的回答里也会带上把档位下标映射到档位文本的 legend。

返回的只有结构化 JSON — 不给模型留下任何可能误读的散文:

{
  "id": "0f4d5c6e-…",
  "label": "support-triage",
  "status": "answered",
  "provider": "live",
  "model": "system-one-2025-09",
  "latency_ms": 812,
  "confidence": { "min": 0.78, "mean": 0.845, "perQuestion": { "category": 0.91, "urgency": 0.78 }, "belowThreshold": [] },
  "answers": {
    "category": { "type": "choice", "choice": "billing", "confidence": 0.91, "probabilities": { "billing": 0.91, "technical": 0.07, "other": 0.02 } },
    "urgency": { "type": "score", "score": 2, "confidence": 0.78, "probabilities": { "0": 0.05, "1": 0.17, "2": 0.78 } }
  },
  "hints": [],
  "error": null,
  "trace": "trace-2026-09-21.jsonl"
}

status 为 "answered" 或 "undecided"。undecided 结果依然为每个问题给出答案(均匀概率,置信度 0),并附上记录下来的 error,所以 Jev 停服只会让判断质量降级,而不是打断这次运行。

可选字段:model(单次调用覆盖模型)与 threshold(单次调用告警阈值)。

jev_trace — 回读最近的决策

{ "limit": 20, "label": "support-triage", "below_threshold": 0.7, "include_payload": false }

最新的在前,直接读自 JSONL 文件。设置 include_payload: false 可以去掉 state 正文,让 Agent 的上下文保持紧凑。

jev_export — 写出报告

{ "format": "markdown", "label": "support-triage", "path": "reports/triage.md" }

把 Markdown 或 CSV 写入 .jevlens/exports/(或你指定的 path),并返回 { format, path, records, bytes }。Markdown 是一份可直接粘贴的缺陷报告:state、问题定义、答案表、概率分布、置信度标记、hints 与 error。CSV 则每个问题一行、重复记录级元数据,方便表格软件做透视。


面板

jevlens ui --port 8787
  • 每条决策的时间线,最新的在前,含 label、model、延迟与最低置信度。

  • 每个问题的概率条;被返回的那个答案是高亮条。

  • 置信度告警:低于阈值的记录用红框描出,并计入概览卡片。阈值可在页头直接修改,并持久化到 .jevlens/config.json。

  • 每 3 秒自动刷新(轮询,无 WebSocket),可暂停,标签页隐藏时保持空闲。

  • 展开某行可看到原始 state、问题定义、hints、错误文本与完整记录。

  • label 过滤、"flagged only" 开关、条数选择器,以及作用于整条记录的文本过滤。

  • 每条决策的置信度图(Chart.js 取自固定版本、带 SRI 哈希的 CDN URL;CDN 不可达时退化为文本展示)。

  • 一键导出 .md / .csv。

  • 用于分享视图的深链:/?label=support&threshold=0.8&flagged=1&expand=1&q=billing,另有 limit=200 与 open=<id,id> 按 trace id 展开指定记录。

面板读的就是服务器写的那个文件;不上传任何内容,除你选定的端口外也不开放其它端口。


问题质量提示

每次调用前,JevLens 会对你的问题做一轮低成本的静态检查,并把结果作为参考性提示附上(工具响应里的 hints,面板里的一个琥珀色标签)。提示从不阻断调用。

代码

含义

choice.overlap

两个选项的意思几乎相同,于是二者之间的概率分配无从解读。比较 label 文本与 label+描述文本,用词重叠加字符二元组 Dice 系数,英文与 CJK 措辞都适用。

choice.too_few_options

选项少于两个:没有可区分的东西。

choice.too_many_options

选项多到概率质量开始变噪。

score.range_narrow

档位少于三个:这么短的量尺除布尔值之外表达不了什么。

score.range_wide

档位多于八个:相邻位置再也分辨不开。

score.duplicate_bucket / score.endpoints_identical

同一段文本被用在量尺的不同位置上。

question.missing_instructions

问题没有指令文本;Jev 只能凭选项措辞作答。

question.too_many

单次调用里超过十二个问题。

noul 问题只做 question.* 那两项检查:没有选项集,也就无从比较重叠或档位数量。

重叠判定的灵敏度通过 .jevlens/config.json 里的 overlapThreshold 调整。


存储

.jevlens/
├── config.json                 # optional: threshold, port, rotation, model
├── trace-2026-09-21.jsonl      # one decision per line
├── trace-2026-09-21-2.jsonl    # rotation part 2 once maxRecordsPerFile is hit
└── exports/                    # jevlens-<timestamp>.md | .csv

只追加,每行一个 JSON 对象,按天分文件,并对单文件记录数设上限。进程被杀留下的半行在读取时会被跳过,而不是把面板弄坏。每行还带有 agent(已连接 MCP 客户端上报的 name@version,如果它报了)与 response.usage 的 token 计数;面板展开原始记录时两者都能看到。

jq -r '[.ts, .label, .status, .confidence.min] | @tsv' .jevlens/trace-*.jsonl
grep -c '"status":"undecided"' .jevlens/trace-2026-09-21.jsonl

凭据清洗是在写入时强制执行的,而非仅靠约定,由三条彼此独立的规则构成。存在某个看起来像凭据的键(api_key、apikey、access_token、auth_token、bearer、token、secret、password、passwd、credential、authorization、cookie)下的值会变成 [redacted]。任何与某个环境变量值相等的字符串,只要该变量的名字匹配上面同样这些模式且长度至少 12 个字符,就会被遮蔽。任意字符串内部的凭据形状 token — sk…、pk…、pat…、ghp…、xoxb… 或 ai… 后接 12 个及以上单词字符 — 会被替换。超过 20 000 字符的字符串会被截断,嵌套深过 12 层会被裁掉。

这些只是形状匹配,不是通用的密钥检测器:自由文本 state 里一个不透明的 Bearer dXkR9f… 会躲过清洗,除非它所在的键就是 bearer/authorization,或者这个值恰好也在你的环境变量里。请把 trace 文件当作敏感内容对待,别让它进版本库 — .jevlens/ 正因如此已被 gitignore。有一个测试会把一把假 key 塞进 state,并断言它永远到不了磁盘。


配置

环境变量

用途

默认值

TYPESAFE_API_KEY

Jev API key(仅环境变量;从不持久化)

—

TYPESAFE_BASE_URL

覆盖 Jev 端点

SDK 默认

TYPESAFE_DEFAULT_MODEL

每次调用请求的模型

provider 默认

JEVLENS_DIR

trace 目录

./.jevlens

JEVLENS_PORT / JEVLENS_HOST

面板绑定

8787 / 127.0.0.1

JEVLENS_CONFIDENCE_THRESHOLD

告警阈值

0.7

JEVLENS_MAX_RECORDS

单个文件轮转前的记录数

5000

JEVLENS_TIMEOUT_MS

Jev 请求超时

20000

JEVLENS_MOCK

强制使用离线 provider

关闭

JEVLENS_RUN_ID

给本进程记录的每条决策打上一个 run id

—

JEVLENS_INSPECTOR_PORT

jevlens inspector 的端口

6274

JEVLENS_UI_HTML

面板 HTML 路径(开发/测试钩子)

<package>/ui/index.html

.jevlens/config.json 放的是同一批开关(confidenceThreshold、storageDir、host、port、maxRecordsPerFile、model、mock、overlapThreshold)。优先级:内置默认值 < 配置文件 < 环境变量 < CLI 参数。

{ "confidenceThreshold": 0.8, "maxRecordsPerFile": 2000, "overlapThreshold": 0.55 }

命令行

jevlens mcp         start the MCP server on stdio (what your agent launches)
jevlens ui          start the local decision timeline
jevlens stats       aggregate the trace on disk: tokens, latency, undecided rate, per label
jevlens doctor      check the install: Node, API key, trace dir, provider, one live Jev call
jevlens inspector   launch the official MCP Inspector against this server
jevlens help        usage;  -v / --version prints the version

公共参数:--port <n>、--host <addr>、--dir <path>、--threshold <0..1>、--mock;jevlens inspector 另外接受 --inspector-port <n>。它们位于优先级链的最上层,因此命令行参数总是压过配置文件与环境变量。

jevlens stats 只读取磁盘上已有的东西,不往里面添加任何内容。--label <name> 把分标签表格收窄到一个 标签,--json 则把整份聚合结果输出为机器可读的 JSON。两者同样接受 --dir 与 --threshold。

jevlens doctor 不用读源码就能回答“为什么所有结果都是 mock?”:它对 Node、版本、trace 目录、 TYPESAFE_API_KEY、当前 provider 以及一次真实的 Jev 往返各打印一行。只有在确实打算发起真实调用时,缺失的 key 才会算作 FAIL——带 --mock 时它是预期内的。标为 warn 的行在全新安装上属正常现象;jevlens doctor 只在出现 FAIL 时以非零退出,而它的探测调用永远不会写入 trace。

jevlens inspector 通过 npx 针对 jevlens mcp 启动官方 MCP Inspector,并打印出 http://127.0.0.1:6274/… 地址(较新的 Inspector 版本会在其中附加一个 auth token)。在那里你可以 手工调用 jev_ask,同时看着 JSONL 文件不断变长。


开发

npm install
npm run typecheck     # tsc -p tsconfig.dev.json (src + tests + examples)
npm run build         # tsc → dist/
npm test              # node --test on TypeScript sources, no build step needed
npm run check         # all three
node examples/seed-trace.ts   # write a few demo decisions with the offline provider

TypeScript、Node 22.18+(engines 为 >=22.18.0;npm test 通过 Node 的类型擦除直接运行 TypeScript 源码,而该能力从 22.18 起才无需 flag)、ESM,运行时依赖恰好三个:@modelcontextprotocol/sdk、@typesafe-ai/sdk 与 zod v4。测试使用 Node 内置 runner,覆盖存储轮转与半行、配置优先级、凭据清洗、问题质量启发式、fail-open 路径(API 不可达、答案缺失、存储不可写)、mock provider 的概率不变量、Markdown/CSV 正确性、面板的 HTTP API,以及一个真实 MCP 客户端经 stdio 与构建好的服务器对话。

发布:

npm publish --access public   # prepublishOnly runs a clean build, the type check and the test suite

JevLens 刻意不做的事

常见的 Jev harness 方向

JevLens

用 Jev 做工具选择或风险闸门

只记录并展示决策,不做任何决策

过滤工具输出或压缩上下文

从不碰 Agent 的上下文

拿 Jev 与其它模型对比

一次只追踪一个 Agent 运行

提供预设问题库或 linter

只展示你的问题实际返回了什么

企业级审计与合规

本地文件,无账号,无配额

v0.1 同样不在范围内:数据库、索引、查询语言、鉴权、多租户、WebSocket 推送、自动改代码、决策链编排。

与同一定位相符的后续方向:决策链可视化(把相关的调用串成一棵树)、写入前的本地 PII 掩码、导出运行的只读分享,以及与 Jev 问题质量 linter 更紧密的联动。

许可证

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Provides coding agents and CI with a typed decision layer that sends bounded state and questions to Jev, then returns deterministic actions for review, risk assessment, requirement checks, and verification.
    9
    1,141 npm
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables frontier coding agents to delegate routine probabilistic judgments to TypeSafe Jev, providing calibrated triage signals for failures, attempts, completion, context ranking, findings, risk, and generic evidence-grounded questions.
    7
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables coding agents to query a Jev model for next-tool recommendations, exposing tools to check status and request tool-choice predictions, while logging all decisions for review.
    526 npm
    4
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables coding or reasoning agents to request structured judgments from TypeSafe's Jev model at decision points, including choices, scores, claim verification, and code reviews, with probabilities and confidence returned as data.
    5
    173 npm
    MIT