Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion cmd/alb-mcp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ func main() {
buildinfo.SetVersion(version)

var addr string
var tlsOpts mcpserver.TLSOptions

flag.StringVar(&addr, "addr", mcpserver.EnvOr("ALB_MCP_ADDR", ":8080"),
"address to serve MCP on")
tlsOpts.BindFlags(flag.CommandLine, "ALB_MCP")

opts := zap.Options{}
opts.BindFlags(flag.CommandLine)
Expand Down Expand Up @@ -86,7 +88,7 @@ func main() {
}

setupLog.Info("listening", "addr", addr, "mcp", "/mcp", "docs", docs.Paths())
err = mcpserver.Serve(addr,
err = mcpserver.Serve(ctrl.SetupSignalHandler(), addr, tlsOpts,
&mcp.Implementation{Name: serverName, Version: serverVersion}, docs,
func(s *mcp.Server, r *http.Request) { agent.RegisterTools(s, depsFromRequest(r, baseConfig)) })
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion cmd/network-mcp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ func main() {
buildinfo.SetVersion(version)

var addr string
var tlsOpts mcpserver.TLSOptions

flag.StringVar(&addr, "addr", mcpserver.EnvOr("NETWORK_MCP_ADDR", ":8080"),
"address to serve MCP on")
tlsOpts.BindFlags(flag.CommandLine, "NETWORK_MCP")

opts := zap.Options{}
opts.BindFlags(flag.CommandLine)
Expand All @@ -75,7 +77,7 @@ func main() {
}

setupLog.Info("listening", "addr", addr, "mcp", "/mcp", "docs", docs.Paths())
err = mcpserver.Serve(addr,
err = mcpserver.Serve(ctrl.SetupSignalHandler(), addr, tlsOpts,
&mcp.Implementation{Name: serverName, Version: serverVersion}, docs,
func(s *mcp.Server, r *http.Request) { networkagent.RegisterTools(s, depsFromRequest(r, baseConfig)) })
if err != nil {
Expand Down
21 changes: 19 additions & 2 deletions config/components/alb-mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ and why.
| File | What it is |
| --- | --- |
| `service_account.yaml` | An intentionally unbound `ServiceAccount`. No `Role` or binding is ever attached to it — see the comments in that file for why. |
| `deployment.yaml` | Runs the `alb-mcp` binary from the operator's own image (`command: [/alb-mcp]`), exposing `/mcp`, `/llms-full.txt`, `/runbooks/*` and `/healthz` on port 8080. |
| `deployment.yaml` | Runs the `alb-mcp` binary from the operator's own image (`command: [/alb-mcp]`), exposing `/mcp`, `/llms-full.txt`, `/runbooks/*` and `/healthz` over HTTPS on port 8080. |
| `service.yaml` | A `ClusterIP` Service in front of the Deployment. Cluster-internal only; no Gateway or HTTPRoute fronts it. |

## Deployment
Expand All @@ -24,7 +24,24 @@ It is **not** applied by the operator's own deployment overlays. It is deployed
from the infra repo, alongside the assistant platform's capability document,
which names this Service's `/mcp`, `/llms-full.txt` and `/runbooks/` URLs.

Two things there have to move with it, and both fail silently if they do not:
## Transport

The server answers HTTPS only. The assistant refuses to send a caller's bearer
token to a plain `http://` endpoint, so the Deployment mounts a certificate from
the `datum-control-plane` ClusterIssuer through the cert-manager CSI driver and
passes it as `--tls-cert-file` and `--tls-key-file`. The binary re-reads the
files when the driver renews them, so a rotation needs no restart. Run without
both flags, as in local development, it serves plain HTTP.

The certificate names the Service as Datum deploys it:
`network-services-operator-alb-mcp` in `datum-system`. Kustomize rewrites the
Service's own name and namespace but not the volume attributes that name it, so
a deployment using a different `namePrefix` or namespace has to patch
`csi.cert-manager.io/common-name` and `csi.cert-manager.io/dns-names` to match,
along with the URLs in `../assistant-capability/service-agent-configuration.yaml`.

Two more things there have to move with it, and both fail silently if they do
not:

- The assistant forwards the calling user's bearer token only to hosts on an
allow-list. This Service's host has to be on it, without a port, or every tool
Expand Down
28 changes: 26 additions & 2 deletions config/components/alb-mcp/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ spec:
- /alb-mcp
args:
- --addr=:8080
- --tls-cert-file=/etc/alb-mcp/tls/tls.crt
- --tls-key-file=/etc/alb-mcp/tls/tls.key
ports:
- containerPort: 8080
name: http
Expand All @@ -73,18 +75,40 @@ spec:
httpGet:
path: /healthz
port: http
scheme: HTTP
scheme: HTTPS
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /healthz
port: http
scheme: HTTP
scheme: HTTPS
initialDelaySeconds: 5
periodSeconds: 10
volumeMounts:
- name: alb-mcp-certs
mountPath: /etc/alb-mcp/tls
readOnly: true
# No writable volume: the binary is static, the documents it serves are
# compiled in, and nothing here writes to disk.
volumes:
# The serving certificate. The assistant sends a caller's token only
# over HTTPS and already trusts this issuer.
#
# The names are the Service as deployed, prefix and namespace included:
# kustomize does not rewrite volume attributes, so a deployer using a
# different namePrefix or namespace has to patch them to match.
- name: alb-mcp-certs
csi:
driver: csi.cert-manager.io
readOnly: true
volumeAttributes:
csi.cert-manager.io/issuer-name: datum-control-plane
csi.cert-manager.io/issuer-kind: ClusterIssuer
csi.cert-manager.io/common-name: network-services-operator-alb-mcp
csi.cert-manager.io/dns-names: network-services-operator-alb-mcp,network-services-operator-alb-mcp.datum-system.svc,network-services-operator-alb-mcp.datum-system.svc.cluster.local
csi.cert-manager.io/key-usages: digital signature,key encipherment,server auth
csi.cert-manager.io/fs-group: '65532'
dnsPolicy: ClusterFirst
restartPolicy: Always
terminationGracePeriodSeconds: 30
5 changes: 3 additions & 2 deletions config/components/alb-mcp/service.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Cluster-internal only: the assistant reaches /mcp over this Service's DNS
# name, and no Gateway or HTTPRoute fronts it. The pod serves plain HTTP and the
# network layer owns transport security.
# name, and no Gateway or HTTPRoute fronts it. The pod serves HTTPS with a
# certificate issued for this name; the port keeps the name network policies
# and probes already select it by.
apiVersion: v1
kind: Service
metadata:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ spec:
sources:
- type: LLMDocs
title: Networks and network services, and how to read their status
url: http://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/llms-full.txt
url: https://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/llms-full.txt
concepts:
- gvk:
group: networking.datumapis.com
Expand All @@ -46,7 +46,7 @@ spec:
tools:
mcpServers:
- name: network
endpoint: http://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/mcp
endpoint: https://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/mcp
toolSelector:
include:
- network_list
Expand All @@ -60,25 +60,25 @@ spec:
skills:
- name: network-create
description: 'Create a network: the one or two choices there are, why IPv4 is not one, and render, plan, show, confirm, then apply'
source: http://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-create.md
source: https://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-create.md
- name: network-service-create
description: 'Create a network service for a workload: selecting its instances, naming ports, and render, plan, show, confirm, then apply'
source: http://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-service-create.md
source: https://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-service-create.md
- name: network-not-ready
description: A network that is not ready, from IPv6Required (the customer's) to address allocation failures (Datum's)
source: http://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-not-ready.md
source: https://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-not-ready.md
- name: network-location-triage
description: A network not reaching a location, or one location's instances waiting on it while others are fine
source: http://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-location-triage.md
source: https://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-location-triage.md
- name: network-interface-triage
description: An instance's network interface not addressed, an IPv4 request on an IPv6-only network, or a kept interface refusing a workload
source: http://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-interface-triage.md
source: https://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-interface-triage.md
- name: network-service-not-serving
description: A network service sending traffic nowhere, matching nothing, spanning two networks, or with no ready instances
source: http://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-service-not-serving.md
source: https://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-service-not-serving.md
- name: network-deletion-stuck
description: Deleting a network that does not finish because instances or kept interfaces still hold addresses in it
source: http://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-deletion-stuck.md
source: https://network-services-operator-network-mcp.datum-system.svc.cluster.local:8080/runbooks/network-deletion-stuck.md
authority:
reads:
- gvk:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ spec:
sources:
- type: LLMDocs
title: Application Load Balancer model and how to read its status
url: http://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/llms-full.txt
url: https://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/llms-full.txt
concepts:
- gvk:
group: networking.datumapis.com
Expand All @@ -53,7 +53,7 @@ spec:
tools:
mcpServers:
- name: alb
endpoint: http://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/mcp
endpoint: https://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/mcp
toolSelector:
include:
- alb_list
Expand All @@ -75,34 +75,34 @@ spec:
skills:
- name: alb-not-serving
description: Triage an Application Load Balancer that is not working, from symptom to root cause and who has to act
source: http://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/alb-not-serving.md
source: https://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/alb-not-serving.md
- name: hostname-not-working
description: Work a hostname that does not reach a load balancer through claim, ownership, DNS record and certificate, in the order each gates the next
source: http://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/hostname-not-working.md
source: https://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/hostname-not-working.md
- name: domain-verification
description: 'Prove ownership of a domain: the exact record to create, and why RecordNotFound is usually not a typo'
source: http://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/domain-verification.md
source: https://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/domain-verification.md
- name: dns-delegation
description: Decide whether Datum answers DNS for a domain or the customer does, and handle DNSAuthorityMissing and nameserver mismatches
source: http://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/dns-delegation.md
source: https://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/dns-delegation.md
- name: certificate-not-issued
description: Tell a certificate that is the cause from one that is a symptom of DNS that has not landed
source: http://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/certificate-not-issued.md
source: https://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/certificate-not-issued.md
- name: backend-not-reachable
description: 'Diagnose origins that cannot be reached: a missing network service or port name, a selector matching nothing, locations out of rotation'
source: http://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/backend-not-reachable.md
source: https://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/backend-not-reachable.md
- name: edge-propagation
description: Handle a load balancer that reports ready but is not serving, and know when that stops being propagation
source: http://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/edge-propagation.md
source: https://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/edge-propagation.md
- name: traffic-protection-triage
description: Traffic protection that is off, not attached, or blocking real traffic, and how to turn it on without breaking a live site
source: http://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/traffic-protection-triage.md
source: https://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/traffic-protection-triage.md
- name: access-log-triage
description: 'Read what actually arrived: response codes, response flags, and why no traffic is not a fault'
source: http://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/access-log-triage.md
source: https://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/access-log-triage.md
- name: alb-create
description: 'Create a load balancer: prerequisites, what is settled at create, and render, plan, show, confirm, then apply'
source: http://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/alb-create.md
source: https://network-services-operator-alb-mcp.datum-system.svc.cluster.local:8080/runbooks/alb-create.md
authority:
reads:
- gvk:
Expand Down
9 changes: 7 additions & 2 deletions config/components/network-mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ it publishes and why.
| File | What it is |
| --- | --- |
| `service_account.yaml` | An intentionally unbound `ServiceAccount`. No `Role` or binding is ever attached to it. |
| `deployment.yaml` | Runs the `network-mcp` binary from the operator's own image (`command: [/network-mcp]`), exposing `/mcp`, `/llms-full.txt`, `/runbooks/*` and `/healthz` on port 8080. |
| `deployment.yaml` | Runs the `network-mcp` binary from the operator's own image (`command: [/network-mcp]`), exposing `/mcp`, `/llms-full.txt`, `/runbooks/*` and `/healthz` over HTTPS on port 8080. |
| `service.yaml` | A `ClusterIP` Service in front of the Deployment. Cluster-internal only. |

## Deployment
Expand All @@ -24,8 +24,13 @@ Deployed the same way as `../alb-mcp`, and with the same three requirements:
forwarding allow-list, or every tool call arrives unauthenticated.
- Permit the assistant's namespace, and nothing else, to reach this pod.

It serves HTTPS only, for the reason and in the way `../alb-mcp` does: a
certificate from the `datum-control-plane` ClusterIssuer, mounted through the
cert-manager CSI driver and re-read on renewal.

It is not applied by the operator's own overlays. It is deployed from the infra
repo, alongside the capability registration in
`../assistant-capability/network-service-agent-configuration.yaml`, whose URLs
assume the Service is named `network-services-operator-network-mcp` in
`datum-system`.
`datum-system`. The certificate in `deployment.yaml` assumes the same name, so
a different `namePrefix` or namespace has to patch both.
28 changes: 26 additions & 2 deletions config/components/network-mcp/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ spec:
- /network-mcp
args:
- --addr=:8080
- --tls-cert-file=/etc/network-mcp/tls/tls.crt
- --tls-key-file=/etc/network-mcp/tls/tls.key
ports:
- containerPort: 8080
name: http
Expand All @@ -72,18 +74,40 @@ spec:
httpGet:
path: /healthz
port: http
scheme: HTTP
scheme: HTTPS
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /healthz
port: http
scheme: HTTP
scheme: HTTPS
initialDelaySeconds: 5
periodSeconds: 10
volumeMounts:
- name: network-mcp-certs
mountPath: /etc/network-mcp/tls
readOnly: true
# No writable volume: the binary is static, the documents it serves are
# compiled in, and nothing here writes to disk.
volumes:
# The serving certificate. The assistant sends a caller's token only
# over HTTPS and already trusts this issuer.
#
# The names are the Service as deployed, prefix and namespace included:
# kustomize does not rewrite volume attributes, so a deployer using a
# different namePrefix or namespace has to patch them to match.
- name: network-mcp-certs
csi:
driver: csi.cert-manager.io
readOnly: true
volumeAttributes:
csi.cert-manager.io/issuer-name: datum-control-plane
csi.cert-manager.io/issuer-kind: ClusterIssuer
csi.cert-manager.io/common-name: network-services-operator-network-mcp
csi.cert-manager.io/dns-names: network-services-operator-network-mcp,network-services-operator-network-mcp.datum-system.svc,network-services-operator-network-mcp.datum-system.svc.cluster.local
csi.cert-manager.io/key-usages: digital signature,key encipherment,server auth
csi.cert-manager.io/fs-group: '65532'
dnsPolicy: ClusterFirst
restartPolicy: Always
terminationGracePeriodSeconds: 30
5 changes: 3 additions & 2 deletions config/components/network-mcp/service.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Cluster-internal only: the assistant reaches /mcp over this Service's DNS
# name, and no Gateway or HTTPRoute fronts it. The pod serves plain HTTP and the
# network layer owns transport security.
# name, and no Gateway or HTTPRoute fronts it. The pod serves HTTPS with a
# certificate issued for this name; the port keeps the name network policies
# and probes already select it by.
apiVersion: v1
kind: Service
metadata:
Expand Down
Loading
Loading