npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

linker-report-write-mcp

v0.1.0

Published

MCP server for Linker report AI filling - page skeleton lookup and per-page content writing (weekly / daily reports). Write-only by design; queries live in the read-only MCP servers.

Readme

linker-report-write-mcp

Linker 报告(周报 / 日报)写入型 MCP Server。

面向 AI Agent,提供「读页面骨架 → 逐页填写」两个工具,供 Hermes agent 在报告编辑页按页填充内容。每填完一页即推进完成度,前端据此实时更新进度与占位动画。

读写分离:本 MCP 只写,不含任何行情/持仓/研报查询。查询请用只读 MCP(linker-position-mcplinker-trading-data-mcplinker-report-mcp)。原因见下方「安全模型」——写通道与超管 Key 不能共处一个进程。

快速开始

环境变量

TRADING_API_BASE=http://hub.linker.net/trading-api
REPORT_WRITE_CALLBACK_SECRET=<运维下发,勿复用只读的 TRADING_API_KEY>

两者缺一进程直接退出。REPORT_WRITE_CALLBACK_SECRET专用回调密钥,不要填只读 MCP 用的 TRADING_API_KEY——后者在后端会命中超管上下文(见「安全模型」)。

配置方式

Hermes(~/.hermes/config.yaml,运维执行):

mcp_servers:
  linker-report-write:
    command: npx
    args: ["-y", "linker-report-write-mcp@latest"]
    env:
      TRADING_API_BASE: "http://hub.linker.net/trading-api"
      REPORT_WRITE_CALLBACK_SECRET: "<secret>"

改完需 /reload-mcp 或重启 Hermes——MCP 是启动时全局注册的,无法按请求注入。

本地开发(直接用编译产物):

{
  "mcpServers": {
    "linker-report-write": {
      "command": "node",
      "args": ["C:/Users/94503/Documents/GitHub/linker_mcp/packages/linker-report-write-mcp/dist/index.js"],
      "env": {
        "TRADING_API_BASE": "http://hub.linker.net/trading-api",
        "REPORT_WRITE_CALLBACK_SECRET": "<secret>"
      }
    }
  }
}

工具列表

| Tool | 说明 | 参数 | 只读 | |------|------|------|------| | get_skeleton | 读某份报告实例的页面骨架(每页可填字段 key/标签/是否已填 + 完成度) | report_type, instance_id, job_token | ✅ | | fill_page | 写入某一页内容,推进完成度 | report_type, instance_id, page_id, fields, job_token, note? | ❌ |

report_typeweekly(周报)/ daily(日报)。日报分支待后端落地后启用,MCP 侧已就绪。

本 MCP 刻意不提供删除、不提供配置修改类工具。 能力面最小化是四道锁之一。

典型调用序列

1. get_skeleton(weekly, 123, token)      → 拿到 P1..P16 各页字段 key 与完成度
2. fill_page(weekly, 123, "P4", {...})   → 完成度 1/16,前端进度条动
3. fill_page(weekly, 123, "P5", {...})   → 2/16
   ...逐页推进

agent 必须先 get_skeletonfill_page:字段 key 由骨架决定,凭记忆猜会被后端白名单拒绝。

安全模型

详见 docs/weekly-report-feature.md §14.6。四道锁:

  1. job_token 绑定:每次 AI 任务由系统签发 token,服务端 Redis 中绑定 (user_id, instance_id),30 分钟 TTL。token 是真正的身份凭证。
  2. 非超管上下文重建:后端从 token 重建非超管上下文再跑归属校验,所以 A 的 token 打不到 B 的报告。
  3. 最小能力面:只有 fill_page + get_skeleton,无删除、无配置改动。
  4. 一次性 + 限流:token 用后即焚并限速。

⚠️ 为什么不能复用 TRADING_API_KEY

后端 X-API-Key 会命中 _api_key_superuser_context()auth.py:27),产出 is_superuser=True, monitor_scope="all";而 check_resource_accessauth.py:509)首行就是

if is_superuser or monitor_scope == "all": return

——归属校验被整体跳过。所以本 MCP 里 X-API-Key 只用于打通通道,不授予任何写权限;授权完全靠 job_token。这也是查询 MCP 必须与写 MCP 分进程的原因:超管 Key 不能和写操作共处一个信任边界。

横向提示:该 bypass 对所有复用此 Key 的写接口成立,不止报告模块,值得单独排查。

富文本

fields 的值支持有限富文本(b/i/u/s/code/span[style=color]ul/ol/li/pbr),服务端按白名单清洗。script/style/onclick 等一律剥离。

错误语义

后端的 message原样带回给 agent,便于它据错自我修正:

| 状态 | 含义 | agent 应做的 | |------|------|-------------| | 403 | job_token 无效/过期/越权 | 停止,向用户报告需重新发起任务 | | 422 | 字段 key 不在该页骨架内 | 重新 get_skeleton 校对 key 后重试 | | 404 | 实例或页不存在 | 停止 |

fill_page 对同一页重复调用为覆盖,完成度不重复累加(幂等)。

开发

cd packages/linker-report-write-mcp
npm install
npm run build        # tsc 编译
npm run watch        # 开发热编译
node test_tool.mjs   # 工具测试

测试

写工具需 job_token 且依赖后端 ai-skeleton/ai-fill-page 端点(backend 阶段 6-3),故测试分两档。

离线契约档(默认,内建 mock server,无需后端与真实 token):

node test_tool.mjs

覆盖:越权 token → 403 且 message 透传、骨架正常返回、未知字段 → 422、正常写入推进完成度、重复填同页幂等。

输出:

=== 离线契约档 ===
═══ Test 1: get_skeleton 越权 token 应 403 ═══
✓ 403 且 message 透传: 403 job_token 无效或越权
═══ Test 2: get_skeleton 正常 ═══
✓ 骨架 pages=1, progress=0/1
═══ Test 3: fill_page 未知字段应 422 ═══
✓ 拒绝未知字段: 422 未知字段: nope
═══ Test 4: fill_page 正常写入 ═══
✓ 写入 filled_count=2, progress=1/1
═══ Test 5: fill_page 幂等 ═══
✓ 幂等: progress 仍=1/1

✅ 离线契约档全部通过

联调档(6-3 端点落地后,打真实后端):

LIVE=1 TRADING_API_BASE=http://hub.linker.net/trading-api \
  REPORT_WRITE_CALLBACK_SECRET=<secret> \
  JOB_TOKEN=<token> INSTANCE_ID=123 \
  node test_tool.mjs

联调档目前只自动验 get_skeletonfill_page 会真实改数据,需确认目标实例可写后手动补 POST 用例。

QA 联调还需覆盖(阶段 6-8):A 用户 token 打 B 用户实例应 403、幂等、XSS 用例。

技术细节

  • 传输:stdio(Hermes 以子进程方式拉起)
  • 认证X-API-Key 建立通道 + job_token 授权(后者才是身份)
  • 回调路径weekly/api/v1/weekly-reportsdaily/api/v1/daily-reports
  • 日志:只写 stderr(stdout 归 MCP 协议所有)
  • Node >= 18(用内建 fetch