MCP 接入

客户端配置

逐个客户端的实配片段。用哪种凭证只取决于一件事:你的客户端能不能用一份托管的元数据文档自证身份(CIMD)。能,填一个地址就够;不能,用长期密钥。

我的客户端该用哪种凭证?

从上往下看,命中第一条就停。决定因素是客户端的能力,不是牌子 —— 任何会 CIMD 的客户端都走「只填地址」这条路,不管它在不在下面的表里。

  1. 它支持 CIMD → 把接入地址填进去就完事了(Cursor 多一行 —— 它的文档我们替你挂好了,见下)。浏览器只弹一次:登录 → 选工作区 → 同意。不用注册,也没有密钥要保管。
  2. 它会 DCR(首次使用时自己注册)→ 同样只填接入地址。n8n、Dify 走这条,把它们的「Use Dynamic Client Registration」开关保持打开即可。
  3. 两样都不会,但你能自定义请求头 → 在设置页签发一枚 popkit_it_…,放进 Authorization。无人值守的场景也该用这条。
  4. 它会 OAuth,而且允许你手填 client_id → 自己托管一份小小的元数据文档,拿它的 URL 当 client_id。这样任何支持 OAuth 的客户端都能变成 CIMD 客户端 —— 做法见下一节。
  5. 以上都不是 → 它走不了 OAuth。实际上就是 Continue —— 它的 MCP 配置里根本没有 OAuth 字段。
客户端用哪种凭证为什么
Claude Code · claude.aiOAuth(不用注册)会 CIMD —— 用一个托管的元数据 URL 自证身份
CursorOAuth(不用注册)它的元数据文档我们替你挂好了 —— 填一个网址,不用密钥。见下
Cline · Continue请求头里放 popkit_it_…Cline 能手填 client_id 但官方没文档;Continue 根本没有 OAuth 字段
n8n · DifyOAuth(客户端自己注册)它们的 OAuth 走 DCR,生产现已开放 —— 保持 DCR 开关打开,不要手填
自建脚本请求头里放 popkit_it_…最省事的一条;也可以自托管一份元数据文档改走 OAuth
其它任何客户端跑下一节那个自测要问的是它会不会 CIMD,而不是它是哪个产品

多数客户端共用同一份 JSON 形状 —— mcpServers 映射 + url + headers:

通用模板
{
  "mcpServers": {
    "popkit": {
      "url": "https://popkit.loxily.com/api/mcp",
      "headers": {
        "Authorization": "Bearer popkit_it_YOUR_TOKEN"
      }
    }
  }
}

会 CIMD 的客户端(Claude Code · claude.ai)

Claude Code
claude mcp add --transport http popkit https://popkit.loxily.com/api/mcp

第一次使用时授权页自己会弹出来:登录 → 选工作区 → 同意 scope。没有 token 要粘,也没有东西要保管。claude.ai 那边把同一个地址加成自定义连接器即可。

scope 是在同意页上授予的,所以你在那里勾的就是这条连接的上限 —— 且永远不会超过你本人的角色。

Cursor

Cursor 不会自助注册,但它允许你手填 client_id —— 而这份我们替你挂好了,你既不用发布文档,也不用保管密钥。把下面这段放进 ~/.cursor/mcp.json:

~/.cursor/mcp.json
{
  "mcpServers": {
    "popkit": {
      "url": "https://popkit.loxily.com/api/mcp",
      "auth": {
        "CLIENT_ID": "https://popkit.loxily.com/.well-known/mcp-client/cursor"
      }
    }
  }
}

那个 CLIENT_ID 就是我们提供的一个网址:它是一份客户端元数据文档,写明了这是 Cursor、以及它那两个固定回调。点 Connect,浏览器弹一次 —— 登录、选工作区、同意,就好了。CLIENT_SECRET 整个不用写:这是公开客户端,靠 PKCE 保证安全。

我们替你托管这份文档只是省事,不代表我们担保它 —— 同意页仍会提示 popkit 没有核实过这个客户端。想自己掌控的话,可以自建一份文档(见「其它 MCP 客户端」一节),把 URL 换成你自己的。

更想用密钥?请求头里放 popkit_it_… 也行 —— 见上面的通用模板。

Cline · Continue

Cursor —— 放进 ~/.cursor/mcp.json(全局)或项目根的 .cursor/mcp.json(可提交、与团队共享;同名时项目级优先)。Cursor 会在 url 与 headers 里解析 ${env:NAME},所以 token 不必落在文件里:

~/.cursor/mcp.json
{
  "mcpServers": {
    "popkit": {
      "url": "https://popkit.loxily.com/api/mcp",
      "headers": {
        "Authorization": "Bearer ${env:POPKIT_MCP_TOKEN}"
      }
    }
  }
}

在 Cursor → Settings → MCP 里检查,服务器下应当列出 popkit 的工具。Cursor 确实支持 OAuth,但只走动态注册 —— 对生产走不通,所以用上面这个请求头。

Cline —— 从命令面板打开设置文件(Cline: Open MCP Settings),把通用模板合并进去。文件真实位置是 ~/.cline/data/settings/cline_mcp_settings.json(Cline 自己的文档里写的是一个已经失效的旧路径)。保存即热加载,不用重启。

Continue —— 是 YAML 不是 JSON,而且它的 OAuth 只对 sse 类型的 server 生效,所以这里只能用请求头。放进 ~/.continue/config.yaml,或作为块文件放在 .continue/mcpServers/ 下:

~/.continue/config.yaml
name: popkit-mcp
version: 0.0.1
schema: v1
mcpServers:
  - name: popkit
    type: streamable-http
    url: https://popkit.loxily.com/api/mcp
    requestOptions:
      headers:
        Authorization: Bearer ${{ secrets.POPKIT_MCP_TOKEN }}
Continue 的 IDE 扩展读不到你在 shell 里 export 的变量 —— 要把 POPKIT_MCP_TOKEN=… 写进 ~/.continue/.env。另外 MCP 工具只在 agent 模式下可用。

n8n · Dify

n8n —— 给 Agent 挂一个 MCP Client Tool 节点(单次调用则用普通的 MCP Client 节点),填三项:

  • Server Transport:选 HTTP Streamable(较新版本的默认值;SSE 那项已废弃)
  • Endpoint:https://popkit.loxily.com/api/mcp
  • Authentication:选 MCP OAuth2 API,新建凭据后保持「Use Dynamic Client Registration」打开,只填 Server URL 为接入地址,保存,再点 Connect。浏览器会弹一次:登录 → 选工作区 → 同意。没有什么要粘。
  • 更想用密钥(无人值守、没有浏览器)?那就选 Bearer Auth,把 popkit_it_… 填进唯一的 Bearer Token 框。
HTTP Streamable 需要 n8n ≥ 1.104;建议 ≥ 2.33 —— 更早的版本在执行结束后不回收 MCP 会话,会持续重连直到空闲超时。网上可能看到有人把 n8n issue #24967 当成传输层缺陷引用:官方结论是会话泄漏而非传输选择,且已修复。

Dify —— Integrations → Tools → MCP → Add MCP Server (HTTP)。Server URL 填端点,起个名字和服务器标识,然后在 Headers 里加一行:名字 Authorization,值 Bearer popkit_it_…。也可以改开 OAuth 授权、并保持「Use Dynamic Client Registration」打开 —— 这条现在通了,省掉管密钥的麻烦。填好点 Get tools 导入工具。

其它 MCP 客户端

上面那些不是白名单 —— popkit 从不看是哪个产品在调。你的客户端不在表里,就照下面判断它落在四条路的哪一条:

  1. 把接入地址填进去,看它怎么反应。 会 CIMD 的客户端会拿自己那份元数据文档的 URL 当 client_id 发过来,浏览器随即弹出,你就完事了。很多客户端号称「支持 OAuth」其实指的是 DCR —— 特征是报错里提到注册。
  2. 翻它的文档看有没有 client_id。 只要允许你手填,就走下面第 3 条,不管它自己怎么描述注册方式。
  3. 再不行就找自定义请求头的设置。 只要能发 Authorization: Bearer …,长期密钥就能用。

第 3 条 —— 自己托管一份元数据文档。 CIMD 的意思是 client_id 本身就是一个 URL,popkit 会去抓这个 URL 来认识这个客户端。所以把下面这份 JSON 挂到任意公网 HTTPS 地址上,再把这个地址作为 client_id 交给你的客户端即可:

https://example.com/mcp-client.json
{
  "client_id": "https://example.com/mcp-client.json",
  "client_name": "My Agent",
  "redirect_uris": ["http://127.0.0.1:8765/callback"],
  "token_endpoint_auth_method": "none",
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"]
}

要求很短:HTTPS 上以 JSON 提供、client_name 非空、redirect_uris 是非空的绝对 URI 数组、token_endpoint_auth_method 取 none(缺省)或 private_key_jwt。http://127.0.0.1:端口/callback 这类环回回调是允许的,所以命令行与桌面客户端同样走得通。

你在文档里写的 client_name 就是同意页上给授权人看的名字 —— 请按真正在连接的那个东西命名,不要写成 popkit。对方在同意页上授予的 scope 就是这条连接的上限,且永远不会超过他本人的角色。

自建客户端

用官方 SDK —— 传输层负责组包,你只管把请求头带上:

TypeScript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(new URL("https://popkit.loxily.com/api/mcp"), {
  requestInit: {
    headers: { Authorization: `Bearer ${process.env.POPKIT_MCP_TOKEN}` },
  },
});

const client = new Client({ name: "my-app", version: "1.0.0" }, { capabilities: {} });
await client.connect(transport);

const { tools } = await client.listTools();
const res = await client.callTool({ name: "get_workspace_context", arguments: {} });
console.log(res.structuredContent);

不用 SDK 的话,每次调用就是一个 POST —— 请求头与信封的硬要求见 工具参考。动手前有四件事值得先弄对:必带的请求头、_meta 信封、同时能读 application/json 与 SSE 两种应答、以及把三层错误分开处理(见 错误与排查)。

本端点是无状态的:从不签发 Mcp-Session-Id,所以没有会话要保活、也没有东西要注销。GET 与 DELETE 按设计回 405 —— MCP 的官方 SDK 把它当正常情况处理。