Blog • Claude Code / MCP

Nach Upgrade auf Claude Code 2.1.318 mit deniedMcpServers URL-Regeln: JSON-Logs für Anthropic-gehostetes MCP und cloud connectors?

Am 4. November 2026 lieferte Anthropic Claude Code 2.1.318. serverUrl in deniedMcpServers blockiert auch Anthropic-gehostetes MCP per upstreamUrl; Connectors in cloud und self-hosted runner vergleichen connectorUrl zuerst, sonst serverName.

Session-Server-Metadaten-JSON: serverKind, upstreamUrl, connectorUrl, serverName, sessionSurface. Verweigerte MCP tool calls: decision denied, reason mcp_server_denied, matchedRule, matchedPattern, upstreamUrl. mcp_url_deny_gate spiegelt schema, deny_by_url, deny_by_connector_url, deny_by_name, allow, nicht serverCommand env-only.

serverCommand-Deny in MCP env allowlist und serverCommand; MCP-Sicherheitsbaseline in MCP-Sicherheit; Elicitation-Timeout-Stops in MCP elicitation timeout JSON. Dieser Artikel behandelt nur die deniedMcpServers URL-Erweiterung 2.1.318, managed settings JSON, Session-Server-Metadaten, MCP tool call, mcp_server_denied Audit-Felder und fünf mcp_url_deny_gate-Zweige.

Zuerst dies: 2.1.318 erweitert deniedMcpServers URL-Matching für gehostetes MCP und cloud connectors plus mcp_server_denied Audit; keine Neuschreibung der serverCommand env-only Deny-Tabelle. Unten: Changelog, managed settings JSON, Metadaten, MCP-Beispiel, Audit-Tabelle, mcp_url_deny_gate, JSONNote.

Wie erweitert 2.1.318 deniedMcpServers URL auf gehostetes MCP und cloud connectors

Änderungen stehen in Claude Code changelog, Tag-Seite Release v2.1.318. Früher vor allem user-konfiguriertes MCP; 2.1.318 gilt serverUrl auch für upstreamUrl bei Anthropic-gehostetem MCP; cloud und self-hosted runner prüfen connectorUrl zuerst, sonst serverName.

Verweigerung vor dem MCP tool call. Audit-JSON: decision denied, reason mcp_server_denied, matchedRule, matchedPattern, upstreamUrl für SIEM-Attribution zur URL-Regel.

Wie schreibt man serverUrl und serverName in deniedMcpServers der managed settings

In managed settings trägt deniedMcpServers serverUrl-Globs und serverName. Ab 2.1.318 matcht serverUrl upstreamUrl bei Anthropic-gehostetem MCP und connectorUrl bei cloud connectors.

Managed settings: ein serverUrl-Glob und ein serverName.
{
  "deniedMcpServers": [
    {
      "serverUrl": "https://mcp.example.com/v1/*"
    },
    {
      "serverName": "slack-connector"
    }
  ]
}

serverUrl kein String oder deniedMcpServers kein Array → schema zuerst, nicht allow bei Formfehlern.

Wie upstreamUrl und sessionSurface im Session-Server-Metadaten-JSON stehen

Beim Auflösen von MCP-Servern schreibt der Client Metadaten-JSON: serverKind, upstreamUrl, connectorUrl, serverName, sessionSurface.

Session-Metadaten: serverKind, upstreamUrl, connectorUrl, serverName, sessionSurface.
{
  "serverKind": "anthropic_hosted",
  "upstreamUrl": "https://mcp.example.com/v1/tools",
  "connectorUrl": "https://connect.example.com/slack",
  "serverName": "analytics-mcp",
  "sessionSurface": "cloud"
}

upstreamUrl und connectorUrl non-leer; sessionSurface in enum; fehlendes serverKind → schema; kein Regeltreffer → allow.

Session-Metadaten-JSON-Schema: Form vor mcp_url_deny_gate.
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "additionalProperties": false,
  "required": ["serverKind", "upstreamUrl", "connectorUrl", "serverName", "sessionSurface"],
  "properties": {
    "serverKind": { "type": "string", "enum": ["anthropic_hosted", "user_configured", "connector"] },
    "upstreamUrl": { "type": "string", "minLength": 1 },
    "connectorUrl": { "type": "string", "minLength": 1 },
    "serverName": { "type": "string", "minLength": 1 },
    "sessionSurface": { "type": "string", "enum": ["cloud", "local", "self_hosted_runner"] }
  }
}

Wie MCP tool call JSON zu Server-Metadaten ohne Regeltreffer passt

Trifft upstreamUrl serverUrl, tool JSON mit mcp__analytics-mcp__search; kein MCP tool, decision denied. CALL_OUTSIDE → allow.

Regeltreffer: MCP tool call denied.
{
  "tool": "mcp__analytics-mcp__search",
  "arguments": {
    "query": "quarterly revenue"
  }
}
Kein Regeltreffer: Metadaten → allow.
{
  "serverKind": "anthropic_hosted",
  "upstreamUrl": "https://other.example.com/v1/tools",
  "connectorUrl": "https://connect.example.com/other",
  "serverName": "other-mcp",
  "sessionSurface": "cloud"
}

Wie decision denied und mcp_server_denied in Audit-Logs stehen

Trifft upstreamUrl oder connectorUrl eine Regel: decision denied, reason mcp_server_denied, matchedRule, matchedPattern, upstreamUrl; connectorUrl für cloud. serverCommand env-only und URL deny nicht in einer reason-Enum mischen.

Audit-Log: decision denied, reason mcp_server_denied, matchedRule, matchedPattern, upstreamUrl.
{
  "decision": "denied",
  "reason": "mcp_server_denied",
  "matchedRule": "serverUrl",
  "matchedPattern": "https://mcp.example.com/v1/*",
  "upstreamUrl": "https://mcp.example.com/v1/tools"
}
Session- oder URL-Signalmcp_url_deny_gate liefertOperator-Aktion
upstreamUrl trifft serverUrl-Globdeny_by_urlAudit an decision denied, matchedRule serverUrl, matchedPattern, upstreamUrl anpassen.
connectorUrl trifft serverUrl, upstream nichtdeny_by_connector_urlmatchedRule serverUrl loggen, connectorUrl für cloud-Attribution behalten.
serverName trifft deniedMcpServers-Namensregeldeny_by_namereason mcp_server_denied und matchedRule serverName schreiben.
Schlechte Metadaten-JSON-Form oder fehlende Deny-ListeschemaManaged settings oder ctx fixen vor deny-Zweigen.

Wie mcp_url_deny_gate zwischen schema und fünf deny-Zweigen wählt

Reihenfolge: CTX_SCHEMA für serverKind, upstreamUrl, connectorUrl, serverName, sessionSurface; deniedMcpServers durchlaufen; upstreamUrl trifft serverUrl → deny_by_url; connectorUrl trifft serverUrl → deny_by_connector_url; serverName trifft Namensregel → deny_by_name; sonst allow.

deny_by_url und deny_by_connector_url nicht zu einem mcp_denied zusammenlegen. deny_by_connector_url für cloud connectors, deny_by_url für gehostetes MCP, deny_by_name für Namen.

mcp_url_deny_gate: schema, deny_by_url, deny_by_connector_url, deny_by_name, allow.
def actual_type(data: object) -> str:
    if data is None:
        return "null"
    if isinstance(data, bool):
        return "boolean"
    if isinstance(data, list):
        return "array"
    if isinstance(data, int):
        return "integer"
    if isinstance(data, float):
        return "number"
    if isinstance(data, str):
        return "string"
    if isinstance(data, dict):
        return "object"
    raise TypeError(type(data))

def validate(data: object, schema: dict) -> list[str]:
    errors: list[str] = []
    if not isinstance(schema, dict):
        return errors
    types = schema.get("type")
    if isinstance(types, str):
        types = [types]
    actual = actual_type(data)
    if types and not any(t == actual or (t == "number" and actual == "integer") for t in types):
        errors.append("type")
    if "enum" in schema and not any(value == data for value in schema["enum"]):
        errors.append("enum")
    if isinstance(data, str) and "minLength" in schema and len(data) < schema["minLength"]:
        errors.append("minLength")
    if isinstance(data, dict) and schema.get("properties"):
        for key in schema.get("required") or []:
            if key not in data:
                errors.append(f"required:{key}")
        if schema.get("additionalProperties") is False:
            for key in data:
                if key not in schema["properties"]:
                    errors.append(f"additional:{key}")
        for key, sub in schema["properties"].items():
            if key in data and data[key] is not None:
                errors.extend(validate(data[key], sub))
    return errors

def url_match(url: str, pattern: str) -> bool:
    return fnmatch(url, pattern)

def mcp_url_deny_gate(ctx: dict, deny_doc: dict, schema: dict) -> str:
    if validate(ctx, schema):
        return "schema"
    entries = deny_doc.get("deniedMcpServers")
    if not isinstance(entries, list):
        return "schema"
    upstream = ctx.get("upstreamUrl", "")
    connector = ctx.get("connectorUrl", "")
    name = ctx.get("serverName", "")
    for entry in entries:
        if not isinstance(entry, dict):
            continue
        pat = entry.get("serverUrl")
        if isinstance(pat, str):
            if upstream and url_match(upstream, pat):
                return "deny_by_url"
            if connector and url_match(connector, pat):
                return "deny_by_connector_url"
        rule_name = entry.get("serverName")
        if isinstance(rule_name, str) and rule_name and rule_name == name:
            return "deny_by_name"
    return "allow"

Wie validiert man managed settings, Session-Metadaten und Audit-Logs in JSONNote

  1. 1
    Deny-Listen-Form per Schema fixieren

    Öffnen Sie JSON Schema. deniedMcpServers-Schema ins erste Feld, serverUrl und serverName ins zweite. required oder Typ zuerst; bei schlechter Form kein deny_by_url oder allow.

  2. 2
    Format für MCP tool calls

    Öffnen Sie JSON formatieren, MCP tool call JSON einfügen. tool und arguments prüfen, dann deny_by_url oder allow für mcp_url_deny_gate.

  3. 3
    Diff: allow vs denied Audit-Logs

    Öffnen Sie JSON Diff. Links CALL_OUTSIDE allow, rechts decision denied und reason mcp_server_denied. Hervorgehobenes matchedPattern ist die SIEM-Schlüsselzeile.

Häufige Fragen

Worin unterscheiden sich serverUrl-Regeln vom alten nur user-konfiguriert?

Früher traf serverUrl vor allem user-konfiguriertes HTTP MCP. Ab 2.1.318 auch upstreamUrl bei Anthropic-gehostetem MCP plus connectorUrl dann serverName.

Wie unterscheiden Logs deny_by_url und deny_by_connector_url?

deny_by_url: matchedRule serverUrl, upstreamUrl passt. deny_by_connector_url: connectorUrl trifft, upstream evtl. nicht, connectorUrl und sessionSurface behalten.

Was wird zuerst geprüft, serverName oder serverUrl?

mcp_url_deny_gate prüft serverUrl zuerst: upstreamUrl→deny_by_url, connectorUrl→deny_by_connector_url, dann serverName→deny_by_name. Keine URL-Globs in serverName.

Wie hängt URL deny mit serverCommand env-only deny zusammen?

serverCommand für stdio und env-Platzhalter ersetzt kein serverUrl-upstream-Deny. JSON getrennt; mcp_url_deny_gate nur URL und serverName.

Enthält dieser Artikel Angriffs- oder Bypass-Tutorials?

Nein. Der Artikel erklärt nur JSON-Formen der deniedMcpServers URL-Erweiterung 2.1.318, mcp_server_denied Audit-Felder und fünf mcp_url_deny_gate-Zweige. Keine Bypass-Schritte via URL oder connector.

Fazit

Claude Code 2.1.318 erweitert deniedMcpServers URL-Matching und schreibt decision denied, reason mcp_server_denied, matchedRule, matchedPattern, upstreamUrl ins Audit-JSON. mcp_url_deny_gate mit managed settings, Metadaten, MCP-Aufrufen und denied Audit füttern.

Entscheidung: Metadaten-JSON scheitert schema → schema; upstreamUrl trifft serverUrl → deny_by_url; connectorUrl trifft serverUrl → deny_by_connector_url; serverName → deny_by_name; kein Treffer → allow; deny Audit wie decision denied, reason mcp_server_denied, matchedRule, matchedPattern, upstreamUrl.

Als Nächstes: deniedMcpServers und Metadaten per Schema, Format für MCP-Aufrufe, Diff allow vs denied Audit-Logs, deny_by_url, deny_by_connector_url, deny_by_name und allow getrennt berichten.

Zurück zum Blog