<?xml version="1.0" encoding="UTF-8"?>
<!-- xml2rfc v3  -->
<rfc category="std" docName="draft-zw-opsawg-mcp-network-mgmt-00"
     ipr="trust200902" submissionType="IETF" consensus="true"
     xml:lang="en" version="3" xmlns:xi="http://www.w3.org/2001/XInclude">

  <front>
    <title abbrev="MCP-NET">
      Model Context Protocol (MCP) Extensions for Network Equipment Management
    </title>

    <author fullname="Zeng Guanming" initials="G." surname="Zeng">
      <organization>Huawei</organization>
      <address><email>zengguanming@huawei.com</email></address>
    </author>
    <author fullname="Jianwei Mao" initials="J." surname="Mao">
      <organization>Huawei</organization>
      <address><email>maojianwei@huawei.com</email></address>
    </author>
    <author fullname="Bing Liu" initials="B." surname="Liu">
      <organization>Huawei</organization>
      <address><email>leo.liubing@huawei.com</email></address>
    </author>
    <author fullname="Xiaotong Shang" initials="X." surname="Shang">
      <organization>Huawei</organization>
      <address><email>shangxiaotong@huawei.com</email></address>
    </author>
    <author fullname="Qiangzhou Gao" initials="Q." surname="Gao">
      <organization>Huawei</organization>
      <address><email>gaoqiangzhou@huawei.com</email></address>
    </author>
    <author fullname="Zhenbin Li" initials="Z." surname="Li">
      <organization>Huawei</organization>
      <address><email>robinli314@163.com</email></address>
    </author>
    <author fullname="Wu Qin" initials="Q." surname="Wu">
      <organization>Huawei</organization>
      <address><email>bill.wu@huawei.com</email></address>
    </author>

    <date year="2025"/>

    <abstract>
      <t>The Model Context Protocol (MCP) provides a JSON-RPC 2.0 framework
      for interaction between AI applications and external context sources.
      This document specifies minimal extensions that allow network equipment
      (routers, switches, etc.) to act as MCP servers while controllers act
      as MCP clients.  New capability tokens, tools, resources, prompts,
      and error codes are defined without breaking existing MCP
      implementations.</t>
    </abstract>
  </front>

  <middle>
    <section anchor="intro">
      <name>Introduction</name>
      <t>Network controllers today need to speak CLI, YANG/NETCONF, SNMP,
      gNMI, and vendor-private APIs.  Implementing a separate adapter for
      each protocol is expensive and error-prone.</t>

      <t>The Model Context Protocol (MCP) already defines a JSON-RPC 2.0
      based framing, capability negotiation, and extensible tool/resource
      model.  By adding a small set of network-specific capability flags
      and tool names, a device can expose its CLI, YANG datastores, and
      event streams through the same MCP channel that AI applications use
      for retrieving context.</t>

      <t>This document specifies those extensions.  All new elements live
      in their own capability namespace and can be ignored by generic MCP
      clients, preserving backward compatibility.</t>

      <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
      "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY",
      and "OPTIONAL" in this document are to be interpreted as described
      in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when,
      and only when, they appear in all capitals, as shown here.</t>
    </section>

    <section anchor="term">
      <name>Terminology</name>
      <t>MCP        Model Context Protocol</t>
      <t>Server     MCP server running on the network device</t>
      <t>Client     MCP client running on the controller</t>
      <t>Datastore  Conventional YANG datastore (running, candidate, operational)</t>
    </section>

    <section anchor="cap">
      <name>Capability Advertisement</name>
      <t>Servers that implement this specification MUST include the following
      object inside serverCapabilities in the initialize response:</t>

      <figure>
        <sourcecode type="json"><![CDATA[
"network": {
  "yangModules": ["ietf-interfaces", "openconfig-interfaces"],
  "cliDialect": "huawei-vrp",
  "configDatastore": ["running", "candidate", "operational"],
  "notificationStream": ["syslog", "netconf-stream", "snmp-trap"],
  "maxBulkEdit": 1000,
  "supportsRollback": true,
  "rollbackTimeout": 300
}
        ]]></sourcecode>
      </figure>

      <section anchor="cap-rationale">
        <name>Rationale for Each Field</name>
        <t>yangModules: Lists YANG modules the server can serve.  Clients use
        this to decide whether to invoke network.yang.* tools or fall back
        to CLI.</t>

        <t>cliDialect: Identifies CLI syntax (cisco-iosxr, huawei-vrp, etc.).
        Controllers can adjust prompt regex and command sequences accordingly.</t>

        <t>configDatastore: Bit-mask hint—running = editable live config;
        candidate = two-phase commit; operational = read-only state DB.
        Avoids unnecessary NETCONF hello round-trips.</t>

        <t>notificationStream: Tells the client which async event streams
        the server can translate into MCP notifications.  Client can
        subscribe only to available types.</t>

        <t>maxBulkEdit: Device-level limit to avoid oversized edit-config
        requests.  Controllers can chunk large changes.</t>

        <t>supportsRollback / rollbackTimeout: Boolean plus numeric seconds.
        Lets client know a confirmed-commit can be rolled back automatically
        if not confirmed within the window.</t>
      </section>
    </section>

    <section anchor="tools">
      <name>Tools</name>
      <t>Seven new tool names are defined.  All reuse the standard MCP
      tools/call request and MUST be listed by tools/list.</t>

      <table anchor="tooltab">
    <thead>
      <tr>
        <th align="left">Name</th>
        <th align="left">Description</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>network.cli.exec</td>
        <td>Execute operational CLI show commands</td>
      </tr>
      <tr>
        <td>network.cli.configure</td>
        <td>Enter config mode and send commands</td>
      </tr>
      <tr>
        <td>network.yang.get</td>
        <td>Retrieve YANG data node</td>
      </tr>
      <tr>
        <td>network.yang.edit</td>
        <td>Edit candidate datastore</td>
      </tr>
      <tr>
        <td>network.commit</td>
        <td>Commit candidate to running</td>
      </tr>
      <tr>
        <td>network.rollback</td>
        <td>Rollback to previous commit</td>
      </tr>
      <tr>
        <td>network.file.pull</td>
        <td>Backup config file</td>
      </tr>
      <tr>
        <td>network.file.push</td>
        <td>Restore config file</td>
      </tr>
    </tbody>
  </table>

      <t>Arguments are described by JSON Schema inside tool metadata, so SDKs
      can auto-generate bindings.  If a device only supports CLI, it
      advertises network.yang.* tools with available=false; controllers
      automatically downgrade.</t>
    </section>

    <section anchor="res">
  <name>Resources</name>

  <t>Network equipment exposes configuration, operational and file data
  as MCP resources under the URI scheme <tt>network:///</tt>.
  All resources described below are read-only unless explicitly
  marked "read-write".</t>

  <t>Servers MUST support <tt>resources/read</tt> and SHOULD support
  <tt>resources/subscribe</tt> for streaming resources.
  Large responses MAY be paginated using the standard MCP
  <tt>nextCursor</tt> mechanism.</t>

  <section anchor="res-uri">
    <name>Standard URI Templates and MIME Types</name>

    <table anchor="res-tab">
      <thead>
        <tr>
          <th align="left">URI Template</th>
          <th align="left">MIME Type</th>
          <th align="left">Access</th>
          <th align="left">Description</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><tt>network:///interface/{name}</tt></td>
          <td>application/yang-data+json</td>
          <td>read-only</td>
          <td>Single interface YANG node (OpenConfig or IETF)</td>
        </tr>
        <tr>
          <td><tt>network:///interfaces</tt></td>
          <td>application/yang-data+json</td>
          <td>read-only</td>
          <td>Full interface list; supports cursor pagination</td>
        </tr>
        <tr>
          <td><tt>network:///routing/ipv4/route-table</tt></td>
          <td>application/yang-data+json</td>
          <td>read-only</td>
          <td>IPv4 RIB (operational datastore)</td>
        </tr>
        <tr>
          <td><tt>network:///routing/ipv6/route-table</tt></td>
          <td>application/yang-data+json</td>
          <td>read-only</td>
          <td>IPv6 RIB (operational datastore)</td>
        </tr>
        <tr>
          <td><tt>network:///system/cpu-utilization</tt></td>
          <td>application/json</td>
          <td>read-only</td>
          <td>CPU percentage; updated every 30 s</td>
        </tr>
        <tr>
          <td><tt>network:///system/memory-summary</tt></td>
          <td>application/json</td>
          <td>read-only</td>
          <td>Memory usage summary</td>
        </tr>
        <tr>
          <td><tt>network:///log/syslog/last{count}</tt></td>
          <td>text/plain; charset=utf-8</td>
          <td>read-only</td>
          <td>Most recent syslog lines (max 10000)</td>
        </tr>
        <tr>
          <td><tt>network:///file/running-config</tt></td>
          <td>text/plain</td>
          <td>read-only</td>
          <td>Running configuration text</td>
        </tr>
        <tr>
          <td><tt>network:///file/startup-config</tt></td>
          <td>text/plain</td>
          <td>read-only</td>
          <td>Startup configuration text</td>
        </tr>
        <tr>
          <td><tt>network:///file/{slot}/crashinfo</tt></td>
          <td>application/json</td>
          <td>read-only</td>
          <td>Crash information file (JSON array)</td>
        </tr>
      </tbody>
    </table>
  </section>

  <section anchor="res-sub">
    <name>Subscription and Pagination</name>

    <t>Resources that change over time (CPU, memory, syslog, interface
    counters) SHOULD implement <tt>resources/subscribe</tt>.  The server
    sends unsolicited <tt>resources/updated</tt> notifications when the
    underlying data changes.</t>

    <t>For large lists (e.g., full IPv4 RIB) the server MAY insert
    <tt>nextCursor</tt> in the response:</t>

    <sourcecode type="json"><![CDATA[
{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "contents": [
      {
        "uri": "network:///routing/ipv4/route-table",
        "mimeType": "application/yang-data+json",
        "data": { "ietf-routing:routes": [ … 1000 items … ] }
      }
    ],
    "nextCursor": "eyJzb3J0LWtleSI6IjEwLjAuMC4xLzI0In0="
  }
}
    ]]></sourcecode>

    <t>The client continues with:</t>
    <sourcecode type="json"><![CDATA[
{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "resources/read",
  "params": {
    "uri": "network:///routing/ipv4/route-table",
    "cursor": "eyJzb3J0LWtleSI6IjEwLjAuMC4xLzI0In0="
  }
}
    ]]></sourcecode>
    <t>until <tt>nextCursor</tt> is absent.</t>
  </section>

  <section anchor="res-write">
    <name>Read-Write Resources (Optional)</name>

    <t>If the device supports whole-config replace, the following URIs
    MAY be advertised with <tt>readOnly: false</tt>:</t>

    <ul spacing="normal">
      <li><tt>network:///file/candidate-config</tt>  (text/plain)</li>
      <li><tt>network:///file/startup-config</tt>   (text/plain)</li>
    </ul>

    <t>Writing is done via the standard MCP <tt>resources/write</tt>
    method; the server MUST validate syntax before committing to
    candidate/running.</t>
  </section>

  <section anchor="res-meta">
    <name>Per-Resource Metadata</name>

    <t>Each resource descriptor MAY include a <tt>_meta</tt> object
    (MCP reserved) to carry unit, precision, or hardware-specific
    attributes, e.g.:</t>

    <sourcecode type="json"><![CDATA[
"_meta": {
  "unit": "percent",
  "precision": 0.1,
  "hardware-slot": "1/0"
}
    ]]></sourcecode>
  </section>
</section>

<section anchor="prompts">
  <name>Prompts</name>

  <t>Interactive assistants (e.g., CLI copilot, chat-bot) MAY expose
  prompt templates whose names start with <tt>network.</tt>.
  Templates are listed by <tt>prompts/list</tt> and executed via
  <tt>prompts/get</tt>; both reuse the standard MCP prompt meta-data
  and JSON Schema for arguments.</t>

  <t>Each entry below includes:</t>
  <ul spacing="normal">
    <li>template name (prompts/list)</li>
    <li>one-line description</li>
    <li>input JSON Schema</li>
    <li>expected tool calls / steps</li>
    <li>return MIME type (text/markdown by default)</li>
  </ul>

  <section anchor="prompt-list">
    <name>Standard Prompt Templates</name>

    <table anchor="prompt-tab">
      <thead>
        <tr>
          <th align="left">Template Name</th>
          <th align="left">Description</th>
          <th align="left">Input Schema</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><tt>network.troubleshoot.ping-fail</tt></td>
          <td>Step-by-step ping failure diagnosis</td>
          <td><tt>{src: string, dst: string, vrf?: string}</tt></td>
        </tr>
        <tr>
          <td><tt>network.config.add-vlan</tt></td>
          <td>Interactive VLAN creation wizard</td>
          <td><tt>{vlan_id: uint16, name: string, ports?: string[]}</tt></td>
        </tr>
        <tr>
          <td><tt>network.security.audit</tt></td>
          <td>Generate and run security compliance checks</td>
          <td><tt>{profile: "basic"|"detailed"}</tt></td>
        </tr>
      </tbody>
    </table>
  </section>

  <section anchor="prompt-example">
    <name>Example: Ping-Failure Diagnosis Flow</name>

    <t>The client calls <tt>prompts/get</tt>:</t>
    <sourcecode type="json"><![CDATA[
{
  "jsonrpc": "2.0",
  "id": 10,
  "method": "prompts/get",
  "params": {
    "name": "network.troubleshoot.ping-fail",
    "arguments": {
      "src": "192.168.1.1",
      "dst": "10.0.0.5",
      "vrf": "mgmt"
    }
  }
}
    ]]></sourcecode>

    <t>Server returns a markdown prompt that embeds tool calls:</t>
    <sourcecode type="markdown"><![CDATA[
## Ping failure diagnosis: 192.168.1.1 → 10.0.0.5 (VRF mgmt)

1. Check local ARP entry:
   `network.cli.exec {"cmd": "show ip arp vrf mgmt 10.0.0.5"}`

2. Verify outbound interface status:
   `network.yang.get {"path": "/openconfig-interfaces:interfaces/interface[name='Vlan100']", "datastore": "operational"}`

3. Run extended ping:
   `network.cli.exec {"cmd": "ping vrf mgmt 10.0.0.5 source 192.168.1.1 repeat 5"}`

... (interactive steps continue) ...
    ]]></sourcecode>

    <t>The client MAY stream the markdown to the user and **inline-execute**
    each tool call, then feed results back into the same prompt context
    (follow-up <tt>prompts/get</tt> with <tt>previousContextId</tt>) until
    the template outputs "Diagnosis complete".</t>
  </section>

  <section anchor="prompt-meta">
    <name>Prompt Metadata and Completion</name>

    <t>Prompt descriptors returned by <tt>prompts/list</tt> MAY include:</t>
    <sourcecode type="json"><![CDATA[
{
  "name": "network.config.add-vlan",
  "description": "Interactive VLAN creation wizard",
  "arguments": [
    {
      "name": "vlan_id",
      "description": "IEEE 802.1Q VLAN ID",
      "type": "integer",
      "minimum": 1,
      "maximum": 4094
    },
    {
      "name": "name",
      "description": "VLAN name (no spaces)",
      "type": "string",
      "pattern": "^[A-Za-z0-9-_]+$"
    },
    {
      "name": "ports",
      "description": "List of interface names to add to VLAN",
      "type": "array",
      "items": { "type": "string" }
    }
  ],
  "required": ["vlan_id", "name"]
}
    ]]></sourcecode>

    <t>Controllers can therefore auto-generate UI forms or CLI wizards
    without hard-coding any vendor logic.</t>
  </section>

  <section anchor="prompt-stream">
    <name>Streaming and Human-in-the-Loop</name>

    <t>Templates MAY set <tt>"stream": true</tt> in their meta-data.
    In this mode the server returns a <tt>prompts/stream</tt> handle
    and pushes incremental markdown + tool calls, allowing
    step-by-step confirmation by the user.</t>

    <t>When the template issues a <tt>network.commit</tt> step it
    MUST include a confirmation prompt; the client SHALL wait for
    explicit user approval before invoking the commit tool.</t>
  </section>
</section>

<section anchor="err">
  <name>Error Codes</name>

  <t>This document registers six new JSON-RPC application-specific
  error codes in the range -32081 to -32086.  Servers that implement
  optional features MAY return additional codes -32087 to -32090
  defined below.  All codes point to this document as reference.</t>

  <section anchor="err-table">
    <name>Error Code Table</name>

    <table anchor="errtab">
      <thead>
        <tr>
          <th align="right">Code</th>
          <th align="left">Message</th>
          <th align="left">Typical Scenario</th>
          <th align="left">Recommended Recovery</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td align="right">-32081</td>
          <td>Network.Timeout</td>
          <td>CLI or NETCONF RPC exceeded device timeout</td>
          <td>Retry with shorter command or increase timeout</td>
        </tr>
        <tr>
          <td align="right">-32082</td>
          <td>Network.Unreachable</td>
          <td>Transport session (SSH/TLS) down</td>
          <td>Check IP reachability, credentials, routing</td>
        </tr>
        <tr>
          <td align="right">-32083</td>
          <td>Network.AccessDenied</td>
          <td>User role lacks permission for command/path</td>
          <td>Escalate role or use lower-privilege account</td>
        </tr>
        <tr>
          <td align="right">-32084</td>
          <td>Network.ConfigIncompatible</td>
          <td>Command/YANG node not supported on this platform</td>
          <td>Fall back to alternate model or CLI dialect</td>
        </tr>
        <tr>
          <td align="right">-32085</td>
          <td>Network.RollbackFailed</td>
          <td>Confirmed-commit rollback could not be applied</td>
          <td>Manual intervention required; check logs</td>
        </tr>
        <tr>
          <td align="right">-32086</td>
          <td>Network.ConfirmedCommitTimeout</td>
          <td>Confirmed commit window expired; config auto-rolled back</td>
          <td>Re-apply change with longer timer or fix root cause</td>
        </tr>
        <tr>
          <td align="right">-32087</td>
          <td>Network.RollbackNotSupported</td>
          <td>Device does not support rollback operation</td>
          <td>Skip rollback step or use file-based restore</td>
        </tr>
        <tr>
          <td align="right">-32088</td>
          <td>Network.YangSyntaxError</td>
          <td>YANG payload failed server-side validation</td>
          <td>Fix offending node and re-submit</td>
        </tr>
        <tr>
          <td align="right">-32089</td>
          <td>Network.HardwareFailure</td>
          <td>Hardware resource exhausted (TCAM, memory)</td>
          <td>Reduce scale or upgrade hardware</td>
        </tr>
        <tr>
          <td align="right">-32090</td>
          <td>Network.SnmpFailure</td>
          <td>SNMP SET returned error-status ≠ noError</td>
          <td>Map error-status to text and retry with correct value</td>
        </tr>
      </tbody>
    </table>
  </section>

  <section anchor="err-example">
    <name>Example Error Response</name>

    <t>A device that rejects a VLAN because the ID is out of range would
    return:</t>

    <sourcecode type="json"><![CDATA[
{
  "jsonrpc": "2.0",
  "id": 12,
  "error": {
    "code": -32084,
    "message": "Network.ConfigIncompatible",
    "data": {
      "detail": "VLAN 4095 > maximum 4094",
      "path": "/openconfig-vlan:vlans/vlan/config/vlan-id",
      "retryPossible": false
    }
  }
}
    ]]></sourcecode>

    <t>The <tt>data</tt> object is optional but SHOULD contain
    <tt>detail</tt> (human-readable), <tt>path</tt> (affected YANG path),
    and <tt>retryPossible</tt> boolean to help controllers decide
    whether to retry automatically.</t>
  </section>

  <section anchor="err-iana">
    <name>IANA Registration</name>

    <t>This document requests IANA to register the following error codes
    in the "JSON-RPC Application-Specific Error Codes" registry:</t>

    <ul spacing="normal">
      <li>-32081 to -32086 (mandatory set)</li>
      <li>-32087 to -32090 (optional set)</li>
    </ul>

    <t>All codes reference this document and are reserved for network
    equipment implementing MCP.</t>
  </section>
</section>

    <!-- <section anchor="res">
      <name>Resources</name>
      <t>Network state is exposed as read-only resources with URI scheme
      <tt>network:///</tt>.  Examples:</t>
      <sourcecode type="text"><![CDATA[
network:///interface/TenGigE0/0/0/0
network:///routing/ipv4/route-table
network:///file/startup-config
      ]]></sourcecode>
      <t>MIME type MUST match the encoding (application/yang-data+json,
      text/plain, etc.).  Large data can be paginated using the native
      MCP resource/subscribe cursor mechanism.</t>
    </section>

    <section anchor="prompts">
      <name>Prompts</name>
      <t>Interactive assistants MAY expose prompt templates such as</t>
      <t><tt>network.troubleshoot.ping-fail</tt>,
      <tt>network.config.add-vlan</tt>, <tt>network.security.audit</tt>.</t>
      <t>Arguments are implementation specific but SHOULD use the same
      JSON Schema style as tools for consistency.</t>
    </section>

    <section anchor="err">
      <name>Error Codes</name>
      <t>New JSON-RPC error codes (registered in IANA section):</t>
      <table anchor="errtab">
    <thead>
      <tr>
        <th align="right">Code</th>
        <th align="left">Message</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td align="right">-32081</td>
        <td>Network.Timeout</td>
      </tr>
      <tr>
        <td align="right">-32082</td>
        <td>Network.Unreachable</td>
      </tr>
      <tr>
        <td align="right">-32083</td>
        <td>Network.AccessDenied</td>
      </tr>
      <tr>
        <td align="right">-32084</td>
        <td>Network.ConfigIncompatible</td>
      </tr>
      <tr>
        <td align="right">-32085</td>
        <td>Network.RollbackFailed</td>
      </tr>
      <tr>
        <td align="right">-32086</td>
        <td>Network.ConfirmedCommitTimeout</td>
      </tr>
    </tbody>
  </table>
      <t>These codes allow controllers to distinguish transport failures
      from authorization or device-level errors without parsing free-text
      messages.</t>
    </section> -->

    <!-- 放在 <back> 之前，章节号顺延为第 8 章 -->
<section anchor="ex">
  <name>Complete Interaction Example (Controller → Router)</name>

  <t>This example walks through a full MCP session between a controller
  (client) and a router (server).  Transport is TLS-over-TCP; frames
  are sent as length-prefixed JSON-RPC 2.0 objects per MCP spec.</t>

  <section anchor="ex-connect">
    <name>Transport and Initialize</name>
    <t>Controller opens <tt>TCP 443</tt> and performs TLS handshake
    with ALPN protocol <tt>mcp</tt>.  Then sends:</t>
    <sourcecode type="json"><![CDATA[
-> {"jsonrpc":"2.0","id":1,"method":"initialize","params":{
     "protocolVersion":"2025-06-18",
     "capabilities":{
       "prompts":{"listChanged":true},
       "resources":{"subscribe":true},
       "tools":{"listChanged":true}
     },
     "clientInfo":{"name":"ACME-NetCtrl","version":"4.7.0"}
   }}
    ]]></sourcecode>
    <t>Router replies:</t>
    <sourcecode type="json"><![CDATA[
<- {"jsonrpc":"2.0","id":1,"result":{
     "protocolVersion":"2025-06-18",
     "capabilities":{
       "prompts":{"listChanged":false},
       "resources":{"subscribe":true},
       "tools":{"listChanged":false},
       "network":{
         "yangModules":["ietf-interfaces","openconfig-interfaces"],
         "cliDialect":"huawei-vrp",
         "configDatastore":["running","candidate","operational"],
         "notificationStream":["syslog","netconf-stream"],
         "maxBulkEdit":1000,
         "supportsRollback":true,
         "rollbackTimeout":300
       }
     },
     "serverInfo":{"name":"IOS-XR-MCP","version":"7.5.3"}
   }}
    ]]></sourcecode>
  </section>

  <section anchor="ex-resource">
    <name>Read Resource (Interface Status)</name>
    <t>Controller fetches operational data:</t>
    <sourcecode type="json"><![CDATA[
-> {"jsonrpc":"2.0","id":2,"method":"resources/read","params":{
     "uri":"network:///interface/TenGigE0/0/0/0"}}
<- {"jsonrpc":"2.0","id":2,"result":{
     "contents":[{
       "uri":"network:///interface/TenGigE0/0/0/0",
       "mimeType":"application/yang-data+json",
       "data":{
         "openconfig-interfaces:interface":{
           "name":"TenGigE0/0/0/0",
           "state":{"admin-status":"UP","oper-status":"DOWN"}
         }
       }
     }]
   }}
    ]]></sourcecode>
  </section>

  <section anchor="ex-prompt">
    <name>Prompt Diagnosis (Ping Failure)</name>
    <t>Controller invokes the standardized prompt:</t>
    <sourcecode type="json"><![CDATA[
-> {"jsonrpc":"2.0","id":3,"method":"prompts/get","params":{
     "name":"network.troubleshoot.ping-fail",
     "arguments":{"src":"192.168.1.1","dst":"10.0.0.5","vrf":"mgmt"}}}
<- {"jsonrpc":"2.0","id":3,"result":{
     "description":"Step-by-step ping failure diagnosis",
     "messages":[{
       "role":"assistant",
       "content":"## Ping failure: 192.168.1.1 → 10.0.0.5 (VRF mgmt)\n\n1. Check local ARP:\n   `network.cli.exec {\"cmd\":\"show ip arp vrf mgmt 10.0.0.5\"}`"
     }],
     "_meta":{"toolCalls":[{"tool":"network.cli.exec","arguments":{"cmd":"show ip arp vrf mgmt 10.0.0.5"}}]}
   }}
    ]]></sourcecode>
    <t>Client executes the embedded tool and sends follow-up:</t>
    <sourcecode type="json"><![CDATA[
-> {"jsonrpc":"2.0","id":4,"method":"tools/call","params":{
     "name":"network.cli.exec","arguments":{"cmd":"show ip arp vrf mgmt 10.0.0.5"}}}
<- {"jsonrpc":"2.0","id":4,"result":{"stdout":"10.0.0.5  00:50:56:ab:cd:ef  Vlan100"}}
    ]]></sourcecode>
    <t>Prompt continues until root cause is found and printed to user.</t>
  </section>

  <section anchor="ex-edit">
    <name>YANG Edit + Confirmed Commit</name>
    <t>Controller adds a loopback interface:</t>
    <sourcecode type="json"><![CDATA[
-> {"jsonrpc":"2.0","id":5,"method":"tools/call","params":{
     "name":"network.yang.edit","arguments":{
       "target":"candidate",
       "edit":[{
         "path":"/openconfig-interfaces:interfaces/interface[name='Loopback100']",
         "value":{
           "config":{"name":"Loopback100","type":"iana-if-type:softwareLoopback"},
           "subinterfaces":{"subinterface":[{"index":0,"config":{"index":0,"ipv4":{"addresses":{"address":[{"ip":"100.100.100.100","config":{"ip":"100.100.100.100","prefix-length":32}}]}}}}]}
         }
       }]
     }
   }}
<- {"jsonrpc":"2.0","id":5,"result":{"commit-id":"2025-10-19-03-27-00"}}
    ]]></sourcecode>

    <t>Confirmed commit with 120 s rollback window:</t>
    <sourcecode type="json"><![CDATA[
-> {"jsonrpc":"2.0","id":6,"method":"tools/call","params":{
     "name":"network.commit","arguments":{"confirmed":120}}}
<- {"jsonrpc":"2.0","id":6,"result":{"status":"committed","rollbackTimeout":120}}
    ]]></sourcecode>

    <t>Controller verifies connectivity; if OK it sends final confirm:</t>
    <sourcecode type="json"><![CDATA[
-> {"jsonrpc":"2.0","id":7,"method":"tools/call","params":{
     "name":"network.commit","arguments":{"confirm":true}}}
<- {"jsonrpc":"2.0","id":7,"result":{"status":"confirmed"}}
    ]]></sourcecode>
  </section>

  <section anchor="ex-notify">
    <name>Event Stream (Syslog)</name>
    <t>Controller subscribes to syslog stream:</t>
    <sourcecode type="json"><![CDATA[
-> {"jsonrpc":"2.0","id":8,"method":"resources/subscribe","params":{
     "uri":"network:///log/syslog/last200"}}
<- {"jsonrpc":"2.0","id":8,"result":{"subscriptionId":"syslog-42"}}
    ]]></sourcecode>
    <t>Server later pushes:</t>
    <sourcecode type="json"><![CDATA[
<- {"jsonrpc":"2.0","method":"resources/updated","params":{
     "subscriptionId":"syslog-42",
     "uri":"network:///log/syslog/last200",
     "contents":[{
       "mimeType":"text/plain",
       "data":"Oct 19 03:29:01.123: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback100, changed state to up\n"
     }]
   }}
    ]]></sourcecode>
  </section>

  <section anchor="ex-close">
    <name>Graceful Shutdown</name>
    <t>Controller unsubscribes and closes the session:</t>
    <sourcecode type="json"><![CDATA[
-> {"jsonrpc":"2.0","id":9,"method":"resources/unsubscribe","params":{
     "subscriptionId":"syslog-42"}}
<- {"jsonrpc":"2.0","id":9,"result":{}}

-> {"jsonrpc":"2.0","id":10,"method":"close"}
<- {"jsonrpc":"2.0","id":10,"result":{}}
    ]]></sourcecode>
    <t>TCP connection is closed by controller.</t>
  </section>
</section>

    <section anchor="sec">
      <name>Security Considerations</name>
      <t>All operations run with the privileges of the authenticated MCP
      session.  Servers MUST enforce role-based access control for
      configuration commands.  Commit confirmed SHOULD be used for
      potentially disruptive changes.  Transport security is provided by
      the underlying MCP transport (TLS for HTTP, SSH port-forward for
      stdio).  Sensitive data (passwords, SNMP communities) MUST be
      redacted in logs and MCP traces.</t>
    </section>

    <section anchor="iana">
      <name>IANA Considerations</name>

      <section anchor="iana-cap">
        <name>MCP Capability Tokens Registry</name>
        <t>IANA is requested to register the following value:</t>
        <ul spacing="normal">
          <li>Token: network</li>
          <li>Description: Network equipment extensions for MCP</li>
          <li>Reference: this document</li>
        </ul>
      </section>

      <section anchor="iana-err">
        <name>JSON-RPC Error Codes Registry</name>
        <t>IANA is requested to register the error codes -32081 to -32086
        in the "JSON-RPC Application-Specific Error Codes" registry,
        all pointing to this document.</t>
      </section>
    </section>
  </middle>

  <back>
    <references title="Normative References">
      <reference anchor="RFC2119">
        <front>
          <title>Key words for use in RFCs to Indicate Requirement Levels</title>
          <author initials="S." surname="Bradner" fullname="Scott Bradner">
            <organization>Harvard University</organization>
          </author>
          <date year="1997" month="March"/>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="2119"/>
      </reference>

      <reference anchor="RFC8174">
        <front>
          <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
          <author initials="B." surname="Leiba" fullname="Barry Leiba">
            <organization>Huawei Technologies</organization>
          </author>
          <date year="2017" month="May"/>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="8174"/>
      </reference>

      <reference anchor="RFC7950">
        <front>
          <title>The YANG 1.1 Data Modeling Language</title>
          <author initials="M." surname="Bjorklund" fullname="Martin Bjorklund">
            <organization>Tail-f Systems</organization>
          </author>
          <date year="2016" month="August"/>
        </front>
        <seriesInfo name="RFC" value="7950"/>
      </reference>

      <reference anchor="RFC8259">
        <front>
          <title>The JavaScript Object Notation (JSON) Data Interchange Format</title>
          <author initials="T." surname="Bray" fullname="Tim Bray">
            <organization>Textuality</organization>
          </author>
          <date year="2017" month="December"/>
        </front>
        <seriesInfo name="STD" value="90"/>
        <seriesInfo name="RFC" value="8259"/>
      </reference>
    </references>

    <references title="Informative References">
      <reference anchor="MCP">
        <front>
          <title>Model Context Protocol Specification 2025-06-18</title>
          <author><organization>Anthropic</organization></author>
          <date year="2025"/>
        </front>
        <seriesInfo name="URL" value="https://modelcontextprotocol.io/specification/2025-06-18/basic"/>
      </reference>
    </references>

    <section anchor="app-schema">
      <name>JSON Schema Examples</name>
      <t>Example tool metadata snippet (pretty printed):</t>
      <sourcecode type="json"><![CDATA[
{
  "name": "network.yang.get",
  "description": "Retrieve a YANG data node",
  "inputSchema": {
    "type": "object",
    "properties": {
      "path": { "type": "string" },
      "datastore": { "enum": ["running", "operational"] }
    },
    "required": ["path"]
  }
}
      ]]></sourcecode>
    </section>
  </back>
</rfc>