---
title: "Node and plugin outbound connections"
description: "Node and plugin outbound connections for cluster operators and plugin authors."
canonical_url: "https://docs.oz0.ai/concepts/outbound-connections/nodes-and-plugins"
---
# Node and plugin outbound connections

> Node and plugin outbound connections for cluster operators and plugin authors.

For: cluster operators and plugin authors.

## The node

<table>
<thead>
  <tr>
    <th>
      Host
    </th>
    
    <th>
      Why
    </th>
    
    <th>
      When
    </th>
    
    <th>
      Turn it off
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        github.com
      </code>
      
       (uv), <code>
        releases.astral.sh
      </code>
      
       (Python), <code>
        pypi.org
      </code>
      
       and <code>
        files.pythonhosted.org
      </code>
      
       (the runtime's packages), <code>
        nodejs.org
      </code>
      
       (Node.js)
    </td>
    
    <td>
      What a node installs before its runtime starts
    </td>
    
    <td>
      Only when the edge mirrors no toolchain, and the node lacks it. <code>
        make dist
      </code>
      
       and <code>
        make toolchain
      </code>
      
       build the mirror; with it, nodes download all of this from the edge
    </td>
    
    <td>
      Serve <code>
        dist/toolchain
      </code>
      
       from the edge, and run nodes with <code>
        oz0-node run --offline
      </code>
      
       (or <code>
        OZ0_NODE_OFFLINE=1
      </code>
      
      ) so they never fall back
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pypi.org
      </code>
      
      , <code>
        registry.npmjs.org
      </code>
      
      , or the index a plugin names
    </td>
    
    <td>
      A plugin's own packages, while it installs (uv, npm), and on a node with a release age, how old its lock's pins are
    </td>
    
    <td>
      When a plugin with Python or npm dependencies installs
    </td>
    
    <td>
      An offline node takes a plugin's Python packages from the edge's toolchain: add them with <code>
        oz0-node toolchain fetch --plugin &lt;folder>
      </code>
      
      . npm packages are not mirrored: an offline node still downloads them from <code>
        registry.npmjs.org
      </code>
      
      , so set <code>
        npm_config_registry
      </code>
      
       on the node to your mirror (and <code>
        UV_DEFAULT_INDEX
      </code>
      
       on a node that is not offline)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pypi.org
      </code>
      
       and <code>
        files.pythonhosted.org
      </code>
      
       (mlx-lm and the packages it needs)
    </td>
    
    <td>
      The node's own mlx-lm for the <a href="https://docs.oz0.ai/fleet/local-models-on-a-mac">
        MLX servers it starts
      </a>
      
      , from the lock built into the node: every package at its version and hash
    </td>
    
    <td>
      Only when <code>
        models.yaml
      </code>
      
       has a <code>
        kind: mlx
      </code>
      
       server whose <code>
        start:
      </code>
      
       begins with <code>
        mlx_lm.server
      </code>
      
       or <code>
        mlx.launch
      </code>
      
      , on macOS on Apple silicon, the first time the node runs one of this lock
    </td>
    
    <td>
      Mirror it on the edge (<code>
        oz0-node toolchain fetch --platform darwin/arm64 --mlx-lm
      </code>
      
      ) and run the node offline, or start an mlx-lm of your own by its absolute path
    </td>
  </tr>
  
  <tr>
    <td>
      The URLs in a harness's <code>
        binaries
      </code>
      
       (such as GitHub releases for OpenCode and goose)
    </td>
    
    <td>
      The harness program, checked against its SHA-256, over https only and to public addresses only, redirects included (at most five). Through an HTTP proxy the operator set (<code>
        HTTPS_PROXY
      </code>
      
      ), the node checks the addresses the name resolves to before it hands the request to the proxy, which resolves the name again: there the proxy's own rules decide where it connects
    </td>
    
    <td>
      When a plugin with such a harness installs
    </td>
    
    <td>
      Plugins without them. The edge does not mirror them: an offline node downloads them too
    </td>
  </tr>
  
  <tr>
    <td>
      A remote MCP server a plugin's <code>
        url:
      </code>
      
       tool names, or, for a remote tool on a connection whose host is a param, the host the connection was connected for
    </td>
    
    <td>
      The runtime is the remote server's client: it lists the server's tools when it starts and makes each call; a remote tool on a connection opens a session per call with that call's token, follows no redirect and reaches that origin only
    </td>
    
    <td>
      Only in a tenant with such a plugin installed (on a connection, once it is connected), when the runtime starts and when an agent calls the tool
    </td>
    
    <td>
      Uninstall the plugin, or a <a href="https://docs.oz0.ai/govern/kill-switches">
        kill switch
      </a>
      
       on the tool
    </td>
  </tr>
  
  <tr>
    <td>
      Your local model servers
    </td>
    
    <td>
      <code>
        local/&lt;model>
      </code>
      
       agents
    </td>
    
    <td>
      Only as listed in the node's <code>
        models.yaml
      </code>
    </td>
    
    <td>
      Leave it empty
    </td>
  </tr>
  
  <tr>
    <td>
      Whatever a tool calls
    </td>
    
    <td>
      A tool is a plugin's code
    </td>
    
    <td>
      When an agent calls it
    </td>
    
    <td>
      <a href="https://docs.oz0.ai/concepts/security/sandbox-tiers#sandboxes">
        Sandbox tier 1
      </a>
      
       denies every host not on the allowlist; the <a href="https://docs.oz0.ai/govern/tool-policy">
        tool policy
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      None from a microVM's monitor: smolvm runs in tier 1's empty network namespace, and its VMs have no network device; Apple's container may download its own kernel when the operator runs <code>
        container system start
      </code>
    </td>
    
    <td>
      A tool with <code>
        isolation: microvm
      </code>
      
       (<a href="https://docs.oz0.ai/fleet/sandbox-tier-2/microvms#microvms">
        microVMs
      </a>
      
      ); a Mac or Windows node fetches the Linux node binary for its VMs from its edge only
    </td>
    
    <td>
      Apple's downloads only when the operator installs and starts it
    </td>
    
    <td>
      <code>
        OZ0_MICROVM=off
      </code>
      
      , or do not install a microVM runtime
    </td>
  </tr>
  
  <tr>
    <td>
      The remote-sandbox service the node's operator configured: E2B Cloud (<code>
        api.e2b.app
      </code>
      
      , <code>
        sandbox.e2b.app
      </code>
      
      ), a self-hosted E2B or CubeSandbox, through ai.oz0/sandbox-e2b
    </td>
    
    <td>
      Creating, keeping alive, listing and destroying remote sandboxes, and the MCP traffic of the tools that run in them; a tool's code and its calls' data go there (<a href="https://docs.oz0.ai/fleet/sandbox-tier-2/remote#remote-sandboxes">
        Sandbox tier 2
      </a>
      
      )
    </td>
    
    <td>
      Only with <code>
        run --remote-sandbox
      </code>
      
      : at the node's start (a list of its own sandboxes, which also checks the key) and while a tenant that allowed remote sandboxes runs a tool with <code>
        isolation: remote
      </code>
    </td>
    
    <td>
      Leave <code>
        --remote-sandbox
      </code>
      
       unset, or <code>
        oz0 tenant remote-sandbox &lt;tenant> deny
      </code>
    </td>
  </tr>
</tbody>
</table>

The node fetches its own new binaries and runtimes from the edge only, checked against the release key (see [Upgrades](https://docs.oz0.ai/fleet/upgrades)). The edge's mirror needs no signature of its own: the node checks uv and Node.js against the checksums in its binary, uv checks the Python build against the checksums in uv, and every package against the hashes in the runtime's `requirements.txt` or the plugin's lock.

The node's loopback proxy, which uv reaches the edge's Python builds and wheels through, answers any local process, so it forwards only the files `toolchain.json` lists, by their listed path, writes the wheels' index pages itself, follows no redirect, and reaches the edge without the node's certificate: what it can fetch is what the edge serves anyone.

On an offline node whose edge serves an [offline folder](https://docs.oz0.ai/fleet/offline-install), the proxy also forwards GET requests for the edge's PyPI and npm mirrors, which answer the cluster's nodes only, with the node's certificate: plain path segments only, no redirect followed, and nothing but those two routes.

The mirror counts a wheel as covering a platform only if nodes there can install it: no newer than glibc 2.28 on Linux (RHEL 8, Debian 10; the Node.js the node pins needs it too), musl 1.2 on Alpine, and macOS 11. A package with no such wheel for a platform is listed as missing in `toolchain.json`, and `toolchain fetch` warns about it: nodes there install it from a package index.

uv sends its version and the machine's platform (operating system, distribution, CPU, Python) in its User-Agent to the package index it downloads from, as pip does; PyPI publishes download statistics from it. Nodes that install from the edge send it to the edge only.

## The runtime on the node

The Python runtime reaches Temporal and the models through the node's local proxies, and sends its traces to the edge. Of its libraries:

- OpenAI Agents SDK: its tracing would send each run, prompts included, to OpenAI. It is off, in code and with `OPENAI_AGENTS_DISABLE_TRACING=1`.
- Pydantic AI: no banner (`PYDANTIC_AI_NO_BANNER=1`), no Logfire (only its no-op API is installed), and model prices from the copy it was released with: it never downloads a new list unless code asks it to.
- MCP servers over HTTP that a plugin names are called when an agent uses them.

## The official plugins

Each reaches only what its job needs, when an agent calls it. Its own code checks each connection against the hosts its manifest declares and the tenant's list. The node's egress proxy holds it to them too on every node with tier 1, whether the server is a job's or the plugin's own (`--plugin-sandbox strict`, the default). On a node with no tier 1, or one its operator runs with `--plugin-sandbox auto`, an installed plugin's servers keep the host's network, and the declared hosts are what the plugin's own code holds to:

<table>
<thead>
  <tr>
    <th>
      Plugin
    </th>
    
    <th>
      Host
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        ai.oz0/github
      </code>
      
      , <code>
        ai.oz0/pr-reviewer
      </code>
    </td>
    
    <td>
      <code>
        api.github.com
      </code>
      
      , or your GitHub Enterprise address
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ai.oz0/slack
      </code>
    </td>
    
    <td>
      <code>
        slack.com
      </code>
      
       (or <code>
        slack-gov.com
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ai.oz0/discord
      </code>
    </td>
    
    <td>
      <code>
        discord.com
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ai.oz0/teams
      </code>
    </td>
    
    <td>
      The Bot Framework's service for Teams (<code>
        smba.trafficmanager.net
      </code>
      
      , or your government cloud's), only at the <code>
        serviceUrl
      </code>
      
       a delivery's verified token names
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ai.oz0/web
      </code>
    </td>
    
    <td>
      The search backend the tenant chose (your SearXNG, or Brave's API) and the pages an agent fetches
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ai.oz0/servicenow
      </code>
    </td>
    
    <td>
      Your ServiceNow instance's host, which you give its connections, only once a tenant admin has connected it: the Table API when an agent calls it, the instance's token endpoint when the edge connects or renews the token, and, only when you turn it on, the instance's MCP Server Console; turn it off by removing the connection or the plugin
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ai.oz0/cve-triage
      </code>
    </td>
    
    <td>
      <code>
        api.osv.dev
      </code>
      
      , or none with an OSV mirror
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ai.oz0/net-diag
      </code>
    </td>
    
    <td>
      The hosts an agent is asked to diagnose
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ai.oz0/host-health
      </code>
    </td>
    
    <td>
      None
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        remote-claude-managed
      </code>
    </td>
    
    <td>
      <code>
        api.anthropic.com
      </code>
      
       (Managed Agents)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        harness-claude
      </code>
    </td>
    
    <td>
      None of its own: Claude Code runs with its telemetry, error reporting and update checks off, and its model calls go through the node's LLM proxy
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        harness-acp
      </code>
    </td>
    
    <td>
      None of its own for Codex (<code>
        check_for_update_on_startup
      </code>
      
       and analytics off), OpenCode (update checks, LSP downloads and the models.dev list off) and goose (telemetry off). Gemini CLI 0.62.0 sends usage statistics to Google unless its settings file turns them off, which no environment variable can do: in sandbox tier 1 that is denied, like every host not on the allowlist
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ai.oz0/a2a-remote
      </code>
      
      , <code>
        ai.oz0/a2a-agentcore
      </code>
      
      , <code>
        ai.oz0/a2a-foundry
      </code>
    </td>
    
    <td>
      None of their own. An <a href="https://docs.oz0.ai/build/apps/remote-agents/a2a#outside-a2a-agents">
        outside A2A agent
      </a>
      
      's card origin and token endpoint, which the plugin that defines the agent lists (AgentCore's <code>
        bedrock-agentcore.&lt;region>.amazonaws.com
      </code>
      
       and a Cognito endpoint, Foundry's <code>
        &lt;account>.services.ai.azure.com
      </code>
      
       and <code>
        login.microsoftonline.com
      </code>
      
      ), only while a job runs that agent; turn it off by removing the plugin that defines it, or with a kill switch on the agent
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ai.oz0/ai-spend
      </code>
    </td>
    
    <td>
      <code>
        api.anthropic.com
      </code>
      
       and <code>
        api.openai.com
      </code>
      
      , the providers' admin cost and usage APIs, only while a tenant has it installed with an admin key set and runs its import (its daily routine, or a person); turn it off by deleting the keys (<code>
        AI_SPEND_*_ADMIN_KEY
      </code>
      
      ), the routine, or the plugin
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ai.oz0/atlassian
      </code>
      
      , <code>
        ai.oz0/atlassian-dc
      </code>
    </td>
    
    <td>
      Cloud MCP calls and Data Center REST calls leave the node; authentication leaves the edge. See <a href="#atlassian-connection-traffic">
        destinations and switches
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ai.oz0/gitlab
      </code>
    </td>
    
    <td>
      MCP calls leave the node; OAuth sign-in and refresh use the browser and edge. See <a href="#gitlab-connection-traffic">
        destinations and switches
      </a>
      
      .
    </td>
  </tr>
</tbody>
</table>

### Atlassian connection traffic

Atlassian Cloud uses `mcp.atlassian.com` for Rovo MCP calls from the node, once to list tools at runtime startup and then for each call. Sign-in and token refresh use `auth.atlassian.com` from the edge.

Jira and Confluence Data Center use the connected instance's host. REST calls leave the node, while `/rest/oauth2/latest/token` is called by the edge.

These connections run only while the tenant has the plugin installed and connected. Remove the plugin or delete the connection to stop them, for example `oz0 connection delete atlassian-cloud`.

### GitLab connection traffic

GitLab traffic goes to the connected instance's host, `gitlab.com` unless the tenant selects its own. The node reaches `/api/v4/mcp` once to list tools at runtime startup and for each call. The person's browser and the edge use `/oauth/authorize` and `/oauth/token` for sign-in and refresh.

This traffic starts only after the tenant connects the `gitlab` connection. Stop it with `oz0 connection delete gitlab` or by removing the plugin. GitLab webhooks arrive at the edge; they are not outbound connections.


## Sitemap

See the full [sitemap](https://docs.oz0.ai/sitemap.md) for all pages.
