NICo MCP Server

View as Markdown

NICo MCP Server

nico-mcp exposes the read-only NICo REST API surface as Model Context Protocol (MCP) tools over streamable HTTP. It generates tools for the GET operations in the embedded OpenAPI specification and does not expose REST operations that create, update, or delete resources.

The server is stateless. It does not authenticate or authorize callers. NICo REST validates the bearer token and enforces organization and role permissions for every forwarded request.

Supported Deployment Topologies

Production: ClusterIP Alongside NICo REST

The supported production topology deploys nico-mcp in Kubernetes alongside NICo REST with the Helm chart at helm/rest/nico-mcp. By default, the chart creates a ClusterIP Service on port 8080 and serves MCP requests at /mcp.

Configure one fixed NICo REST base URL at startup. An in-cluster Service URL is the typical choice:

1config:
2 baseURL: http://nico-rest-api:8388
3 apiName: nico

The MCP listener is plaintext HTTP. Place an upstream service in front of it that provides all of the following controls:

  • Authenticates callers and passes each caller’s bearer token to nico-mcp
  • Terminates TLS for client connections
  • Routes MCP traffic to the nico-mcp ClusterIP Service
  • Restricts direct access to the MCP Service from untrusted networks

The chart does not deploy these controls. Use the ingress, gateway, proxy, and network-policy components approved for your environment.

Standalone Development and Testing

For development and testing, build and run the binary directly against a reachable NICo REST endpoint:

$cd rest-api
$make nico-mcp
$nico-mcp \
> --listen 127.0.0.1:8080 \
> --path /mcp \
> --base-url https://nico.example.com \
> --org example-org

Keep the listener on localhost or a trusted network. If it must be reachable from an untrusted network, put it behind the same authentication, TLS, routing, and network controls required for production.

Install the Helm Chart

Before installing the chart, make sure that:

  • The nico-mcp image is available to the cluster
  • NICo REST is reachable from the target namespace
  • The upstream authentication and TLS frontend is configured

Create a values file for the deployment:

1global:
2 image:
3 repository: registry.example.com/nico
4 tag: "2.0.0"
5 pullPolicy: IfNotPresent
6 imagePullSecrets:
7 - name: image-pull-secret
8
9config:
10 baseURL: http://nico-rest-api:8388
11 org: example-org
12 apiName: nico

Install the chart in the NICo REST namespace:

$helm upgrade --install nico-mcp helm/rest/nico-mcp \
> --namespace nico-rest \
> --create-namespace \
> --values nico-mcp-values.yaml

The rendered image is <global.image.repository>/<image.name>:<global.image.tag>. The chart does not create global.imagePullSecrets; create the referenced Secret before the Deployment starts when the registry requires authentication.

Chart Values

ValueDefaultPurpose
global.image.repositoryemptyImage registry and repository prefix. Required for deployment.
global.image.tagemptyImage tag. Required for deployment.
global.image.pullPolicyIfNotPresentKubernetes image pull policy.
global.imagePullSecrets[{name: image-pull-secret}]Existing image pull secrets attached to the pod (list of name objects).
replicaCount1Number of MCP server replicas.
nameOverrideemptyOverride for the Deployment and Service name.
namespaceOverrideemptyNamespace override; otherwise the Helm release namespace is used.
image.namenico-mcpImage name appended to the repository.
service.typeClusterIPKubernetes Service type. Keep ClusterIP for production.
service.port8080Listener and Service port.
config.path/mcpHTTP path for the MCP handler.
config.shutdownTimeout10sGraceful shutdown timeout.
config.baseURLemptyFixed default NICo REST URL. Set this in production.
config.orgemptyDefault organization for tool calls.
config.apiNameemptyREST API path segment; the binary defaults to nico.
config.debugfalseLog outbound NICo REST HTTP requests and responses.
resources.requests50m CPU, 64Mi memoryPod resource requests.
resources.limits250m CPU, 256Mi memoryPod resource limits.

Bearer tokens are intentionally not exposed as chart values. Shared production deployments should use the authenticated caller’s token instead of a static service token.

Runtime Configuration

The standalone binary accepts the following startup settings. When running the binary directly, a command-line flag takes its value from the corresponding environment variable when the flag is omitted.

FlagEnvironment variableDefaultHelm value
--listenNICO_MCP_LISTEN:8080service.port sets the port
--pathNICO_MCP_PATH/mcpconfig.path
--shutdown-timeoutNICO_MCP_SHUTDOWN_TIMEOUT10sconfig.shutdownTimeout
--base-urlNICO_BASE_URLnoneconfig.baseURL
--orgNICO_ORGnoneconfig.org
--api-nameNICO_API_NAMEnicoconfig.apiName
--tokenNICO_TOKENnoneNot exposed
--debugnonefalseconfig.debug

The Helm chart explicitly renders --listen, --path, and --shutdown-timeout from service.port, config.path, and config.shutdownTimeout. Those Helm values take precedence over the corresponding NICO_MCP_* environment variables.

nico-mcp does not read ~/.nico/config.yaml.

Every tool accepts optional base_url, org, api_name, and token arguments. Non-empty values are resolved for each call as follows:

SettingPrecedence, highest first
base_urlFixed startup --base-url or NICO_BASE_URL; a tool argument must match it (mismatch rejected). Without a startup value, the tool argument
orgTool argument, then startup --org or NICO_ORG
api_nameTool argument, then startup --api-name or NICO_API_NAME, then nico
tokenTool argument, inbound Authorization: Bearer header, then startup --token or NICO_TOKEN

When a startup base URL is configured, a tool argument can repeat that destination, with or without a trailing slash, but it cannot select a different one. When no startup base URL is configured, a tool call can supply base_url only with an explicit per-call token or with no resolved token. The server does not combine a caller-chosen destination with an inherited inbound or startup token.

base_url and org must resolve to non-empty values. A token can be empty, but NICo REST normally rejects the resulting unauthenticated request.

Security Requirements

Treat the REST destination and the bearer token as one trust decision:

  • Set a fixed startup base URL for every production deployment.
  • Use caller-specific bearer tokens on shared endpoints. NICo REST remains the authorization enforcement point.
  • A configured startup base URL pins the REST destination. A different per-call base_url is rejected, including when the call supplies an explicit token.
  • Without a startup base URL, a per-call base_url is allowed only when the call also supplies its own explicit token, or when the request resolves to no token. The server does not send an inherited inbound or startup credential to a caller-selected destination.
  • Do not configure NICO_TOKEN for a shared production deployment. It is a common credential used whenever a caller supplies no token. Limit any development use of a startup token to a trusted network and a fixed base URL.
  • Restrict network access even though NICo REST independently validates each token. The MCP endpoint provides a convenient read-only interface to every eligible REST GET operation.

Debug Logging

--debug and config.debug log the outbound NICo REST request and response. Sensitive header values, including Authorization, cookies, and API-key headers, are redacted. URLs, request bodies, and response bodies are not content-redacted.

NICo REST response bodies can contain inventory, configuration, and tenant data. Protect debug logs as sensitive operational data, enable debug logging only while diagnosing an issue, and disable it afterward.