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

ask-experts-mcp

v0.2.0

Published

MCP server that routes domain-specific questions to expert LLMs (Hunyuan, Qwen, etc.) via OpenAI-compatible APIs

Readme

ask-experts-mcp

让任意支持 MCP 的客户端(Claude Code / Cursor / Cline / Continue / Zed 等)在遇到自己不擅长的领域知识时,主动咨询训练数据更对口的国产专家模型

写微信小程序问 wx.login、写阿里云 OSS 直传、写飞书机器人——这些中文互联网生态特有的领域,海外训练为主的模型(Claude / GPT / Gemini)覆盖比国产模型薄。ask-experts-mcp 给调用方模型暴露一组按"擅长领域"命名的工具(ask_hunyuanask_qwenask_doubao),让它自己读工具描述、自己挑该问谁——不需要切 chat 窗口、复制粘贴。

| 领域 | 谁更熟 | |---|---| | 微信生态(小程序、公众号、企业微信、视频号、QQ、腾讯云) | 混元 | | 阿里云 / 钉钉 / 通义系产品 / 1688 / 淘宝 | Qwen | | 抖音 / 飞书 / 火山引擎 / 字节系开放平台 | 豆包 |

本工具只做两件事:路由(通过工具描述告诉调用方"这种问题该找谁")+ 接入(任意 OpenAI 兼容端点,baseURL + model 配置化)。

不做的事:不做内置 LLM 自动选 expert(那会增加一次模型调用、和调用方判断打架);不做多模型对比 / 投票;不做对话历史(每次 ask_* 单轮无状态);不做流式;不持有用户的 API Key,不做 SaaS 托管。


快速开始

要求 Node.js ≥ 18。

路径 A:零配置(推荐)

只要在 MCP 客户端的 env 里塞 API Key,不需要写任何 JSON 配置文件ask-experts-mcp 会扫描以下环境变量,匹配到哪家就启用哪家(用 preset 默认 model 和领域描述):

| env 变量 | 启用的 expert | 工具名 | |---|---|---| | HUNYUAN_API_KEY | 腾讯混元 | ask_hunyuan | | DASHSCOPE_API_KEY(或 QWEN_API_KEY) | 阿里通义千问 | ask_qwen | | DOUBAO_API_KEY(或 ARK_API_KEY) | 字节豆包 | ask_doubao |

Claude Code 一行命令搞定:

claude mcp add ask-experts \
  -e HUNYUAN_API_KEY=$HUNYUAN_API_KEY \
  -e DASHSCOPE_API_KEY=$DASHSCOPE_API_KEY \
  -e DOUBAO_API_KEY=$DOUBAO_API_KEY \
  -- npx -y ask-experts-mcp

或者写到 mcpServers 配置里(各客户端通用格式):

{
  "mcpServers": {
    "ask-experts": {
      "command": "npx",
      "args": ["-y", "ask-experts-mcp"],
      "env": {
        "HUNYUAN_API_KEY": "sk-xxx",
        "DASHSCOPE_API_KEY": "sk-yyy",
        "DOUBAO_API_KEY": "sk-zzz"
      }
    }
  }
}

| 客户端 | 配置文件位置 | |---|---| | Claude Code | ./.mcp.json(项目级)或 ~/.claude.jsonmcpServers 字段 | | Cursor | ~/.cursor/mcp.json./.cursor/mcp.json(项目级) | | Cline / Continue | 各自插件的 MCP settings 面板,字段一致 | | Zed | ~/.config/zed/settings.jsoncontext_servers 字段 | | Windsurf | ~/.codeium/windsurf/mcp_config.json |

验证:

HUNYUAN_API_KEY=sk-xxx npx -y ask-experts-mcp check    # 给每个 expert 发 ping
HUNYUAN_API_KEY=sk-xxx npx -y ask-experts-mcp list     # 打印实际生效的工具描述

然后在客户端里说:"帮我实现微信小程序登录,要拿到 unionid"——调用方模型会自己挑出 ask_hunyuan 来调用。

调用方模型必须支持 tool use(function calling)。

路径 B:JSON 配置(需要自定义 model / 领域描述 / 自有 endpoint 时)

把下面文件写到 ~/.config/ask-experts/config.json(全局)或项目目录下的 .ask-experts.json(项目级):

{
  "experts": [
    {
      "name": "hunyuan",
      "provider": "hunyuan",
      "apiKey": "${HUNYUAN_API_KEY}",
      "model": "hunyuan-turbos-latest"
    }
  ]
}

零配置和 JSON 配置可以混用——找到任意 JSON 文件后就走 JSON 路径,env-only 仅在两个文件都不存在时兜底。


预设 provider

只内置三家有独立中文互联网生态的 provider,加上一个 custom 兜底:

| provider | baseURL | 推荐 model | 默认领域 | |---|---|---|---| | hunyuan | https://api.hunyuan.cloud.tencent.com/v1 | hunyuan-turbos-latest | 微信生态(小程序、公众号、企业微信、视频号)、腾讯云、QQ | | dashscope | https://dashscope.aliyuncs.com/compatible-mode/v1 | qwen-plus-latest | 阿里云、钉钉、淘宝/天猫/1688 | | doubao | https://ark.cn-beijing.volces.com/api/v3 | doubao-seed-1-6-250615 | 字节系、抖音、飞书、火山引擎 | | custom | (自填) | (自填) | 任意 OpenAI 兼容端点,自填 expertise.override: true 完整定义领域 |

故意不内置 deepseek / zhipu / moonshot / openai——这些是通用模型能力的另一选择而非独立的中文生态,调用方模型本身就够用,走 ask-experts 路由价值有限。需要的话用 custom 自定义即可。

具体 model 名常调整,配置时核实。三家预设的 OpenAI 兼容性踩坑清单见 docs/openai-compat.md(主流程不踩,接 custom 用其他字段时值得先看)。


配置

文件查找与合并

按下面的顺序查找,全部存在时按规则合并:

  1. ~/.config/ask-experts/config.json(全局)
  2. ${PROJECT}/.ask-experts.json(项目级)
  3. --config <path> 启动参数(指定时完全替换前两层,适合 CI / 临时测试)

合并规则:

  • defaults:深合并,项目级字段覆盖全局同名字段
  • experts:按 name list-merge——同名的项目级 expert 字段级覆盖全局,新名字追加;在项目级显式 { "name": "x", "enabled": false } 可屏蔽全局某个 expert

随时用 ask-experts-mcp list 看合并后的最终结果。

完整示例

{
  "experts": [
    {
      "name": "hunyuan",
      "provider": "hunyuan",
      "apiKey": "${HUNYUAN_API_KEY}",
      "model": "hunyuan-turbos-latest"
    },
    {
      "name": "qwen",
      "provider": "dashscope",
      "apiKey": "${DASHSCOPE_API_KEY}",
      "model": "qwen-plus-latest",
      "max_tokens": 4096,
      "expertise": {
        "trigger_keywords_append": ["阿里云函数计算 FC 3.0 触发器配置"]
      }
    },
    {
      "name": "internal",
      "provider": "custom",
      "baseURL": "https://internal-llm.company.com/v1",
      "apiKey": "${INTERNAL_LLM_KEY}",
      "model": "company-rag-v2",
      "expertise": {
        "override": true,
        "summary": "公司内部知识库 RAG,擅长内部业务流程和制度",
        "trigger_keywords": ["内部 SOP", "审批流程", "公司制度"],
        "avoid_keywords": [],
        "system_prompt": "你是公司内部知识专家,严格基于检索到的内部文档回答。"
      }
    }
  ],
  "defaults": {
    "timeout_ms": 60000,
    "max_tokens": 2048,
    "temperature": 0.3,
    "log_level": "info"
  }
}

字段参考

| 字段 | 必填 | 说明 | |---|---|---| | name | ✅ | 工具名后缀,生成的工具是 ask_{name}。要求小写、字母数字下划线;全局唯一 | | provider | ✅ | hunyuan / dashscope / doubao / custom | | apiKey | ✅ | API Key。强烈建议只写 ${ENV_VAR} 占位符 | | model | ✅ | 模型名 | | baseURL | ⚠️ | provider=custom 时必填;预设 provider 自动填充 | | enabled | ❌ | 默认 true;false 可临时禁用 | | expertise | ❌ | 自定义擅长领域元数据;详见 调优工具描述 | | timeout_ms / max_tokens / temperature | ❌ | per-expert 覆盖 defaults 同名字段。reasoning 模型常需更大 max_tokens | | thinking | ❌ | 思考类模型的 reasoning_content 处理:drop(默认)/ prepend(以 <thinking> 块附在前)/ separate |

API Key 安全

  • 只用 ${ENV_VAR} 占位符引用 API Key,不要把明文 Key 写进配置文件——配置文件常被 git 追踪、被备份工具同步,明文 Key 是常见泄露源
  • 启动时对所有明文 Key 字段会打 warning
  • 环境变量未设置时,该 expert 自动 disable + warning(不阻断启动)

调优工具描述

整个产品的成败取决于一件事:调用方模型看到工具描述能不能正确判断该不该调用、该调用哪个

每个 ask_* 工具的 description 由三部分拼成:

  1. WHEN(trigger_keywords)——精确列出领域关键词
  2. WHEN NOT(avoid_keywords)——防止过度调用
  3. HOW——固定的提问技巧提示

expertise 字段级合并语义

expertise 与预设的合并是字段级深合并,不是整体覆盖。这样想加一个关键词不需要把整段预设抄一遍。

| 用户写法 | 效果 | |---|---| | 不写 expertise | 完全使用预设 | | expertise.summary: "..." | summary 替换;其他字段保留预设 | | expertise.summary_append: "..." | summary 是"预设 + 换行 + 用户值" | | expertise.trigger_keywords: [...] | 列表整体替换 | | expertise.trigger_keywords_append: [...] | 追加到预设列表末尾 | | expertise.avoid_keywords / ..._append | 同上 | | expertise.system_prompt: "..." | 完全替换 system prompt(此时 response_language 不再注入) | | expertise.system_prompt_append: "..." | 在默认 system prompt 末尾追加(常用于加业务约束) | | expertise.override: true | 整体替换,未列出字段视为空。custom provider 必须这么写 |

调优反馈循环

  1. ~/.config/ask-experts/config.jsontrigger_keywords
  2. ask-experts-mcp list——立刻看到最终 description
  3. 在 MCP 客户端里测几条该领域的问题,看调用方模型是否触发该 expert
  4. 不触发就加更具体的关键词;过度触发就加 avoid_keywords 或缩小 trigger

长度上限

每个 description 上限 1000 字符(约 250 tokens)。超长时按以下优先级保留 → 截断:

  1. 首行 summary —— 始终保留
  2. ✅ 何时调用 —— 始终保留;实在装不下时按数量截断,末尾补 (...省略 K 条)
  3. ❌ 何时不调用 —— 装不下时整段去掉
  4. 📝 提问技巧 —— 最先去掉

触发截断时 stderr 会打 warning,但不阻断启动。


CLI

ask-experts-mcp                     启动 MCP stdio server(默认)
ask-experts-mcp list                打印每个工具最终生效的 description(调优用)
ask-experts-mcp check               逐个 expert 发一个最小请求,报告 OK/FAIL + 延迟
ask-experts-mcp --config <path>     用指定配置文件,完全替换默认两层
ask-experts-mcp --help              帮助
ask-experts-mcp --version           版本号
  • list:调优 description 时的核心反馈工具——改完 trigger_keywords 跑一次就知道最终长什么样、有没有触发截断。
  • check:注册前 / 出问题时排查 API Key、baseURL、模型名是否对得上。退出码 0=全通过、非 0=有 expert 失败,可在 CI 当 gate。

错误处理与日志

| 错误类型 | 行为 | |---|---| | 401 / 403 API Key 无效 | 不重试,返回明确错误 | | 429 限流 / 配额耗尽 | 不重试,建议切其他 expert | | 超时(>timeout_ms) | 不重试(避免 turn 阻塞翻倍) | | 5xx 服务端 / 连接错误 | 重试 1 次(1s 退避) | | 模型返回空响应 | 返回错误,不返回空字符串 |

错误以 MCP isError: true 形式返回,调用方模型自行决定是否重试或换 expert。

日志:

  • 写到 stderr(MCP stdio 标准做法,大多数客户端会捕获)+ ~/.cache/ask-experts/log/server.log(滚动 5MB × 3)
  • 启动时打印一次配置加载摘要(API Key 脱敏)
  • 每次工具调用打印 [timestamp] ask_<name> latency=<ms> tokens_in=<n> tokens_out=<n> status=<ok|err:<code>>
  • defaults.log_level: "debug" 可看请求 / 响应体(API Key 脱敏)

FAQ

Q: 为什么不做内置 LLM 自动选 expert?

A: 调用方模型已经在做 reasoning,顺便选 expert 是零额外成本。内置路由会增加一次 LLM 调用(延迟+费用),且和调用方的判断打架。工具描述写好,调用方选得不会比一个小模型差。

Q: 配了 5+ 个 expert,调用方选不准怎么办?

A: 文档建议 ≤3 个 expert,且 trigger_keywords 应尽量互斥。需要更多 expert 可以分项目用 .ask-experts.json 局部启用。

Q: 支持 streaming 吗?

A: 不支持。MCP 协议返回完整结果即可,客户端主对话本身的流式由 MCP 客户端自己负责。

Q: 对调用方模型有什么要求?

A: 必须支持 tool use(function calling)。Claude 全系列、GPT-4 / 4o、Gemini 1.5+、Qwen 系列等主流模型都支持。如果调用方模型本身就是国产大模型(比如用 Qwen 调 Qwen),路由价值会显著降低——这个工具的甜点是"训练数据偏海外"的调用方 + 国产专家模型。

Q: 支持思考类模型(deepseek-reasoner / qwen-thinking / doubao-seed)吗?

A: 支持。在 expert 配置里加 "thinking": "drop"(默认丢弃)/ "prepend"(<thinking> 块附在答案前)/ "separate"(用分隔符切两段)。reasoning 模型一般要把 max_tokens 调大到 4K-8K。

Q: 我自己的内部 LLM 服务可以接吗?

A: 可以,只要兼容 OpenAI Chat Completions 非 streaming + 纯 messages 接口。配 provider: "custom" + baseURL + 完整 expertise.override: true 即可。

Q: 可以让 ask_ 工具返回英文吗?*

A: 工具调用时传 response_language: "en" 即可。该参数会注入到 system prompt;若 expert 配置了完整自定义 system_prompt,则由用户自行控制语言。


贡献

欢迎贡献新 provider 或修订现有预设的擅长领域元数据。

  • 改预设:编辑 presets/<provider>.json,跑 npm run build 重新生成
  • 加 provider:新建 presets/<name>.json + 在 src/config/schema.ts 的 PROVIDERS 列表加项
  • 跑测试:npm test(单测 + nock 集成测试,无需 API Key)
  • 跑路由质量评估:JUDGE=qwen npm run eval:routing(实跑 LLM,需要对应 API Key,详见 tests/routing/)
  • 跑 OpenAI 兼容性探针:HUNYUAN_API_KEY=... DASHSCOPE_API_KEY=... DOUBAO_API_KEY=... npx tsx scripts/probe-compat.ts

PR 请在描述里说明:为什么这条 trigger / avoid 关键词是必要的——最好附上一个真实的"调用方模型选错了"的例子,或一条 eval:routing 失败的 case。


License

MIT