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

dsh-mcp-auth

v0.2.1

Published

Persistent MCP login state for DeepSeek Harness: OAuth 2.1 / manual header credentials per MCP server, injected into mcp-client rows via !!js. Settings UI talks to the host over Typert Remote.

Readme

dsh-mcp-auth

Requires: dsh ≥ v0.1.7-rc.2(兼容 0.1.7 / 0.2.x,peer 区间 >=0.1.7-rc.2 <0.3.0;dsh 0.2.1 起有插件版本门禁,需本包 2026-10-20 后版本)。 本包是 dsh 插件,须装进 dsh profile 由 dsh 宿主加载使用,不是独立 npm 库。 桌面端(DeepSeek Harness.app)已支持:设置页「MCP 登录」已改版(卡片/横幅/ 状态圆点,随宿主明暗主题),OAuth 全链路已在桌面 app 0.2.1-rc.2 验证。

为 DeepSeek Harness 提供 MCP 登录态持久化:按服务器保存凭据(OAuth 2.1 令牌 或手工请求头),存放在 dsh home 下,并通过 !!js 配置表达式注入官方 mcp-client 行。不修改任何官方包。

工作原理

  1. 本 bundle 提供 mcpAuth 服务。headers(serverName) 同步读取持久化的 登录态(loader 在引导时求值一次)。
  2. mcp-client 行等待该服务并注入请求头:
- id: my-server
  name: '@deepseek-ai/dsh-mcp-client'
  inject: [mcpAuth]
  config:
    transport: streamable-http
    serverName: nocodb
    url: https://mcp.example.com/mcp
    headers: !!js ctx.mcpAuth.headers('nocodb')
  1. 登录态存于 ~/.dsh/mcp-auth/tokens.json(文件 0600,目录 0700)。

登录方式(设置里的「MCP 登录」分区)

  • 手工凭据 —— 粘贴一个请求头(如 Authorization: Bearer … 或 API Token 头),原样保存、原样注入。
  • OAuth 2.1 —— 基于 MCP SDK 的 auth() 状态机:RFC 9728 受保护资源发现、 客户端注册(见下「客户端身份」)、PKCE(S256)、一次性回环重定向监听器、 系统浏览器完成授权。令牌(含 refresh_token 与绝对 expires_at)跨重启持久。

按需登录(懒认证)

长连的 MCP 连接(例如 dsh-mcp-apps 为每个服务器自开的那条)拿到 401 时,SDK 的 streamable-HTTP transport 会自己重跑 auth():不需要人工参与时它直接重试;需要 用户点同意时它抛 UnauthorizedError 交给调用方 —— SDK 自己没法等人。 mcpAuth 因此额外提供:

lazyAuth(serverName, serverUrl, scope?): Promise<LazyAuthHandle>

句柄含 provider(交给 transport 的 authProvider)、authorize()(等人批准后 换码并落盘)、authorizationUrl()、lastError()、dispose()。授权 URL 会写进 list 投影(设置页 "MCP 登录" 分区可见)并打印到 stdout —— 无头环境 (DSH_MCP_AUTH_NO_BROWSER=1)靠它手工打开。

参考实现见 dsh-mcp-apps:把 provider 装到自己的连接上,捕获 UnauthorizedError 后调 authorize(),然后重试那一次调用。

⚠️ 装了 authProvider 就必须把静态 Authorization 从 requestInit.headers 里 去掉。 SDK 的 _commonHeaders() 把 requestInit.headers 展开在 provider 的 bearer 之后,留下的静态头会覆盖刚拿到的令牌,让整条流程静默失效。

死凭据自愈

服务器吊销了会话(或"授权即自杀"场景:受保护的 revoke 工具在登出状态被调用,触发 的新授权又被这次 revoke 本身吊销)后,SDK 的 refresh 路径会抛普通 Error(不是 UnauthorizedError)——不处理的话同一失败会永远重复。authorize() 检测错误消息含 refresh / revoked / invalid_grant 时会自动清掉死凭据并在同一轮内重跑交互式 授权,用户只需再点一次同意。lastError() 始终可查失败原因(不静默)。

另有 reset():只清 OAuth 态、保留手工 header 凭据。

客户端身份(三条路线)

| 路线 | 配置 | 适用对象 | |---|---|---| | A · CIMD(SEP-991,URL 型 client id) | clientMetadataUrl:https 且路径非根 | 声明 client_id_metadata_document_supported 的授权服务器 | | B · 断言式 client id | staticClientId | 既不支持 CIMD 也不支持动态注册的服务器 | | C · 动态客户端注册 | 两者都不配(默认) | 提供 registration_endpoint 的服务器 |

  • 两者都配时 A 优先:可移植的路线不该被遗留的 B 拉回去。
  • B 是捷径,不是通用解:它只在对方接受所断言的 id 时可行(例如 lazy-auth-server-demo 压根不校验 client_id)。换一个真实授权服务器可能被拒。
  • clientMetadataUrl 不合法会让插件启动即报错并带出具体取值。MCP SDK 只接受 https 且路径非根的 URL(isHttpsUrl),没有 localhost 例外,所以回环 http 的元数据文档用不了 —— 本地调试请用 B,或把文档托管到真 HTTPS 上。
  • 已注册/已发放的 clientInformation 优先于配置:刷新时必须沿用当初发放授权 所用的同一个 client id。

配置

bundle 行无必填配置。可选:

| 键 | 默认 | 说明 | |---|---|---| | tokenFile | 空 | 覆盖存储路径(仅供测试)。 | | clientMetadataUrl | 空 | 路线 A:https 且路径非根的客户端元数据文档 URL。 | | staticClientId | 空 | 路线 B:断言式 client_id。 |

安装

在 profile(~/.dsh/profiles/web/package.json)的 dependencies 中添加:

"dsh-mcp-auth": "^0.2.0"

并把 "dsh-mcp-auth" 列入 dsh.profile.bundles,然后在 profile 目录执行 pnpm install。peer 依赖(@deepseek-ai/cordis、dsh-typert-protocol)无需 手动安装——dsh 宿主自带,Node 会从你的 dsh 安装中解析。

从 0.1.x 的 link: 本地安装升级:把依赖项改成上面的版本号写法,删除 node_modules/ 里的旧软链(如有),重新 pnpm install 即可。

安全

  • 令牌文件以仅属主权限(0600)创建。
  • 设置界面经 dsh Typert Gateway(/api 通道)调用本插件的 Remote 方法 (mcp-auth 命名空间:list / save-headers / forget / oauth-start),受与 /api 相同的浏览器信任栅栏保护(错误 Origin → 403)。0.2.0 起不再有独立 的 loopback RPC 监听器与 per-boot token。
  • OAuth 重定向监听器仅绑定 127.0.0.1,只接受经 state 校验的回调;懒认证的 监听器在句柄生命周期内常驻(授权请求与令牌交换必须是同一个 redirect_uri), 随插件卸载关闭。
  • 回调只接受与当前这次授权尝试匹配的 state;不匹配直接 400,不放行。
  • 等待用户批准有上限(默认 5 分钟),避免关掉标签页后把调用方永久挂住。

已知限制

  • headers() 在引导时取快照:引导完成后新完成的登录在下次重启(或该行自身 重连)时生效。懒认证不受此限 —— 它的 transport 每次请求都向 provider 取 令牌,授权完成后重试即刻生效。
  • 读取到已过期且带 refresh_token 的令牌时会尽力刷新;刷新结果下次启动生效。
  • 暂无交互式刷新界面。
  • 走静态头的官方 @deepseek-ai/dsh-mcp-client 行不做 401 挑战处理(其产物里 401|WWW-Authenticate|oauth|authorize 零命中),且不得修改官方包。 解决方式:让官方行 disabled: true,由 dsh-mcp-apps 的工具桥 (registerTools: true)接管工具注册——模型侧调用从此走活凭据连接,免重启。 详见 dsh-mcp-apps/README.zh.md 的「活凭据工具桥」。

模型体验

不改变任何模型可见面:无新增工具、提示词段落或会话事件;请求与 KV 缓存行为 不变。

开发

pnpm install --ignore-workspace
pnpm run build   # tsdown 两遍:node 半边(含 @Remote 装饰器降级)+ client 半边
                 # 并把手写 Typert 工件(typert.host / typert.remote-client)拷入 lib/
pnpm test

Typert 工件为手写维护(src/typert.host.manual.js / typert.remote-client.manual.js): 官方 generator 的 package 模式只认 workspace 内的包,不识别从 npm 安装的 protocol。新增/修改 @Remote 方法时需同步改这两个文件(wire 名 ≠ JS 方法名时 必须写 implementation 字段)。0.1.x 的 rpc-server / settings.register 路线 已退役(_attic-0.1.x/)。