import { Callout } from "zudoku/ui/Callout";

# Tools reference

The MCP server exposes a focused toolset over the [`businessdev.ALbuild` module](../powershell-module/index).
Read-only tools are **synchronous**; mutating / long-running tools are **asynchronous**: they return a
`jobId` you poll with `get-job`.

---

## Tools

| Tool | Tier | Notes |
| --- | --- | --- |
| `list-containers` | read-only | Docker state + pool metadata. |
| `inspect-container` | read-only | Container detail + installed apps. |
| `find-artifact` | read-only | Resolve a BC artifact URL for a country/version/type. |
| `get-build-order` | read-only | Multi-project dependency build order. |
| `resolve-dependencies-plan` | read-only | Dry-run dependency resolution (what would be fetched). |
| `ensure-container` | mutating (job) | Warm-reuse or provision a container; optional dependency install + license. |
| `restart-container` | mutating (job) | Restart a container. |
| `remove-container` | destructive | Self-created → runs; shared/pre-existing → `approval_required`. |
| `reconcile-dependencies` | read-only | Manifest vs container vs feeds → satisfied / available-from-feed / **missing**. |
| `publish-app` | mutating (job) | Upload a built `.app` (base64) and publish it, the remote file transport. |
| `unpublish-app` | mutating (job) | Uninstall (`-Force`) + unpublish one or more apps by name, makes a re-publish at the same version idempotent. |
| `deploy-and-test` | mutating (job) | `appFolder` (local) **or** `apps` (base64 uploads) → publish clean → run tests. |
| `run-tests` | mutating (job) | Re-run tests without redeploy, the fast inner-inner loop. |
| `build-app` | mutating (job) | Compile the workspace fresh (fresh symbols → `alc`). Always runs on the host. |
| `install-dependencies` | mutating (job) | Resolve and install an app's dependency closure into a container. |
| `diagnose-app` | read-only | A container's actual app state: published versions, install/sync state, tenant data version, event-log tail, and named blockers with remedies. |
| `get-test-results` | read-only | Fetch the last test run's results. |
| `convert-coverage` | read-only | Raw BC coverage (`.dat`) → ALbuild JSON / Cobertura / Markdown. |
| `coverage-summary` | read-only | Summarise a coverage report. |
| `coverage-threshold` | read-only | Gate on coverage; reports below-threshold as a failure. |
| `coverage-delta` | read-only | Patch coverage of git-changed lines against a baseline ref. |
| `coverage-merge` | read-only | Merge coverage from several runs into one report. |
| `test-quality` | read-only | Assess AL test quality (assertions / empty tests / score). |
| `get-job` / `cancel-job` | read-only | Async job control. |

---

## The async job model

Anything that mutates a container or runs long returns immediately with a `jobId`:

1. Call the tool → get `{ jobId }`.
2. Poll `get-job` `{ jobId }` → `state` (`running` / `succeeded` / `failed` / `cancelled`), the streamed
   `log`, and on success the structured `result` (e.g. `tests: { passed, failed, skipped, failures[] }`).
3. `cancel-job` aborts a running job.

---

## Remote app and dependency flow

When the agent is **not** on the MCP host (e.g. OpenClaw or Claude Code on a Mac talking to a Windows
host), a filesystem path is meaningless on the host, so apps and feed credentials travel in the call:

1. **`reconcile-dependencies`**: send the `app.json` dependencies **and the merged (app + workspace)
   [`albuild.json`](../concepts/project-config) feeds**, because the host can't read your repo. A private
   feed carries its **API key** in `feeds[].token`, the host doesn't have your credentials, so the agent
   supplies them (kept out of logs, passed to PowerShell via a child env var). You get back what's
   **satisfied** (already in the container, including Microsoft apps), **availableFromFeed**, and **missing**.
2. **`publish-app` / `deploy-and-test`** (upload form), send the missing `.app` files (and your app + test
   app) as base64, in dependency order; the server stages them on the host and publishes. Tests run by
   `testExtensionId`.

<Callout type="info" title="Local agents are simpler">
When the agent runs on the MCP host, `deploy-and-test` takes an `appFolder` host path instead, it resolves the dependency closure from your feeds and publishes every `.app` in the folder directly.
</Callout>

---

## Per-agent tool scoping

Each agent, identified by the stdio `ALBUILD_MCP_AGENT` value or its HTTP bearer token, sees **only its
allowed tools**. This is a correctness requirement for small local models (fewer, relevant tools = better
tool selection). Example roles: a coding-loop agent (full deploy/test), an ops agent (container hygiene),
an architecture/DevOps agent (read-only visibility). The full toolset is available to `claude-code`.

---

## Governance

- **Mutating tools run as logged async jobs**: every action is traceable.
- **`remove-container` protects shared resources**: a container the agent did *not* create this session
  returns `{ status: "approval_required" }` instead of acting, for a human (or the OpenClaw Escalation
  Router) to approve. Only self-created containers are auto-removable
  (toggle with `ALBUILD_ALLOW_SELF_CLEANUP`).
- **Secrets stay where they belong**: the host's own credentials (its PAT, signing cert) live on the host
  as the service identity. Per-feed API keys, which the host does *not* have, are supplied by the agent via
  `reconcile-dependencies` `feeds[].token`, kept out of logs and passed to PowerShell through a child env
  var (never inline). This relies on the authenticated, LAN/Tailscale-only channel.

---

## Configuration (environment variables)

| Variable | Default | Purpose |
| --- | --- | --- |
| `ALBUILD_MODULE_PATH` | installed module | Path to the `businessdev.ALbuild` module to import. |
| `ALBUILD_POWERSHELL` | `pwsh` | PowerShell executable (falls back to `powershell`). |
| `ALBUILD_DOCKER` | `docker` | Docker executable. |
| `ALBUILD_MAX_WARM_CONTAINERS` | `2` | Warm-pool size cap (LRU eviction beyond it). RAM-bound. |
| `ALBUILD_CONTAINER_MEMORY` | `8G` | Memory per container; ceiling for a tool's `memoryLimit` request. |
| `ALBUILD_DEFAULT_ARTIFACT_TYPE` | `Sandbox` | Fallback artifact type. |
| `ALBUILD_ALLOW_SELF_CLEANUP` | `true` | Agent may remove containers it created without approval. |
| `ALBUILD_POOL_STATE` | `%LOCALAPPDATA%/albuild-mcp/pool.json` | Pool registry file. |
| `ALBUILD_MCP_HTTP_HOST` | `127.0.0.1` | HTTP bind host. |
| `ALBUILD_MCP_PORT` | `5020` | HTTP port. |
| `ALBUILD_MCP_TOKENS` | _(none)_ | JSON `{ "<token>": "<agentId>" }` for HTTP bearer auth. |
| `ALBUILD_MCP_AGENT` | `claude-code` | Agent identity for the stdio transport (scopes the toolset). |
| `ALBUILD_MCP_SKIP_PREFLIGHT` | _(unset)_ | Set to `1` to bypass the start-up preflight gate. |

See the [step-by-step guide](get-started) to wire the server into VS Code, Claude Code, or a remote host.
