关于 qURL
qURL 是供 AI Agent 发布正在运行的本地应用并管理短期私密访问链接的 MCP 服务。它提供基于 CLI 的本地模式,以及基于账户的 API 或远程 HTTP 模式;应用分享与文件上传采用不同流程。
主要功能
- 01发布运行中的应用或 URL
- 02创建和管理限时链接
- 03处理访问请求与授权
- 04上传文件或文本并生成链接
- 05解析令牌并管理会话
适用场景
- 01向评审者分享 localhost 预览
- 02向接收者提供 PDF 临时访问链接
- 03批准或拒绝私密访问请求
MCP 相关
通过本地 stdio 或经身份验证的远程 HTTP 向 MCP 客户端提供 qURL 工具。本地模式调用 qURL CLI;基于账户的模式使用 qURL API。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y @layervai/qurl-mcpQURL_API_KEY密钥Optional. Without it, the tools run through the local qURL CLI (qurl), which needs no account. With it, the tools use the qURL API: a key with qurl:read, qurl:write, and/or qurl:resolve scopes from https://layerv.ai.QURL_API_URLqURL API base URL. Defaults to https://api.layerv.ai. Override only for testing against a non-production qURL backend.QURL_CONNECTOR_URLConnector base URL used by local-file, file-data, and text-to-PDF upload tools before minting a qURL.QURL_MCP_CONFIGOptional path to a shared qURL MCP config file. Both stdio and HTTP modes can read SMTP, connector, and default API settings from this file.MCP_MAX_UPLOAD_FILE_DATA_BYTESMaximum decoded/local upload size. Accepts bytes or units such as 10mb; capped at 100mb.QURL_SMTP_HOSTSMTP hostname for optional qURL link delivery.QURL_SMTP_PORTSMTP port for optional qURL link delivery.QURL_SMTP_SECUREWhether SMTP uses an implicit TLS connection (true/false).QURL_SMTP_USERNAME密钥SMTP authentication username.QURL_SMTP_PASSWORD密钥SMTP authentication password or app-specific credential.QURL_SMTP_FROM_EMAILValidated sender email address for qURL delivery.QURL_SMTP_FROM_NAMEOptional sender display name for qURL delivery.QURL_SMTP_ALLOWED_RECIPIENTSOptional comma-separated exact recipient allowlist.QURL_SMTP_ALLOWED_RECIPIENT_DOMAINSOptional comma-separated recipient-domain allowlist.QURL_SMTP_MAX_RECIPIENTS_PER_MESSAGEMaximum recipients in one delivery request (default 10).QURL_SMTP_MAX_RECIPIENTS_PER_HOURMaximum attempted recipients per qURL key per fixed hourly window (default 100).本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
13收录的工具列表 · 更新于 2 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| type | string | 否 | 允许发行非 URL qURL 的集成所用的资源类型(最多 64 个字符)。默认为 url。 |
| label | string | 否 | 用于标识此 qURL 接收对象的易读标签(最多 500 个字符) |
| expires_in | string | 否 | 时长字符串(例如:"1h"、"24h"、"7d") |
| target_url | string | 是 | 要通过 qURL 保护的 URL |
| max_sessions | integer | 否 | 此 qURL 令牌允许的最大并发会话数(明确设置 one_time_use 为 false 时,0 表示不限;最大为 1000) |
| one_time_use | boolean | 否 | 链接是否只能使用一次 |
| access_policy | object | 否 | qURL 的访问控制策略 |
| access_policy.ip_denylist | array | 否 | 拒绝的 IP 地址或 CIDR 范围(最多 100 项,每项 64 个字符) |
| access_policy.geo_denylist | array | 否 | 拒绝的国家/地区代码(ISO 3166-1 alpha-2;最多 50 项,每项 8 个字符) |
| access_policy.ip_allowlist | array | 否 | 允许的 IP 地址或 CIDR 范围(最多 100 项,每项 64 个字符) |
| access_policy.geo_allowlist | array | 否 | 允许的国家/地区代码(ISO 3166-1 alpha-2;最多 50 项,每项 8 个字符) |
| access_policy.ai_agent_policy | object | 否 | 结构化的 AI Agent 访问控制 |
| access_policy.ai_agent_policy.block_all | boolean | 否 | 阻止所有已识别的 AI Agent |
| access_policy.ai_agent_policy.deny_categories | array | 否 | 要阻止的 AI Agent 类别(例如:gptbot、commoncrawl;最多 20 项,每项 128 个字符) |
| access_policy.ai_agent_policy.allow_categories | array | 否 | 要允许的 AI Agent 类别(阻止所有其他类别;最多 20 项,每项 128 个字符) |
| access_policy.user_agent_deny_regex | string | 否 | 用于拒绝匹配用户代理的正则表达式(最多 256 个字符) |
| access_policy.user_agent_allow_regex | string | 否 | 用于允许匹配用户代理的正则表达式(最多 256 个字符) |
| custom_domain | string | 否 | 分配给自动创建资源的自定义域名(最多 253 个字符,必须已注册、已启用且归您所有)。 |
| session_duration | string | 否 | 收件人访问内容后,访问权限持续的时长(例如,"1h")。创建新资源时,此值用于设定资源级会话时长上限。 |
详细介绍
用于临时访问链接的 qURL MCP 服务
为 AI Agent 提供工具,通过即将过期的 qURL™ by LayerV 访问链接分享 localhost Web 应用、私有 API 和指定文件。
此仓库实现了用于该工作流的 Model Context Protocol 服务。
@layervai/qurl-mcp 软件包可以作为本地 stdio 服务运行,由 qURL CLI 或 API 提供支持;也可以作为经过身份验证的远程 HTTP 服务运行,由 API 提供支持。
从无需账号的本地快速入门或基于账号的客户端配置开始,然后根据任务选择工具。在本地模式下,publish_crid 会运行已安装的 CLI,发布已在运行的应用;share_by_crid 会为其生成访问链接。仅创建链接不会发布应用,也不会限制现有的公开 URL。上传需要基于账号的工具集,并使用独立的连接器生命周期;支持的选项和限制请参阅上传工具。
⚠️ 在 v0.4.0 中由
@layerv/qurl-mcp更名而来。 旧软件包已弃用,不会再收到更新。如果你使用的是@layerv/[email protected],只需在 MCP 客户端配置中替换作用域即可——二进制文件和 API 密钥都相同,无需其他更改。
让 AI Agent 分享本地预览
当 Agent 需要让审核者访问开发预览或内部 API 时,可以使用此工作流。创建链接的工具不会在你的笔记本电脑上启动应用。
-
保持本地应用运行。使用无需账号的快速入门配置本地 stdio MCP 客户端,并确保 qURL CLI 安装在同一主机上,且未设置
QURL_API_KEY。 -
请 Agent 使用
app_name(简短的公开名称,不包含密钥或收件人信息)和应用的根回环 URL(例如http://127.0.0.1:3000)调用publish_crid,并保存返回的 CRID。也可以使用 CLI 直接发布。 本地工具使用该设备的设备身份;CRID 不会授予其他设备访问该资源的权限。 -
请 Agent 使用已发布的 CRID 和请求的有效时长调用
share_by_crid。以下是工具参数对象,而非完整的 MCP 消息:{ "crid": "REPLACE_WITH_PUBLISHED_CRID", "ttl": "5m" } -
通过你选择的私密渠道分享返回的完整链接,并说明服务返回的过期时间。不要假定请求的 TTL 会原样获准。保持发布主机和应用可用。
请确认你安装的版本提供了这些工具。在基于账号的模式下,share_by_crid 则使用 API 凭据,并要求 qurl:resolve 和资源授权。对于已通过 API 管理的资源,请参阅 mint_link 和其他链接管理工具。工具是否可用以及资源标识符都很重要;不能将已上传文件的标识符用于此工作流。
让 AI Agent 分享 PDF 或图像
例如,向审核者提供一个指向选定 PDF 报告的短期链接。
使用基于账户的 stdio 模式(设置 QURL_API_KEY),或经过身份验证的 HTTP 模式,
然后在配置文件下配置上传 Connector。
无账户本地模式不会列出上传工具。请根据传输方式选择工具:
| 文件位置 | 工具 | 重要要求 |
|---|---|---|
| MCP 服务主机上的 PDF 或受支持的栅格图像 | upload_file_qurl | 在 stdio 模式下可用;主机进程必须有权读取所选文件。 |
| 提供给 HTTP 或 stdio MCP 客户端的 PDF 或图像字节 | upload_file_data_qurl | 将受支持的文件以 base64 数据形式提供,并指定正确的文件名和媒体类型。 |
| 要分享为生成的 PDF 的文本 | upload_text_qurl | 使用已配置的上传服务,而不是发布本地应用。 |
stdio 工具参数示例:
{
"file_path": "/absolute/path/to/review.pdf",
"expires_in": "5m",
"one_time_use": true
}
仅当文件由用户选定时,才将这些参数传递给 upload_file_qurl。
该工具会将文件上传到已配置的文件服务,并返回新的访问链接。
请使用其响应中确认的有效期。打开一次性链接进行测试可能会在接收者打开前将其消耗掉。
目前无法通过此 MCP 服务撤销上传链接,且 mint_link
无法为已上传文件创建另一个链接。请参阅上传工具,
了解支持的格式、大小限制、响应字段和清理限制。
为 Agent 选择分享内容
Agent 应该分享应用,还是已部署的预览?
如果审核者需要访问当前的 localhost 应用,请保持应用运行,并使用本地 CLI 工具发布资源并生成链接。现有的 ngrok 端点、Cloudflare 应用或 Vercel 预览也可用于交接,但其访问控制和可用性由单独配置的服务决定。本服务提供 qURL 操作;它不会创建其他部署。选择工作流时,请参阅应用分享方式对比。请分享已确认的有效期,并保留应用的登录要求。
Agent 应该上传结果,还是链接到正在运行的文件服务?
选定的 PDF 或图像可以使用本服务的基于账户的上传工具。托管在 Google Drive 上的文档则使用 Drive 的共享权限;S3 对象可以使用预签名下载 URL。这些存储工作流不同于发布本地文件服务;本地文件服务必须保持可用。请根据结果应存放的位置以及 Agent 获准使用的服务来选择。本服务的上传标识符和撤销限制仍然适用;文件路径、已上传文件标识符和本地服务 CRID 不能互换。
MCP 分享常见问题
这是通往我 localhost 应用的公共隧道吗?
在无账户 stdio 模式下,本服务会调用本地 CLI 来发布和管理 已运行的应用。基于 API 和远程 HTTP 模式会使用其已配置的资源; 远程服务无法通过自己的 localhost 地址发布你笔记本电脑上的应用。 选择资源访问链接还是公共端点工作流时,请参阅 localhost 分享方式对比。
每个 AI 客户端都支持相同的工具吗?
不支持。请配置客户端支持的传输方式,并检查已安装服务的
工具列表。远程 HTTP 服务无法使用 upload_file_qurl 读取
客户端笔记本电脑上的文件;请对受支持的附件使用文件数据工具。
我可以互换使用应用链接和已上传文件链接吗?
不可以。应用资源管理和已上传文件链接生成遵循不同的生命周期。请使用签发链接的工具,并遵守其撤销限制。打开链接时,仍需使用你本地应用自身的登录方式。
概述
服务器会根据已配置的传输方式,将 qURL 操作作为 MCP 工具提供给客户端。有关产品设置,请参阅 LayerV MCP 指南;本版本源代码支持的功能见下表。
目前支持:
- 创建、读取、更新和删除 qURL
- 解析访问令牌
- 管理 qURL 令牌和会话
- 上传文本或文件内容并生成 qURL
- 可选提供 LayerV 公开法律页面
- 提供可配置的 MP4 视频播放页面
快速开始:无需账户
通过 Claude Desktop、Claude Code、Cursor、Codex 或任何本地 MCP 客户端,私下分享运行在你机器上的应用或某个 URL。你无需账户或 API 密钥:如果未设置 QURL_API_KEY,服务器会调用安装在你机器上的
qURL CLI,首次发布时会自动创建这台机器的身份。
1. 安装 qURL CLI(适用于 macOS 和 Linux;运行 MCP 服务器需要 Node.js 22.12 或更高版本):
(umask 022 && mkdir -p "$HOME/.local/bin" "$HOME/.local/state") && chmod go-w "$HOME/.local" "$HOME/.local/bin" "$HOME/.local/state" && curl -fsSL --proto '=https' https://raw.githubusercontent.com/layervai/qurl-integrations/main/scripts/install.sh | INSTALL_DIR="$HOME/.local/bin" sh
在 Windows 上,从最新版本下载 qurl.exe,并将其所在文件夹添加到 PATH。服务器会在 PATH、~/.local/bin、/opt/homebrew/bin 和 /usr/local/bin 中查找 qurl;许多 MCP 客户端不会将这些目录包含在传递给服务器的 PATH 中。如果找不到 CLI,每个工具都会返回此安装命令,而不会失败。
2. 将服务器添加到 MCP 客户端,无需 env 块。
Claude Desktop(claude_desktop_config.json)和 Cursor(~/.cursor/mcp.json):
{
"mcpServers": {
"qurl": {
"command": "npx",
"args": ["-y", "@layervai/qurl-mcp"]
}
}
}
Codex(~/.codex/config.toml):
[mcp_servers.qurl]
command = "npx"
args = ["-y", "@layervai/qurl-mcp"]
Claude Code:
claude mcp add qurl -- npx -y @layervai/qurl-mcp
3. 提出你的需求,例如“与我的客户端分享 localhost:3000 上的应用”。Agent 会发布该应用(应用仍在你的机器上运行;CLI 的后台服务会保持分享状态),并向你提供一个供单人使用的短期链接,或者启用访问请求,让其他人申请访问权限。
无需账户的工具
| 工具 | 功能说明 | CLI 命令 |
|---|---|---|
publish_crid | 私密发布本地应用或 URL,并返回其 CRID | qurl publish <url> [--allow-requests] [--access <mode>] |
share_by_crid | 为此机器发布的 CRID 创建短期访问链接 | qurl share <CRID> [--ttl] [--session-duration] |
list_crids | 列出此机器发布的资源(只读) | qurl list --status active |
manage_crid_requests | 列出、通过代码批准或拒绝访问请求;列出或移除已批准的人员;开启或关闭请求 | qurl requests、qurl approve、qurl deny、qurl grants |
manage_crid_access | 私密访问策略、邀请和使用者授权 | qurl access <action> <CRID> |
set_crid_sharing | 停止、启动或重启本地应用的共享 | qurl stop、qurl start、qurl restart |
delete_crid | 永久删除资源 | qurl delete <CRID> --yes |
这些工具遵循 qURL Agent 技能中的相同规则 (https://layerv.ai/skills/qurl/SKILL.md):
- 所有内容都以私密方式发布。这些工具没有公开发布选项。
- 只有对方提供的六位数代码才能用于批准待处理的访问请求。任何列表都不会显示代码,也没有工具可以按姓名批准:任何人都可以输入任意姓名,而姓名会作为未经验证的数据返回。
- 访问链接是仅供一个接收者使用的持有者密钥。CRID 本身不授予任何权限,可以安全分享。
服务器通过参数数组(绝不使用 shell)运行 CLI,并采用 JSON 输出、关闭的 stdin、超时和有界输出;它不会记录 CLI 输出的内容。需要账户密钥的工具(qURL 链接、令牌、会话和上传工具,以及 qurl:// 资源和提示词)不会在此模式下列出。
使用账户密钥
将 QURL_API_KEY 设置为 LayerV API 密钥,服务器便会直接使用 qURL API,并提供 功能映射 中描述的完整工具集:
{
"mcpServers": {
"qurl": {
"command": "npx",
"args": ["-y", "@layervai/qurl-mcp"],
"env": { "QURL_API_KEY": "lv_live_xxx" }
}
}
}
远程 HTTP 服务
HTTP 传输(qurl-mcp-http)为远程 Agent 运行时提供服务。它基于账户运行:每个请求都携带调用方的 qURL API 密钥作为持有者令牌,并且绝不会运行本地 CLI。请参阅 HTTP 身份验证
和 LayerV MCP 指南。
私有消费者访问
共享 qURL SDK 要求 Node.js 22.12 或更高版本。
publish_crid 会创建带有 keys、invite_only、
email_capture、review 或 contract 访问权限的私有 URL 资源。manage_crid_access 会使用当前版本更改
策略、发送邀请、列出授权、批准或拒绝请求,以及移除访问权限。这些工具会返回
限定于资源的回执,并省略邀请密钥和 bearer 链接。本地应用会在发布者的计算机上使用
qURL CLI。在本地模式下,必须提供 app_name,该参数会通过 qurl preview set 设置并确认
公开预览名称(需要支持该命令的 CLI)。
如果命名失败,工具会返回错误,并附上已发布的 CRID 和恢复
说明。它不会删除或重新发布资源。调用方现在必须
提供 app_name;请使用用户的应用名称或不含
机密信息或收件人详情的简短中性名称。即使已发送邀请邮件,也要在答复中包含返回的名称和浏览器地址。
例如,助手可以将“与 [email protected] 分享此内容,并且 不允许任何请求”转化为 invite_only 资源和一份已授权的邀请。 对于 email capture,消费者必须知道发布者会收到其经过验证的电子邮件地址。经过验证的电子邮件地址证明对邮箱的控制权,而非法律身份。 合同审批需要可信的发布者后端权益回执; 这些工具不会验证付款。session_cleanup 仍在等待时,不要报告连接已完全移除。
此功能需要匹配的服务和准入读取器。在发布者和消费者的使用流程通过测试之前,请保持 此功能禁用。该软件包固定使用已发布的 SDK 3.0.0,并支持在阻止依赖项脚本的情况下进行干净安装。本版本要求 Node.js 22.12 或更高版本;不再支持 Node.js 20。
运行时模式
| 模式 | 用途 | 启动命令 | 典型用例 |
|---|---|---|---|
stdio | 本地子进程 MCP 服务 | npm run start | Claude Desktop、Cursor、Codex 和其他本地 MCP 客户端 |
http | 经身份验证的远程 MCP 服务 | npm run start:http | HTTPS 后的远程 Agent 运行时 |
功能概览
qURL 管理工具
| 工具 | 描述 |
|---|---|
create_qurl | 创建新的 qURL |
resolve_qurl | 将访问令牌解析为受保护的目标 URL |
list_qurls | 列出 qURL 资源 |
get_qurl | 获取单个 qURL 的详细信息 |
delete_qurl | 删除 qURL |
extend_qurl | 延长链接的有效期(还需要 qurl:read) |
update_qurl | 更新 qURL 元数据或有效期 |
mint_link | 为现有资源生成新的访问链接 |
share_by_crid | 根据资源 CRID 生成临时访问链接 |
batch_create_qurls | 在一次请求中创建多个 qURL |
revoke_qurl_token | 撤销指定令牌 |
update_qurl_token | 更新指定令牌 |
list_qurl_sessions | 列出活跃的访问会话 |
terminate_qurl_sessions | 终止一个或所有活跃会话 |
share_by_crid 会将独立的 $<CRID> 值识别为明确请求,表示要为该 CRID
生成临时链接。$ 是面向用户的标记,会在将 CRID 发送到 qURL API 前移除。裸 CRID 仍受支持。
此工具需要 qurl:resolve。可选的 Go 时长 ttl 必须解析为正的整数秒数。
服务会限制所请求的有效时长。分享操作会发起一次请求,超时时间为 30 秒,且不会自动重试。
再次调用此工具可以生成另一个链接。
资源状态筛选条件接受 active、revoked 或 active,revoked。
即使 expires_at 已过期,资源仍保持 active 或 revoked 状态;单个访问令牌则可能过期。
list_qurls 不接受 expired,尽管响应解析可以容忍旧版取值。快照保留了上游过时的过期说明;
其 active/revoked 状态枚举才是权威依据。
网络故障或 HTTP 429 后重试 POST/PATCH 请求时,qURL SDK 会重用相同的 Idempotency-Key 和请求正文。
对于会修改数据的 HTTP 5xx 响应,不会自动重试。每次新的 MCP 工具调用都是一个带有新键的新操作,
因此重复调用 create_qurl、batch_create_qurls 或 mint_link 可能会生成额外令牌。MCP 不会向调用方提供传入自定义键的方式。
上传工具
| 工具 | 模式 | 描述 |
|---|---|---|
upload_file_qurl | stdio | 上传本地文件并生成 qURL |
upload_file_data_qurl | stdio/HTTP | 上传 base64 文件内容并生成 qURL |
upload_text_qurl | stdio/HTTP | 上传文本内容并生成 qURL |
upload_file_qurl 有意仅支持 stdio。它可以读取本地 MCP 进程用户可访问的任何受支持 PDF/图像,因此 Agent 只能在用户明确选择要分享的路径时调用它。不要将其暴露给不可信提示词或自主 Agent:否则,提示词注入可能会选择主机上其他可读取的 PDF/图像。请在文件系统访问权限仅限于预期可分享内容的 OS 账户下运行 stdio。 | ||
| HTTP 模式不会注册此主机文件工具。 | ||
| 字节/文本工具也可在 stdio 中使用,因此本地客户端无需先将聊天附件保存到已知的主机路径,即可分享这些附件。 | ||
连接器上传和链接生成是两个独立操作。链接来自连接器的 POST /api/mint_link/:resource_id(隧道模式下为按接收者加水印的视图),而非 qURL mint_link,因此上传的文件无法通过 mint_link 重新生成链接;请再次运行上传工具。上传链接支持 expires_in(1m-30d,会根据 MCP 主机时钟转换为绝对过期时间,因此主机时钟不准会缩短或延长链接有效期;如果主机时钟显示返回的过期时间已过,则会返回 expires_at_already_past)、one_time_use 和 session_duration(整数秒,最长 24h);必须省略 access_policy 和 max_sessions,或将其设为 null;非 null 值会在上传前被拒绝。如果连接器生成的链接数量超过请求数量,结果会在 unexpected_extra_link_count 中报告多出的数量,并在 unexpected_extra_qurl_ids 中列出连接器返回的 ID(最多 10 个);即使按此主机时钟判断链接已过期,这些链接也可能仍然有效,因此请告知用户。如果上传后生成链接失败,连接器目前没有删除端点;服务器会记录孤立的 resource_id 以供运维人员清理,并返回生成链接失败的信息。此服务器目前无法撤销上传链接:对上传文件的 resource_id 调用 delete_qurl 不会使连接器生成的链接失效(撤销需要连接器的 /api/revoke_links),因此敏感文件应优先使用较短的有效期。 | ||
时长输入接受整数天数或周数(7d、1w),或无符号 Go 单位序列(1h30m、1.5h)。混合使用天/周的序列(1d12h)、前导符号、小数点前无数字的分数,以及希腊字母 mu(μs)都会被拒绝;微符号(µs)则可接受。 | ||
| HTTP 上传尝试仍受每 IP 和每凭据的 MCP 速率限制约束;stdio 运维人员应另行限制自主重试循环。 | ||
上传验证会将声明的媒体类型与文件名及格式起始/结束标记进行匹配;它不是恶意软件扫描器,也不会完整解码 PDF/图像。为防止多格式文件攻击,PDF 最后的 %%EOF 标记后只能有 ASCII 空白;即使宽松的 PDF 阅读器能够接受,末尾含有其他字节的生成器输出也会被拒绝。JPEG 验证会检查帧结构和终止标记,而不会解码图像段。当媒体内容的语义有效性很重要时,经过身份验证的连接器必须在存储前独立解码或以其他方式完整验证内容。它还必须保留声明的安全媒体类型,并使用 `X-Content-Type-Options: | ||
| nosniff` 提供下载内容,而不是推断可执行文件类型。 | ||
| 这里有意不设置应用层路径允许列表:符号链接和检查时与使用时之间的竞态会使词法前缀检查成为误导性的安全边界。请使用专用 OS 账户、容器或只读挂载,确保其可读文件已限制在预期共享目录内。 | ||
最后一个路径组件会通过 O_NOFOLLOW 打开;在此可信本地用户边界内,中间目录的符号链接仍按文件系统的常规行为处理。 |
MCP 资源
| URI | 描述 |
|---|---|
qurl://links | 当前 qURL 列表 |
qurl://usage | 当前配额和使用情况信息 |
MCP 提示词
| 提示词 | 描述 |
|---|---|
secure_a_service | 安全服务集成提示词 |
audit_links | 链接审计提示词 |
rotate_access | 访问权限轮换提示词 |
快速开始
1. 安装依赖
npm install
对于仅在本地使用 stdio 的源码安装,请使用 npm install --omit=optional;这会
跳过 AWS SDK。使用 DynamoDB 凭证配额的 HTTP 部署必须使用常规安装,以便打包可选 SDK。
2. 构建
npm run build
3. 启动
本地 stdio 模式:
npm run start
远程 HTTP 模式:
npm run start:http
MCP 客户端示例
如果要在本地 MCP 客户端中以 stdio 模式使用此服务,请使用快速开始中的配置。省略
env 即可通过本地 qURL CLI 在无账户的情况下运行;也可以添加
"env": { "QURL_API_KEY": "lv_live_xxx" },使用账户密钥调用 qURL API。
配置文件
复制已跟踪的示例文件以创建本地配置文件:
cp qurl-mcp.config.example.json qurl-mcp.config.json
cp qurl-mcp.http.example.json qurl-mcp.http.json
本地文件已加入 gitignore,因此凭证和特定于机器的路径不会提交。
各文件的用途如下:
| 文件 | 用途 |
|---|---|
qurl-mcp.config.json | stdio 和 http 模式共用的运行时配置 |
qurl-mcp.http.json | 仅供 HTTP 使用的服务监听器和公共访问配置 |
qurl-mcp.config.json 参考
共享核心设置
| 字段 | 用途 |
|---|---|
maxUploadFileDataBytes | 限制解码文件和本地文件上传大小(默认值为 10mb) |
defaultQurlApiUrl | qURL 后端 API 的基础 URL |
defaultQurlConnectorUrl | 上传连接器的基础 URL |
共享设置可由以下环境变量覆盖。环境变量的优先级高于共享配置文件。 进程会缓存解析后的共享设置,但当文件元数据或任何相关环境变量发生变化时,会自动使缓存失效。
| 环境变量 | 配置字段 |
|---|---|
MCP_MAX_UPLOAD_FILE_DATA_BYTES | maxUploadFileDataBytes |
QURL_API_URL | defaultQurlApiUrl |
QURL_CONNECTOR_URL | defaultQurlConnectorUrl |
QURL_SMTP_HOST | smtp.host |
QURL_SMTP_PORT | smtp.port |
QURL_SMTP_SECURE | smtp.secure |
QURL_SMTP_USERNAME | smtp.username |
QURL_SMTP_PASSWORD | smtp.password |
QURL_SMTP_FROM_EMAIL | smtp.fromEmail |
QURL_SMTP_FROM_NAME | smtp.fromName |
QURL_SMTP_ALLOWED_RECIPIENTS | smtp.allowedRecipients |
QURL_SMTP_ALLOWED_RECIPIENT_DOMAINS | smtp.allowedRecipientDomains |
QURL_SMTP_MAX_RECIPIENTS_PER_MESSAGE | smtp.maxRecipientsPerMessage |
QURL_SMTP_MAX_RECIPIENTS_PER_HOUR | smtp.maxRecipientsPerHour |
QURL_PUBLIC_VIDEO_FILE_PATH | publicVideo.filePath |
QURL_PUBLIC_VIDEO_TITLE | publicVideo.title |
QURL_PUBLIC_VIDEO_PAGE_PATH | publicVideo.pagePath |
特意仅通过环境变量配置 QURL_API_KEY,配置文件中没有对应字段。 | |
SMTP 密钥也建议使用 QURL_SMTP_PASSWORD。如果在 POSIX 主机上将 | |
smtp.password 存储在配置文件中,请将该文件的权限限制为仅文件所有者可访问 | |
(例如,chmod 600);当文件具有组用户或其他用户的读取权限时,启动时会发出警告。 | |
| 此检查仅提供建议,因此现有部署升级后不会因此启动失败;Windows 上没有 POSIX | |
| 权限位,因此会跳过此检查。 | |
除非配置了至少一项精确的 smtp.allowedRecipients 或 | |
smtp.allowedRecipientDomains,否则电子邮件投递会默认拒绝;当 SMTP 凭据完整但 | |
| 缺少此策略时,启动时会发出警告。 |
提高 maxUploadFileDataBytes 也会将 HTTP JSON 解析器的单请求内存上限提高到该值的
约 1.5 倍(在 100 MB 的最大值下约为 150 MB),之后 Base64 解码会应用精确的字节数上限。
在会话成功完成一次下游 qURL API 调用之前(已完成上传并生成链接也算),其解析器上限仍为
较小的默认上传设置 10 MB;配置了较大首个上传文件的客户端必须先通过一次较小的 qURL API
调用或较小的上传来验证会话。
请一并设置配置的最大值和反向代理并发限制。
在环境变量中设置 QURL_API_KEY,即可在 stdio 模式下使用 qURL API。
如果未设置,该模式将通过本地 qURL CLI 运行,无需账户
(参见快速入门(无需账户))。在 HTTP 模式下,每个
客户端请求都必须通过 bearer token 提供自己的 qURL API 密钥。
对于非回环主机,defaultQurlApiUrl 和 QURL_API_URL 必须使用 HTTPS,因为 qURL API 密钥
和数据会以 bearer 方式发送到该目标。只有字面量回环开发端点才接受普通 HTTP。
上传连接器 URL 也遵循相同的 HTTPS(回环地址除外)规则。
回环地址指 127.0.0.0/8 或 ::1;不接受 0.0.0.0 和 :: 这类通配绑定地址作为
出站 HTTP 目标。连接器目标属于可信的运维人员配置,而非调用方输入,因此允许使用私有地址
并进行 DNS 解析。请在部署 DNS 中固定连接器主机名,不要将其指向元数据服务。
调用方的 qURL bearer 凭据会转发到该主机,因此,连接器 URL 和 DNS 的控制权限属于凭据
信任边界的一部分。
请配置连接器服务的基础 URL,而非上传路由:qurl-mcp 会将 /api/upload 追加到普通基础
路径,接受恰好以该端点后缀结尾的 URL,并拒绝 /upload 或 /api/upload/v2 等含义不明确的
类上传路径。
MCP 服务会执行有界的文件帧检查,而不会完整解析媒体内容;连接器必须在存储或提供上传内容
之前独立重新验证,并且内容投递必须保留 nosniff 行为,将其作为权威的类型边界。
现在,API 和连接器基础 URL 若包含内嵌凭据、查询字符串或片段,启动时都会被拒绝。此前使用
这类特殊 URL 格式的部署必须将凭据移至 QURL_API_KEY,并确保配置的服务 URL 仅包含其源
和可选的路径前缀。
SMTP 设置
| 字段 | 用途 |
|---|---|
smtp.host | SMTP 服务器主机名 |
smtp.port | SMTP 服务器端口 |
smtp.secure | true 表示使用隐式 TLS;false 表示必须使用 STARTTLS |
smtp.username | SMTP 登录用户名 |
smtp.password | SMTP 登录密码或应用专用代码 |
smtp.fromEmail | 发件人电子邮件地址 |
smtp.fromName | 发件人显示名称 |
smtp.allowedRecipients | 可选的精确地址允许列表 |
smtp.allowedRecipientDomains | 可选的精确域名允许列表(不包含子域名) |
smtp.maxRecipientsPerMessage | 每封邮件的收件人数上限(默认值为 10) |
smtp.maxRecipientsPerHour | 每个 qURL 密钥在固定每小时窗口内尝试发送的收件人数上限(默认值为 100) |
当以下工具等请求发送电子邮件时,会使用这些设置:
create_qurlmint_linkupload_text_qurlupload_file_qurlupload_file_data_qurl如果配置了任一收件人允许列表,则只有地址或域名完全匹配时才会投递。如果两个列表都为空,邮件数量和每小时数量上限仍然适用。 域名条目必须完全匹配:example.com不会隐式允许mail.example.com;请明确列出每个获准的子域名。 比较和投递前,地址和域名会被规范化为小写的 NFC/IDNA ASCII 格式,并移除末尾的 DNS 根点。 每个收件人允许列表最多可配置 1,000 个条目。单封邮件的收件人数量上限适用于允许列表筛选前的完整去重请求收件人集合,因此无法通过提交超大批次来利用被屏蔽的地址。 在 HTTP 模式下,任何持有有效 qURL API 密钥的调用方都可以请求服务器端 SMTP 投递。在面向互联网的 HTTP 部署中启用 SMTP 前,请配置allowedRecipients或allowedRecipientDomains;允许列表为空时,任何语法有效的地址都可投递,但仍受配额限制。 SMTP 传输使用有界的连接/套接字超时,并在每批投递后关闭。SMTP 尝试失败仍会消耗配额,包括临时服务中断导致一封邮件都未投递的情况,因此反复失败无法绕过滥用限制。 每个投递请求的总时限也为 60 秒。时限到达前尚未开始处理的收件人会被报告为已跳过;对于规模更大或耗时更长的扇出投递,建议使用服务商端队列。 传输必须加密:smtp.secure: true使用隐式 TLS,而smtp.secure: false则要求成功升级到 STARTTLS。465 端口专用于隐式 TLS,因此必须设置smtp.secure: true。 每个服务器进程都会维护自己的每小时配额状态:服务器重启后配额会重置,且不会在多个副本间共享。运行多个实例的运营者应在 SMTP 服务商或网关处实施相应的总量限制。 因此,进程内配额只是滥用防护措施,并非持久的全局安全边界;必须通过服务商端限制来防范重启或扩容时的故障开放行为。 单个进程保留 10,000 个主体后,对新主体的跟踪将采取故障关闭策略;现有主体在过期条目被清理前,仍会继续使用当前配额桶。 请限制 qURL API 密钥的签发,并监控新主体的配额上限拒绝情况:轮换大量有效密钥可能会故意让共享表在一个配额周期内持续处于满载状态。 配额采用固定的一小时窗口;上一窗口过期后,首次尝试投递时窗口即开始。 与所有固定窗口一样,边界前后的流量总量可能接近配置的每小时上限的两倍;如果必须防止多个副本间出现这种边界突发,请使用服务商端的滑动或滚动限制。
HTTP SMTP 投递仅限使用在 QURL_API_KEY 中配置的运营者凭据。其他客户的有效 qURL 密钥不能授权使用运营者的 SMTP 帐户。未配置明确的运营者密钥时,HTTP 邮件投递将被禁用。Stdio 保留本地运营者信任模型。两种模式均适用收件人允许列表和配额。
生成的 qURL 链接会包含在纯文本邮件正文中。如果链接机密性很重要,请使用 SMTP 允许列表限制收件人,并在 SMTP 服务器/服务商处配置传输加密。
建议使用环境变量配置 SMTP 凭据和策略:
QURL_SMTP_USERNAME、QURL_SMTP_PASSWORD、QURL_SMTP_FROM_EMAIL、
QURL_SMTP_ALLOWED_RECIPIENTS、QURL_SMTP_ALLOWED_RECIPIENT_DOMAINS、
QURL_SMTP_MAX_RECIPIENTS_PER_MESSAGE 和
QURL_SMTP_MAX_RECIPIENTS_PER_HOUR。
公共视频页面设置
| 字段 | 用途 |
|---|---|
publicVideo.title | 公共视频页面上显示的标题 |
publicVideo.pagePath | 视频播放页面的公共路径 |
publicVideo.filePath | MP4 文件的服务器绝对路径 |
配置后,HTTP 服务还会公开:
- 公共视频播放页面
- MP4 文件的流式传输端点
publicVideo.filePath 是受信任的运维人员配置。最后一个路径组件必须是非符号链接的常规 .mp4 文件;中间目录中的符号链接仍按正常文件系统解析,因此必须由运维人员控制。启动时会探测此可选资源,并在文件缺失、为空或不是常规文件时发出警告,但会有意保持 MCP 服务和 /healthz 可用。视频文件路由仍会默认拒绝访问并返回 404,直到资源得到修正。
qurl-mcp.http.json 参考
本地有状态开发请使用 qurl-mcp.http.example.json。qurl-mcp.http.stateless.example.json 展示了已部署的无状态服务所需的所有存储和指标字段。
| 字段 | 用途 |
|---|---|
port | HTTP MCP 监听器端口 |
host | HTTP MCP 绑定地址 |
baseUrl | 服务的公共基础 URL |
allowedHosts | 用于验证 Host 标头的主机允许列表 |
trustProxyHops | 精确的受信任反向代理跳数(默认值为 0) |
stateless | 无会话亲和性的、按请求划分作用域的 HTTP 传输(默认值为 false) |
maxConcurrentRequests | 仅无状态模式下每个进程的 POST/解析器并发上限(默认值为 20) |
credentialRateLimitStore | 凭据计数器后端:memory 或 dynamodb(默认值为 memory) |
rateLimitDynamoDbTable | 共享凭据计数器使用的 DynamoDB 表 |
metricsNamespace | 无状态饱和度指标的 CloudWatch EMF 命名空间 |
metricsService | 稳定的 CloudWatch EMF Service 维度 |
metricsEnvironment | 稳定的 CloudWatch EMF Environment 维度 |
maxSessions | 活跃 MCP 会话硬性上限(默认值为 1000) |
maxSessionsPerCredential | 每个 bearer 的活跃及正在初始化会话上限(默认值为 20) |
maxUnvalidatedSessions | 尚未完成下游 qURL API 调用的会话上限(默认值为 100) |
sessionIdleTtlMs | 已连接会话的空闲驱逐时长(默认值为 15 分钟) |
sessionAbsoluteTtlMs | 会话绝对生命周期,包括活跃的 SSE/工具请求(默认值为 24 小时) |
unvalidatedSessionTtlMs | 从未验证的 bearer 会话的绝对验证时限(默认值为 1 分钟) |
mcpRateLimitPerMinute | 每个客户端的 /mcp 请求限制(默认值为 120) |
publicFileRateLimitPerMinute | 每个客户端的公共路由请求限制(默认值为 300) |
HTTP 字段均有对应的环境变量覆盖项:
| Environment variable | Config field |
|---|---|
MCP_PORT | port |
MCP_HOST | host |
MCP_BASE_URL | baseUrl |
MCP_ALLOWED_HOSTS | allowedHosts |
MCP_TRUST_PROXY_HOPS | trustProxyHops |
MCP_HTTP_STATELESS | stateless |
MCP_MAX_CONCURRENT_REQUESTS | maxConcurrentRequests |
MCP_CREDENTIAL_RATE_LIMIT_STORE | credentialRateLimitStore |
MCP_SERVE_LAYERV_LEGAL_PAGES | serveLayerVLegalPages (default false) |
MCP_RATE_LIMIT_DYNAMODB_TABLE | rateLimitDynamoDbTable |
MCP_METRICS_NAMESPACE | metricsNamespace |
MCP_METRICS_SERVICE | metricsService |
MCP_METRICS_ENVIRONMENT | metricsEnvironment |
MCP_MAX_SESSIONS | maxSessions |
MCP_MAX_SESSIONS_PER_CREDENTIAL | maxSessionsPerCredential |
MCP_MAX_UNVALIDATED_SESSIONS | maxUnvalidatedSessions |
MCP_SESSION_IDLE_TTL_MS | sessionIdleTtlMs |
MCP_SESSION_ABSOLUTE_TTL_MS | sessionAbsoluteTtlMs |
MCP_UNVALIDATED_SESSION_TTL_MS | unvalidatedSessionTtlMs |
MCP_RATE_LIMIT_PER_MINUTE | mcpRateLimitPerMinute |
MCP_PUBLIC_FILE_RATE_LIMIT_PER_MINUTE | publicFileRateLimitPerMinute |
MCP_MAX_UPLOAD_FILE_DATA_BYTES | maxUploadFileDataBytes (shared) |
监听器默认使用 127.0.0.1。除非显式配置 allowedHosts,否则会拒绝非回环地址的 host。将 trustProxyHops(或 MCP_TRUST_PROXY_HOPS)设为受信任代理跃点的确切数量;直接连接时保持为 0,以防转发的 IP 标头伪造速率限制键。
Host 允许列表最多包含 1,000 个条目,以确保即使操作员配置异常,运行时验证也能保持有界。
/mcp 会分别对客户端 IP 和经过身份验证的 bearer 的 SHA-256 摘要应用配置的请求限额。内存存储仅限于当前进程;DynamoDB 存储使用以凭据摘要和 UTC 分钟为键的原子固定窗口计数器。它绝不会存储 bearer。与任何固定窗口一样,在分钟边界附近,请求总数可能接近配置限额的两倍。表的契约是使用名为 rate_key 的字符串分区键;原子更新会写入数值型 request_count 计数器和数值型 expires_at TTL 时间戳。请在 expires_at 上启用 DynamoDB TTL,以免过期行不断累积;TTL 只会安排异步清理,活动窗口由键中的分钟重置,而非由物理删除重置。任务角色在启动时需要 dynamodb:DescribeTable,并在请求路径上需要对 dynamodb:UpdateItem 的权限。请使用按需容量,或为预期的整个任务集速率预留充足的写入容量;发生限流时会 fail closed,返回 503,且绝不会回退到内存存储。客户端使用标准重试模式,最多尝试两次,连接超时为一秒,请求超时为两秒,超时时会抛出异常;这些明确的限制可限制存储部分故障期间请求占用并发许可的时间。可选的 AWS SDK 依赖项在顶层固定为精确版本,而已提交的包锁定文件会固定其传递依赖项 @aws-sdk/* 和 @smithy/* 的依赖关系图。升级任何 SDK 时都必须更新锁定文件,并确保真实 NodeHttpHandler 的超时物化回归测试通过。仅在选择 DynamoDB 存储时才会加载该依赖项,因此仅使用 stdio 的消费者可以通过 --omit=optional 安装。已部署的 HTTP 镜像必须包含可选依赖项;如果 SDK 缺失或暴露不兼容的运行时接口,启动会在开始监听前失败。客户端使用标准的 AWS_REGION 和凭据提供程序链;ECS 部署通常会从任务环境和任务角色获取两者。使用反向代理部署时,必须设置正确的跃点数,否则代理后的所有调用方都会共用代理的单个 IP 限额桶。只有 DynamoDB 凭据限额是整个任务集共享的:IP 限流器仅限于当前进程,因此其实际的整个任务集限额会随任务数量成倍增加,且必须由共享边缘限流来配合。qurl-integrations-infra PR #1305 中的托管部署会同时实施按来源 IP 限制的 WAF 限额,以及更低的整个 /mcp 任务集总限额;实时余量证明记录在 issue #1306 中。凭据桶还可防止通过轮换来源 IP 来绕过请求限额,而 maxSessionsPerCredential 可防止单个凭据占满整个会话池。
在当前一分钟窗口内,每个不同的 bearer 值都会保留一个凭据桶条目。IP 限流器优先运行,因此来自同一来源的令牌轮换无法以高于 mcpRateLimitPerMinute 的速度创建条目;恶意的分布式流量仍需要使用文档中所述的共享边缘限流。由于不同的未验证 bearer 字符串必然会占用不同的凭据桶,因此 IP 桶是在进程内防止任意 bearer 轮换的主要控制措施。
在有状态模式下,为待处理会话的解析器内存预留预算时,请按 maxUnvalidatedSessions 乘以 maxUploadFileDataBytes 和 10 MB 中较小者的约 1.5 倍估算(每个请求另加约 64 KiB)。使用默认值时,理论并发上限约为 1.5 GiB。如果部署的内存预算较低,请同时降低 maxUnvalidatedSessions 和共享边缘并发限额。
bearer 凭据只有在首次成功调用下游 qURL API 时才会被确证为有效。在此之前,会话受较低的待处理会话上限和一分钟验证期限约束,因此任意非空 bearer 字符串都无法像正常的 15 分钟 TTL 那样占用整个会话池。只执行 MCP 内省的客户端会按设计保持待处理状态;期限届满并被清除后,客户端必须先重新初始化,才能发送下一条请求。对于从内省到工具调用间隔较长的客户端,可配置会话上限和验证期限。该期限是绝对期限,不受活动影响,包括 SSE 流保持打开或首次工具调用长时间运行的情况。
已验证的客户端如果断开连接时未发送 DELETE /mcp,其有界会话槽位会保留 30 秒,供客户端在宽限期内重新连接。重新连接会清除此期限;否则,会话会被回收,无须等待更长的空闲 TTL。对于保持连接但不会显式结束会话的客户端,请合理设置 maxSessions 和空闲 TTL。
即使 SSE 流或工具请求仍在进行,已验证的会话也会在 sessionAbsoluteTtlMs(默认 24 小时)后过期。这可以防止保活机制无限期占用全局或按凭据划分的会话槽位。
因此,首次下游 qURL 操作必须在该期限内完成;如果首次 API 调用异常缓慢,可能会被中断,客户端必须重新初始化。这种 fail-closed 行为可防止无效凭据通过故意运行时间过长的请求延长其待处理槽位。
达到未经验证会话上限时,新初始化会替换最早的空闲未验证会话,因此无效握手无法在整个验证 TTL 期间占满所有名额。已验证会话和活动请求绝不会被驱逐;待处理初始化和异步拆除也都受到限制。持续流量仍可能导致未验证会话频繁轮换,因此公共部署应使用无状态模式和边缘准入控制。
在 MCP 初始化期间接受非空 bearer 是有意为之:这样可在首次 qURL 操作前提供协议内省,同时全局会话上限、每凭据会话上限、待处理会话上限、绝对截止时间和请求速率限制会约束无效密钥对名额的占用。MCP 中间件本身不会验证密钥;只有下游 qURL API 成功响应后,会话才会升级为已验证状态。
下游错误(包括看似已通过身份验证的非 2xx 响应)不会使会话升级,因为中间代理可能会在 qURL API 验证 bearer 之前生成这些错误。
因此,会话升级依赖于这样的前提:所配置的 HTTPS qURL API 端点及所有受信任的中间代理都不会缓存或伪造已验证的成功响应。该链路中的反向代理必须转发授权信息,并为 qURL API 流量禁用响应缓存。
因此,任何持有非空 bearer 的调用方都可以枚举公开的工具/资源/提示词目录,并短暂占用受限的待处理会话状态。在不可信网络上,非环回部署应置于能够识别身份的代理之后,并由该代理为 /mcp 授权保留调用方的 qURL bearer 凭据。
初始化和目录列表只会返回由服务端管理的静态元数据;它们不会调用工具/资源/提示词处理程序、读取主机文件、联系 qURL API 或连接器,也不会发送电子邮件。处理程序调用依赖所配置的 qURL API 在返回数据或执行操作前对转发的 bearer 进行身份验证。所配置的连接器是第二个凭据授权方:它必须在接受或存储上传字节前验证转发的 qURL bearer。不支持部署未经过身份验证的连接器,因为这会允许未经验证的 MCP 调用方创建连接器端状态。
有状态模式是兼容性默认模式,并保留现有的 MCP 会话注册表、GET SSE、显式 DELETE 行为,以及对所有三种 MCP 方法按进程计费的凭据配额。有状态模式会为每个 POST 创建并关闭一个服务和传输,忽略 mcp-session-id,并对 GET 和 DELETE 返回 JSON-RPC 形式的 405 响应。负载均衡器或自动扩缩服务后必须使用此模式,因为它不依赖进程本地亲和性。并发许可会在解析 JSON 之前获取,并在每种响应/错误/断连路径中释放。无状态模式直接使用所配置的 maxUploadFileDataBytes 解析器上限,因为解析前的并发许可已对内存放大提供约束。
每个进程的内存预算大约为 maxConcurrentRequests 乘以(maxUploadFileDataBytes 的 1.5 倍加 64 KiB);在 100 MB 上传上限下,默认并发量在下游工作开始前约需 3 GiB。无状态模式启动时会拒绝保守解析器预算超过 4 GiB 的配置。如果 ECS 任务的内存限制较低,应进一步调低任一设置。相比之下,超过默认上限的有状态会话必须先成功完成一次下游 qURL API 调用。
在不可信网络上,部署时必须设置经过身份验证的边缘请求大小限制,且该限制不得高于所配置的解析器上限:许可可以限制总内存,但非空 bearer 只有在解析后的操作到达下游 qURL API 时才会得到权威验证。
无状态监听器会将接收标头的时间限制为 15 秒,并将接收完整请求和套接字空闲时长均限制为 120 秒。并发许可从解析开始一直占用到响应完成,因此停滞的客户端无法无限期占用整个许可池。若工具调用在 120 秒内未产生任何套接字流量,将按预期中止;需要执行更长时间静默操作的集成必须将此类工作移至异步 API,而不是提高适用于整个集群的保留时限。
已部署的(非回环)无状态模式要求使用 DynamoDB 凭证存储,并设置全部三个稳定的指标标识字段。该模式每 30 秒发送一次 EMF 心跳:McpConcurrencyUtilization 是在请求准入和心跳时观测到的区间内许可使用率峰值(包括在两次心跳之间开始并结束的请求),而 McpConcurrencyRejected 和 McpRateLimitStoreErrors 是采用快照后清零的区间增量,其中包含显式零值。会话上限和电子邮件收件人配额仍存储在内存中;DynamoDB 凭证配额是全集群共享的,计数涵盖每个经过身份验证的 HTTP POST,包括初始化、发现和工具调用。应根据预期的完整请求模式(而非仅工具调用)来设置该配额上限。许可还会在有界的 DynamoDB 递增操作期间持续占用:存储服务出现故障时,每个已准入请求可能会保留一个许可约四秒(两次各两秒的尝试),之后才会以失败关闭的方式失败;超出上限的请求则会快速收到并发 503。固定窗口计数器会递增每次尝试,包括已超过凭证限制的尝试;因此,边缘速率限制和 DynamoDB 写入/限流告警必须限制恶意写入放大。部署负责人必须将这两种告警和超限写入放大探测设为硬性发布门槛,而不能将其视为可选的可观测性措施。托管部署 qurl-integrations-infra#1305 会配置这些告警;其上线记录和 issue #1306 会跟踪上线验证情况,作为发布前的依据。对于注入凭证存储实现的直接 createHttpRuntime 嵌入方,非回环无状态模式仍必须声明 credentialRateLimitStore: "dynamodb"。通用注入接口无法证明自定义后端在多个副本间共享,因此注入机制不会成为规避已部署契约的途径。
状态化模式会拒绝指标标识字段,以免并发量规指标无声地报告误导性的零值。
每个无状态 POST 请求都会创建全新的 MCP 服务和传输层,因此任何请求都无法继承其他凭证的处理器状态。已完成响应的清理工作会以异步方式跟踪。当待清理队列达到 maxConcurrentRequests 时,将停止准入;此时已在处理的请求仍可完成,因此队列可能短暂达到该数量的两倍,但始终有界。在准入保护关闭期间,新请求会收到 503,并使 McpConcurrencyRejected 递增,而不会让清理内存无限增长。此计数器有意表示由活动请求饱和或清理背压导致的准入失败。自动扩缩容必须仅使用 McpConcurrencyUtilization;拒绝计数器仍应触发告警,而利用率较低但出现拒绝时,则表明清理延迟。
池化这些对象会削弱请求隔离能力;除非测得注册压力,否则不应将其作为性能优化。
/healthz 和公开视频文件端点各自使用独立的 publicFileRateLimitPerMinute 配额桶,彼此隔离,且不受法律页面/视频页面流量影响。负载均衡器、存活探针以及预期的视频范围请求频率应低于该按源 IP 计算的限额(默认每分钟 300 个请求);如果客户端请求频率异常高,则应提高此限额。
配置优先级
默认情况下,配置从上述两个本地 JSON 文件加载。如果文件不存在,则使用内置默认值和环境变量。
相对配置路径(包括默认路径)均从进程工作目录解析。如果 supervisor、npx 或 MCP 主机从其他目录启动服务,请设置下方的显式路径变量。
以下环境变量分别覆盖配置文件路径:
QURL_MCP_CONFIGQURL_MCP_HTTP_CONFIG
QURL_MCP_HTTP_CONFIG 不会替换共享运行时配置路径。这样可避免监听器设置悄然覆盖 SMTP、连接器或 API 设置。
server.json 和 smithery.yaml 描述已发布的 stdio 传输,因此其中包含共享的上传/SMTP 设置,但会有意省略仅用于 HTTP 的监听器变量,例如 QURL_MCP_HTTP_CONFIG 和 MCP_MAX_SESSIONS。
请勿提交 API 密钥、SMTP 凭据或私有文件系统路径。
HTTP 路由
以 http 模式启动后,可用的常见路由如下:
| 路由 | 用途 |
|---|---|
/mcp | 远程 MCP 主端点 |
/healthz | 健康检查端点 |
/legal/privacy | 公开隐私政策页面 |
/legal/terms | 公开服务条款页面 |
publicVideo.pagePath | 公开视频播放页面 |
publicVideo.pagePath + /file | MP4 流式传输端点 |
/healthz 对所有调用方均有意不进行身份验证和 Host 验证,仅公开 { "ok": true },并在单独的限流桶中使用已配置的公开路由请求限制,以免健康探测耗尽法律/视频路由的限额。此路由返回 429,表示探测来源超出了 publicFileRateLimitPerMinute,而非应用未通过存活检查;请将探测频率控制在此限额以下。由于 ALB 目标探测使用任务 IP 和端口作为 Host,此路由会在 Host 验证之前注册;公开的 MCP 和浏览器路由仍会进行 Host 验证。
HTTP 身份验证
每个请求都必须在 /mcp 端点提供 Authorization: Bearer <qURL API key>。在有状态模式下,Bearer 令牌会与生成的 MCP 会话绑定,因此会话 ID 不能与其他凭据重复使用。在无状态模式下,Bearer 令牌仅限当前请求使用,并会在响应关闭时丢弃。
**运营方身份验证边界:**初始化接受任意非空的 Bearer 令牌,并允许在首个下游 qURL API 调用进行权威验证前读取公开的工具/资源/提示词目录。该目录由静态架构和说明组成,不含 Bearer 令牌、SMTP 凭据或其他运营方配置。未验证会话数量上限、较短的验证期限和请求速率限制共同约束验证前的状态;提供的令牌只会转发给配置的 qURL API,以及用于上传工具的配置 qURL Connector。因此,仅进行内省的会话仍未经过验证,并会在 unvalidatedSessionTtlMs 到期后关闭;若客户端需要更长时间的会话,可以重新初始化。只有在成功调用 qURL API,或通过配置的连接器生成可交付的上传链接(该连接器会将 Bearer 令牌转发给 qURL API)后,会话才会升级;被拒绝或受速率限制的调用不能证明凭据有效。因此,连接器也是此信任边界的一部分:QURL_CONNECTOR_URL 只能指向会验证 Bearer 令牌的连接器。其上传错误文本(长度上限为 1 KiB,控制字符会被展平)和生成的链接都会返回给 Agent,生成的链接也可能通过电子邮件发送。断开连接的会话会在 30 秒的 SSE 重连宽限期内继续注册;在频繁变动的情况下,maxSessions 和 maxSessionsPerCredential 会限制此宽限范围。
不含 Origin 标头的请求会被接受,用于非浏览器 MCP 客户端。若存在 Origin,其来源必须与 baseUrl 的来源相匹配;/mcp 上格式错误或跨来源的值会被拒绝。公开的健康检查、法律文件和已配置的视频路由不使用浏览器来源状态,也不会受此检查限制。
为远程 MCP 客户端配置:
| 设置 | 值 |
|---|---|
| MCP 服务 URL | 您的公开 HTTPS URL 加上 /mcp |
| 身份验证 | Bearer 令牌 |
| 令牌 | 调用方的 qURL API 密钥 |
如果客户端仅支持 OAuth 发现,请在此服务前放置一个兼容 OAuth 的网关,而不是不经身份验证就公开 /mcp。
如何验证部署
服务级检查
从以下路径开始:
/healthz/mcp
LayerV 法律文件默认禁用。只有由 LayerV 运营的服务才应设置 MCP_SERVE_LAYERV_LEGAL_PAGES=true(或在 HTTP 配置中设置 serveLayerVLegalPages: true)。可自托管的运营方必须发布自己的政策。
公开页面检查
启用后,请验证法律页面和已配置的视频页面:
/legal/privacy/legal/terms- 已配置的公开视频页面路径
域名验证
如果计划使用 OpenAI Platform,请确保根目录下存在以下路径:
/.well-known/openai-apps-challenge
此验证文件必须放在域名根目录的
.well-known路径下,而不能放在/mcp下。
Docker
此代码仓库包含用于容器化部署的 Dockerfile。
示例:
docker build -t qurl-mcp .
docker run -i -e QURL_API_KEY=lv_live_xxx qurl-mcp
如果使用 Docker 部署,请确保容器仍可访问正确的配置文件,或通过环境变量覆盖配置文件路径。
在 Docker 中本地运行 HTTP 监听器:
镜像默认使用 stdio 入口点,且 HTTP 服务器默认绑定到容器本地回环地址。HTTP 部署必须覆盖命令,并绑定到 0.0.0.0,同时明确设置 Host 允许列表和 HTTPS 公共源站。此示例仅将端口发布到主机回环地址;请在前面配置 TLS 反向代理,以匹配已配置的 https://mcp.example.com 源站:
docker run --rm -p 127.0.0.1:3000:3000 \
-e MCP_HOST=0.0.0.0 \
-e MCP_BASE_URL=https://mcp.example.com \
-e MCP_ALLOWED_HOSTS=mcp.example.com,127.0.0.1,localhost \
qurl-mcp node dist/http.js
对于单个可信的生产环境反向代理,请设置 MCP_TRUST_PROXY_HOPS=1,在 MCP_BASE_URL 中使用公共 HTTPS 源站,并将 MCP_ALLOWED_HOSTS 设置为公共主机名。启用代理信任后,请勿直接暴露容器的监听器。
常用命令
| 命令 | 用途 |
|---|---|
npm run build | 编译 TypeScript |
npm test | 运行测试 |
npm run test:coverage | 运行强制覆盖率检查 |
npm run lint | 运行 ESLint |
npm run dev | TypeScript 监视模式 |
npm run format | 格式化源代码 |
npm run format:check | 检查格式 |
npm run start | 启动 stdio 模式 |
npm run start:http | 启动 HTTP 模式 |
推荐部署顺序
- 复制并更新两个示例配置文件
- 通过环境变量设置凭据
- 运行
npm install - 运行
npm run build - 运行
npm run start:http - 验证
/healthz - 验证未认证的
/mcp请求会收到401 - 配置 HTTPS 反向代理
- 验证已认证的 MCP 初始化以及可选公共页面
第三方资源
文本转 PDF 功能捆绑了常规字重的 Noto Sans SC TrueType 字体(约 10 MB),以离线支持多语言字形。静态字体保留了原可变字体中的所有字符;PDFKit 仅嵌入每份文档实际使用的字形。无需下载,也无需额外的运行时依赖。其 SIL Open Font License 和版权声明包含在 assets/fonts/OFL.txt 中;转换详情见 assets/fonts/README.md。
许可证
MIT -- LayerV AI
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。