Skip to content

MCP (Model Context Protocol)

norsk-ctl ships a full MCP server so an LLM-driven host (Claude Code, Claude Desktop, Cursor, etc.) can drive the same operations as the CLI and web UI — launch and inspect instances, configure the daemon, and (via a proxied Studio MCP) author workflows inside each running Studio instance.

There are two MCP surfaces, one connection:

  • Daemon-side tools — orchestration: launch/inspect/teardown instances, images, config.
  • Per-instance Studio tools — proxied under studio.<instanceId>.* for workflow authoring and dashboard design. They appear once the matching instance is running.
  • A running norsk-ctl daemon (norsk-ctl serve, or it’ll auto-spawn).
  • An MCP host. Claude Code is the reference target; any host that accepts a stdio MCP entry works.

The CLI carries the stdio bridge — norsk-ctl mcp proxies stdio to the daemon’s HTTP MCP endpoint at /mcp on the local loopback. Add this to your Claude Code MCP config:

{
"mcpServers": {
"norsk-ctl": {
"command": "norsk-ctl",
"args": ["mcp"]
}
}
}

The bridge auto-spawns the daemon if it isn’t already running (same discovery logic as every other CLI command). The /mcp endpoint bypasses proxy auth on the loopback interface so the local bridge doesn’t need credentials.

The live norsk://instructions resource is the canonical breakdown — fetch it from your MCP host (or read backend/src/mcp/instructions.md in the repo). High-level summary:

ToolPurpose
statusComposite read: daemon readiness, instance summary, proxy state, host hardware. Call this first
instance.list / instance.describeEnumerate / inspect instances
instance.launch / instance.restart / instance.relaunch / instance.deleteLifecycle
instance.switch_workflowSwap the active workflow YAML and restart Studio
instance.update_ingest_portsPatch ingest port assignments on a running instance
image.list / image.list_bakedLocal Norsk image inventory, filtered by the norsk-ctl.baked-plugins label for baked variants
working_directory.scaffold / working_directory.inspectScaffold the plugins / studio-save-files / dashboards skeleton; inspect enumerates the workflows and dashboards within
config.show / config.setRead / write ~/.norsk-ctl/config.yaml
sdk.stageStage a Studio SDK release into a working directory
studio.bootstrapRecipe: idempotent zero-to-ready (writes config if absent, pulls images, reports readiness)
workflow.create_and_applyRecipe: write a known YAML workflow + instance.switch_workflow
studio.<instanceId>.*Proxied Studio MCP — appears once an instance is running

Tool annotations follow the MCP spec: readOnlyHint on inspection tools, destructiveHint on relaunch/delete/restart/config.set, idempotentHint on restart and studio.bootstrap.

There are no daemon-side plugin tools — plugin scaffold/install/build lives on the Studio product’s HTTP API (/products/norsk-studio/api/plugins/*); see Manage plugins.

URIs are norsk://. Read them via your host’s resource UI; bodies are sized for direct context inclusion.

  • norsk://index — entry-point map
  • norsk://instructions — the live, canonical instructions document
  • norsk://openapi/index and norsk://openapi/endpoint/{method}/{path} — every REST endpoint
  • norsk://openapi/schema/{name} — every named schema
  • norsk://recipes/{topic} — curated recipes (launch, workflow, dashboard, working-directory, studio-mcp, sdk)
  • norsk://state/instances, norsk://state/config, norsk://state/working-directory — live state mirrors
  • norsk://studio/{instanceId}/{originalUri} — per-instance Studio resources, once an instance is up

Surfaced as /mcp__norsk-ctl__<name> in Claude Code. Each is a markdown brief that tells the model how to use the tools — they don’t call the tools themselves.

  • launch-studio — get a running Studio with a workflow loaded
  • new-workflow — author a workflow via the Studio MCP path
  • inspect-studio — guided read of an existing instance
  • extend-studio — end-to-end feature build (workflow + dashboard, with optional plugin steps that point at the Studio product’s /api/plugins endpoints)

docs.search is the discovery escape hatch — keyword search across recipes, OpenAPI summaries, named-schema descriptions, and the instructions doc. Returns { uri, snippet, score } so you can follow up with a targeted resources/read.

Each running Studio container exposes its own MCP server over HTTP. The norsk-ctl MCP server opens a client to each one as it comes up and re-registers its tools, resources, and prompts under a per-instance namespace.

  • Tools appear as studio.<instanceId>.<originalToolName> (e.g. studio.live-9100.workflow.list). Each carries [instance: <id>] in its description so the model picks the right one in multi-instance environments.
  • Resources appear as norsk://studio/<instanceId>/<originalUri>.
  • Prompts appear as studio.<instanceId>.<originalPromptName>.
  • notifications/tools/list_changed and notifications/resources/list_changed fire on instance up/down so the host’s tool list grows and shrinks without a reconnect.

Use the proxied tools whenever you’re authoring workflows or dashboards — the daemon side cannot author those for you.

  • Plugin changes don’t apply to running instances. Rebuild the baked image via the Studio product’s plugins/build endpoint and relaunch from a product template that pins it.
  • workflow.create_and_apply is not the authoring path. It applies a known YAML body. Author via the Studio MCP (studio.<id>.* tools) and use this only to apply backups, fixtures, or cross-instance copies.
  • Studio MCP shows up asynchronously. After instance.launch returns, the daemon retries the upstream MCP handshake with exponential backoff. If the tool list doesn’t include studio.<id>.* immediately, give it a few seconds.
  • The /mcp endpoint is loopback-bypass. It is unauthenticated on the loopback interface only. The proxy refuses to forward /mcp traffic from the outside — connect via the stdio bridge, not the public proxy URL.
  • Manage plugins — plugin tooling, on the Studio product’s HTTP API
  • The live norsk://instructions resource is the source of truth — read it from your MCP host or open backend/src/mcp/instructions.md in the repo