Files
3c8578e9f4 feat(mcp): add Streamable HTTP transport (#736)
* feat(mcp): add Streamable HTTP transport

Add a modern MCP 2026-07-28 HTTP endpoint for standalone and Web modes, with shared listener configuration, authentication, schema, tests, and bilingual documentation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(tests): support Python 2 HTTP assertions

Normalize response header names and call handler methods through their underlying functions so the HTTP tests behave consistently on Python 2.7 and Python 3.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(mcp): harden HTTP request handling

Validate mirrored request IDs, align Config Studio listener checks, bound socket reads, and accept the binary wrapper's documented SIGINT exit status.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(mcp): align HTTP negotiation validation

Reject unavailable Accept media types by quality and keep schema host validation consistent with runtime listener checks.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(tests): validate host schema behavior

Assert accepted and rejected host samples instead of comparing Unicode escape representations that differ on Python 2.7.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(tests): avoid cross-engine schema regex

Keep the schema pattern contract without executing its ECMA-262 Unicode escape through Python 2's incompatible regex engine.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(mcp): validate HTTP request boundaries

Reject empty tokens and malformed JSON-RPC request shapes, and keep Config Studio bracket validation aligned with runtime listener handling.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(mcp): tighten HTTP input validation

Reject legacy notifications, nested host brackets, and document the required JSON content type so validation remains consistent across runtime, schema, and Config Studio.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(mcp): validate Origin before method errors

Apply the existing Origin policy to non-POST MCP requests and return CORS headers for configured allowed origins.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* docs(mcp): clarify proxy Origin allowlist

Explain that browser clients behind TLS termination must allowlist the public HTTPS origin even when the public page appears same-origin.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* docs(mcp): add standalone server guide

Move MCP client setup, transports, tools, security, and protocol limits into dedicated Chinese and English pages with matching navigation and index links.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(mcp): reject duplicate routing headers

Reject repeated MCP protocol, method, and name headers before body consistency checks across Python 2 and Python 3.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(mcp): validate named request headers

Validate Mcp-Name for tools/call, prompts/get, and resources/read before dispatching unsupported methods.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-08-23 21:36:26 +08:00

707 lines
20 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://ddns.newfuture.cc/schema/v4.1.json",
"description": "DNS 配置文件 https://github.com/NewFuture/DDNS",
"type": "object",
"properties": {
"$schema": {
"type": "string",
"title": "please use https://ddns.newfuture.cc/schema/v4.1.json",
"description": "请更换为 https://ddns.newfuture.cc/schema/v4.1.json",
"default": "https://ddns.newfuture.cc/schema/v4.1.json",
"enum": [
"https://ddns.newfuture.cc/schema/v4.1.json",
"http://ddns.newfuture.cc/schema/v4.1.json",
"./schema/v4.1.json"
]
},
"interval": {
"$id": "/properties/interval",
"type": "integer",
"title": "Web synchronization interval",
"description": "Web控制台内置同步间隔(分钟);配置后普通启动会自动进入Web模式",
"minimum": 1,
"maximum": 1440
},
"http": {
"$id": "/properties/http",
"type": "object",
"title": "Web and MCP HTTP listener",
"description": "Web控制台与MCP Streamable HTTP共享的监听和认证配置",
"properties": {
"host": {
"type": "string",
"minLength": 1,
"pattern": "^(?:\\[[^\\s/\\\\\\u0000\\[\\]]+\\]|[^\\s/\\\\\\u0000\\[\\]]+)$",
"default": "127.0.0.1",
"description": "监听地址;非回环地址和通配地址必须同时配置token"
},
"port": {
"type": "integer",
"minimum": 0,
"maximum": 65535,
"default": 9876
},
"token": {
"type": [
"string",
"null"
],
"minLength": 1,
"pattern": "^[!-~]+$",
"description": "Web API与MCP HTTP共享的Bearer token;回环监听可省略"
},
"origins": {
"type": "array",
"uniqueItems": true,
"default": [],
"items": {
"type": "string",
"pattern": "^https?://(?:\\[[0-9A-Fa-f:.%]+\\]|[^\\s/@?#:]+)(?::[0-9]+)?/?$"
},
"description": "允许跨源访问MCP endpoint的精确HTTP(S) origin"
}
},
"additionalProperties": false
},
"providers": {
"$id": "/properties/providers",
"type": "array",
"title": "DNS Providers List",
"description": "DNS服务提供商列表,支持多个不同的DNS服务商",
"items": {
"type": "object",
"properties": {
"provider": {
"type": "string",
"title": "DNS Provider Name",
"description": "dns服务商:阿里为alidns,阿里ESA为aliesa,DNS.COM为dnscom,DNSPOD国际版为(dnspod_com),cloudflare,ClouDNS为cloudns,HE.net为he,华为DNS为huaweidns,NameSilo为namesilo,腾讯云为tencentcloud,腾讯云EdgeOne为edgeone,腾讯云EdgeOne DNS为edgeone_dns,西部数码为west,自定义回调为callback",
"enum": [
"51dns",
"alidns",
"aliesa",
"callback",
"cloudflare",
"cloudns",
"debug",
"dnscom",
"dnspod_com",
"dnspod",
"edgeone",
"edgeone_dns",
"he",
"huaweidns",
"namesilo",
"noip",
"tencentcloud",
"west"
]
},
"id": {
"type": [
"string",
"null"
],
"title": "ID or Email",
"description": "DNS服务API认证的ID或者邮箱"
},
"token": {
"type": "string",
"title": "API Token",
"description": "DNS服务商的访问Token或者Key"
},
"endpoint": {
"type": [
"string",
"null"
],
"title": "API Endpoint",
"description": "DNS服务商的API端点URL,用于自定义或私有部署的API地址",
"default": null
},
"ipv4": {
"title": "IPv4 domain list",
"description": "待更新的IPv4 域名列表",
"type": "array",
"uniqueItems": true,
"items": {
"title": "ipv4 domain for DDNS",
"type": "string",
"pattern": "^(?:\\*\\.)?(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,18}$"
}
},
"ipv6": {
"type": "array",
"title": "IPv6 domain list",
"description": "待更新的IPv6 域名列表",
"uniqueItems": true,
"items": {
"title": "The ipv6 domain for DDNS",
"type": "string",
"pattern": "^(?:\\*\\.)?(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,18}$"
}
},
"index4": {
"type": [
"string",
"integer",
"boolean",
"array"
],
"items": {
"type": [
"string",
"integer"
],
"minimum": 0
},
"uniqueItems": true,
"minItems": 1,
"minimum": 0,
"title": "IPv4 address Setting",
"description": "本机 IPv4 获取方式设置,支持数组、字符串(逗号/分号分隔)等多种格式",
"default": [
"default"
]
},
"index6": {
"type": [
"string",
"integer",
"boolean",
"array"
],
"items": {
"type": [
"string",
"integer"
],
"minimum": 0
},
"uniqueItems": true,
"minItems": 1,
"minimum": 0,
"title": "IPv6 address Setting",
"description": "本机 IPv6 获取方式设置,支持数组、字符串(逗号/分号分隔)等多种格式",
"default": [
"default"
]
},
"ttl": {
"type": [
"number",
"null"
],
"title": "TTL",
"description": "设置DNS TTL,默认不填读取DNS服务商的配置",
"default": null
},
"line": {
"type": [
"string",
"null"
],
"title": "DNS Line/Route",
"description": "DNS线路设置,如电信、联通、移动等,支持中文和英文线路名称",
"default": null
},
"cache": {
"type": [
"string",
"boolean"
],
"title": "Enable Cache",
"description": "是否启用缓存记录以避免频繁更新",
"default": true,
"examples": [
true,
false,
"/path/to/cache/ddns.cache"
]
},
"cache_max_age": {
"type": "integer",
"minimum": 0,
"title": "Cache Max Age",
"description": "缓存文件最大有效期(秒);0表示每次启动都清空已有缓存",
"default": 259200
},
"log": {
"type": "object",
"title": "Log Config",
"description": "日志配置,仅支持设置日志级别",
"properties": {
"level": {
"type": "string",
"title": "Log Level",
"description": "日志级别,如 DEBUG、INFO、WARNING、ERROR、CRITICAL",
"default": "INFO",
"enum": [
"DEBUG",
"INFO",
"WARNING",
"ERROR",
"CRITICAL"
]
}
},
"required": [],
"additionalProperties": false
},
"proxy": {
"type": [
"string",
"null",
"array"
],
"title": "HTTP Proxy Setting",
"description": "该Provider专用的HTTP代理设置,支持多种格式:http://host:port(具体代理)、DIRECT(强制直连)、SYSTEM/DEFAULT(系统代理),多个代理逐个尝试直到成功",
"pattern": "^(https?://[a-zA-Z0-9\\-_:\\.]+|[a-zA-Z0-9\\-_:\\.]+:[0-9]+|DIRECT|SYSTEM|DEFAULT)(;(https?://[a-zA-Z0-9\\-_:\\.]+|[a-zA-Z0-9\\-_:\\.]+:[0-9]+|DIRECT|SYSTEM|DEFAULT))*$",
"examples": [
"http://127.0.0.1:1080",
"http://proxy.example.com:8080",
"DIRECT",
"SYSTEM",
"DEFAULT"
],
"uniqueItems": true,
"items": {
"title": "proxy setting for HTTP requests",
"type": "string",
"pattern": "^(https?://[a-zA-Z0-9\\-_:\\.]+|[a-zA-Z0-9\\-_:\\.]+:[0-9]+|DIRECT|SYSTEM|DEFAULT)$",
"examples": [
"http://127.0.0.1:1080",
"https://proxy.example.com:8080",
"DIRECT",
"SYSTEM",
"DEFAULT"
]
}
},
"extra": {
"type": "object",
"title": "Extra Fields",
"description": "额外的自定义字段,用于传递DNS服务商特定的参数,如Cloudflare的proxied、comment、tags等",
"additionalProperties": true,
"examples": [
{
"proxied": true,
"comment": "Managed by DDNS"
}
]
}
},
"required": [
"provider"
],
"not": {
"anyOf": [
{
"required": [
"interval"
]
},
{
"required": [
"http"
]
}
]
},
"additionalProperties": true
}
},
"id": {
"$id": "/properties/id",
"type": [
"string",
"null"
],
"title": "ID or Email",
"description": "DNS服务API认证的ID或者邮箱"
},
"token": {
"$id": "/properties/token",
"type": "string",
"title": "API Token",
"description": "DNS服务商的访问Token或者Key"
},
"endpoint": {
"$id": "/properties/endpoint",
"type": [
"string",
"null"
],
"title": "API Endpoint",
"description": "DNS服务商的API端点URL,用于自定义或私有部署的API地址",
"default": null,
"examples": [
"https://dnsapi.com",
null
]
},
"dns": {
"$id": "/properties/dns",
"type": "string",
"title": "DNS Provider",
"description": "dns服务商:阿里为alidns,阿里ESA为aliesa,DNS.COM为dnscom,DNSPOD国际版为(dnspod_com),cloudflare,ClouDNS为cloudns,HE.net为he,华为DNS为huaweidns,NameSilo为namesilo,腾讯云为tencentcloud,腾讯云EdgeOne为edgeone,腾讯云EdgeOne DNS为edgeone_dns,西部数码为west,自定义回调为callback",
"default": "dnspod",
"examples": [
"dnspod",
"alidns",
"cloudflare"
],
"enum": [
"51dns",
"alidns",
"aliesa",
"callback",
"cloudflare",
"cloudns",
"debug",
"dnscom",
"dnspod_com",
"dnspod",
"edgeone",
"edgeone_dns",
"he",
"huaweidns",
"namesilo",
"noip",
"tencentcloud",
"west"
]
},
"ipv4": {
"$id": "/properties/ipv4",
"title": "IPv4 domain list",
"description": "待更新的IPv4 域名列表",
"type": "array",
"uniqueItems": true,
"items": {
"$id": "/properties/ipv4/items",
"title": "ipv4 domain for DDNS",
"type": "string",
"pattern": "^(?:\\*\\.)?(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,18}$",
"examples": [
"newfuture.cc",
"ipv4.example.newfuture.cc"
]
}
},
"ipv6": {
"$id": "/properties/ipv6",
"type": "array",
"title": "IPv6 domain list",
"description": "待更新的IPv6 域名列表",
"uniqueItems": true,
"items": {
"$id": "/properties/ipv6/items",
"title": "The ipv6 domain for DDNS",
"type": "string",
"pattern": "^(?:\\*\\.)?(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,18}$",
"examples": [
"newfuture.cc",
"ipv6.example.newfuture.cc"
]
}
},
"index4": {
"$id": "/properties/index4",
"type": [
"string",
"integer",
"boolean",
"array"
],
"items": {
"type": [
"string",
"integer"
],
"minimum": 0
},
"uniqueItems": true,
"minItems": 1,
"minimum": 0,
"title": "IPv4 address Setting",
"description": "本机 IPv4 获取方式设置,支持数组、字符串(逗号/分号分隔)等多种格式",
"default": [
"default"
],
"examples": [
"default",
"public",
0,
"192\\\\.168\\\\..*",
"public,regex:192\\\\.168\\\\..*",
[
"public",
"default"
],
false
]
},
"index6": {
"$id": "/properties/index6",
"type": [
"string",
"integer",
"boolean",
"array"
],
"items": {
"type": [
"string",
"integer"
],
"minimum": 0
},
"uniqueItems": true,
"minItems": 1,
"minimum": 0,
"title": "IPv6 address Setting",
"description": "本机 IPv6 获取方式设置,支持数组、字符串(逗号/分号分隔)等多种格式",
"default": [
"default"
],
"examples": [
"default",
"public",
0,
1,
"2404:f801:10:.*",
"public;regex:2404:f801:.*",
[
"public",
"default"
],
false
]
},
"ttl": {
"$id": "/properties/ttl",
"type": [
"number",
"null"
],
"title": "TTL",
"description": "设置DNS TTL,默认不填读取DNS服务商的配置",
"default": null,
"examples": [
600,
null
]
},
"line": {
"$id": "/properties/line",
"type": [
"string",
"null"
],
"title": "DNS Line/Route",
"description": "DNS线路设置,如电信、联通、移动等,支持中文和英文线路名称",
"default": null,
"examples": [
"telecom",
"电信",
"default",
"默认"
]
},
"proxy": {
"$id": "/properties/proxy",
"type": [
"string",
"null",
"array"
],
"title": "HTTP Proxy Setting",
"description": "HTTP代理设置,支持多种格式:http://host:port(具体代理)、DIRECT(强制直连)、SYSTEM/DEFAULT(系统代理),多个代理逐个尝试直到成功",
"pattern": "^(https?://[a-zA-Z0-9\\-_:\\.]+|[a-zA-Z0-9\\-_:\\.]+:[0-9]+|DIRECT|SYSTEM|DEFAULT)(;(https?://[a-zA-Z0-9\\-_:\\.]+|[a-zA-Z0-9\\-_:\\.]+:[0-9]+|DIRECT|SYSTEM|DEFAULT))*$",
"examples": [
"http://127.0.0.1:1080",
"http://proxy.example.com:8080",
"DIRECT",
"SYSTEM",
"DEFAULT",
"http://127.0.0.1:1080;DIRECT"
],
"uniqueItems": true,
"items": {
"$id": "/properties/proxy/items",
"title": "proxy setting for HTTP requests",
"type": "string",
"pattern": "^(https?://[a-zA-Z0-9\\-_:\\.]+|[a-zA-Z0-9\\-_:\\.]+:[0-9]+|DIRECT|SYSTEM|DEFAULT)$",
"examples": [
"http://127.0.0.1:1080",
"https://proxy.example.com:8080",
"DIRECT",
"SYSTEM",
"DEFAULT"
]
}
},
"cache": {
"$id": "/properties/cache",
"type": [
"string",
"boolean"
],
"title": "Enable Cache",
"description": "是否启用缓存记录以避免频繁更新",
"default": true,
"examples": [
true,
false,
"/path/to/cache/ddns.cache"
]
},
"cache_max_age": {
"$id": "/properties/cache_max_age",
"type": "integer",
"minimum": 0,
"title": "Cache Max Age",
"description": "Maximum cache file age in seconds; 0 clears an existing cache on every invocation",
"default": 259200,
"examples": [
259200,
0
]
},
"ssl": {
"$id": "/properties/ssl",
"type": [
"string",
"boolean"
],
"title": "SSL/TLS Setting",
"description": "SSL/TLS连接设置,auto表示自动检测,true强制使用SSL,false禁用SSL",
"default": "auto",
"examples": [
"auto",
true,
false
]
},
"log": {
"$id": "/properties/log",
"type": "object",
"title": "Log Config",
"description": "日志配置,支持自定义日志级别、输出位置、格式和日期格式。可通过命令行 --log.level, --log.file, --log.format, --log.datefmt 或环境变量 DDNS_LOG_LEVEL, DDNS_LOG_FILE, DDNS_LOG_FORMAT, DDNS_LOG_DATEFMT 设置。",
"properties": {
"level": {
"type": "string",
"title": "Log Level",
"description": "日志级别,如 DEBUG、INFO、WARNING、ERROR、CRITICAL",
"default": "INFO",
"enum": [
"DEBUG",
"INFO",
"WARNING",
"ERROR",
"CRITICAL"
]
},
"file": {
"type": [
"string",
"null"
],
"title": "Log Output File",
"description": "日志输出文件路径,留空或为null时输出到控制台"
},
"format": {
"type": [
"string",
"null"
],
"title": "Log Format",
"description": "日志格式,参考Python logging模块的格式字符串",
"default": "%(asctime)s %(levelname)s [%(module)s]: %(message)s"
},
"datefmt": {
"type": [
"string",
"null"
],
"title": "Date Format",
"description": "日期时间格式,参考Python time.strftime()的格式字符串",
"default": "%Y-%m-%dT%H:%M:%S"
}
},
"required": [],
"additionalProperties": false
},
"extra": {
"$id": "/properties/extra",
"type": "object",
"title": "Extra Fields",
"description": "额外的自定义字段,用于传递DNS服务商特定的参数,如Cloudflare的proxied、comment、tags等",
"additionalProperties": true,
"examples": [
{
"proxied": true,
"comment": "Managed by DDNS",
"tags": ["production", "ddns"]
}
]
}
},
"not": {
"allOf": [
{
"required": [
"providers"
]
},
{
"anyOf": [
{
"required": [
"dns"
]
},
{
"required": [
"id"
]
},
{
"required": [
"token"
]
},
{
"required": [
"ipv4"
]
},
{
"required": [
"ipv6"
]
},
{
"required": [
"endpoint"
]
}
]
}
]
},
"anyOf": [
{
"required": [
"token"
]
},
{
"required": [
"providers"
]
}
],
"additionalProperties": true
}