# Conventions for mcporter MCP wrapper skills

The principles the scaffolder enforces, applied across all transports and auth shapes. Each decision encodes a tradeoff that has already been paid for once. Cite this file when explaining a generated artifact to a user or when pushing back on a request that would violate a convention.

Mode-specific details (OAuth vault seeding, stdio binary gating, bearer-token env interpolation, etc.) live in the per-mode references. This file owns only the rules that apply *regardless of mode*.

References: OpenClaw [skills reference](https://github.com/openclaw/openclaw/blob/main/docs/tools/skills.md), OpenClaw [skill-creator playbook](https://github.com/openclaw/openclaw/blob/main/skills/skill-creator/SKILL.md), mcporter [agent-skills pattern](https://github.com/openclaw/mcporter/blob/main/docs/agent-skills.md), mcporter [config](https://github.com/openclaw/mcporter/blob/main/docs/config.md).

## Frontmatter shape

The standard frontmatter for an mcporter-wrapped skill, with what each field is for. The per-mode references own the specific values; this section owns the shape and which fields are required vs optional.

| Field | Required? | Purpose |
|---|---|---|
| `name` | always | Skill slug. Must equal the directory name and the mcporter server key in `mcporter.json` (load-bearing — drift across these breaks invocation silently). Lowercase + hyphens + digits, ≤64 chars per [skill-creator naming spec](https://github.com/openclaw/openclaw/blob/main/skills/skill-creator/SKILL.md#skill-naming). |
| `description` | always | The agent's primary triggering signal. Durable purpose framing only — name the integration's purpose ("Read and write Linear workspace data"), not the tool surface ("issues, comments, projects, …"). Include a "use when …" cue. Scaffolder emits a `TODO:` placeholder that the user must rewrite before publishing. |
| `homepage` | always | URL pointing at the upstream MCP's documentation (e.g. `https://linear.app/docs/mcp`). Not the vendor's marketing homepage; not an internal wiki. Scaffolder emits a `TODO:` placeholder. |
| `metadata.openclaw.emoji` | always | One emoji used by ClawHub UIs as the skill's icon. Pick a glyph that hints at the integration (📐 for Linear, 📡 for hosted HTTP MCPs, 🔌 for stdio). |
| `metadata.openclaw.requires.bins` | always | Binaries that must exist on PATH at agent runtime. OAuth mode: `["mcporter", "jq", "flock", "shasum"]` because the runtime wrapper calls all four. Other HTTP modes: `["mcporter"]`. stdio: `["mcporter", "<spawn-binary>"]`. |
| `metadata.openclaw.requires.env` | mode-dependent | Env vars OpenClaw requires before loading the skill. OAuth: three vars sharing a prefix. Bearer: one. Headers: every var referenced in `headers`. No-auth: omitted. stdio: any env var the spawn process needs. See [Required env vars are required](#required-env-vars-are-required) below. |
| `metadata.openclaw.primaryEnv` | mode-dependent | The single env var the OAuth runtime wrapper or sanitizer hashes/keys on. Omitted for no-auth. |
| `metadata.openclaw.install` | always | Installer specs that OpenClaw uses to provision binaries listed in `requires.bins`. HTTP modes: a single `mcporter` entry. stdio: `mcporter` plus entries for the spawn binary covering every plausible installer kind (brew, node, uv, go, download). |
| `user-invocable` | optional | `true` only for skills the user invokes directly via slash command. mcporter-wrapped skills are agent-driven and should omit this (or set `false`); mcporter-skill-builder itself sets `true` because the user invokes `/mcporter-skill-builder`. |

References for the frontmatter shape: [OpenClaw skills.md § "Optional frontmatter keys"](https://github.com/openclaw/openclaw/blob/main/docs/tools/skills.md#optional-frontmatter-keys), [OpenClaw skills.md § "Installer specs"](https://github.com/openclaw/openclaw/blob/main/docs/tools/skills.md#installer-specs).

## Discovery template (the "How to use this skill" body)

The discovery flow is identical across all modes — find tools via `--schema`, call them by name, optionally request JSON output. The block below is **a specification, not a copy source**. It uses `<a | b>` alternation syntax to show how the canonical text varies between modes; the per-mode references resolve those alternations into ready-to-copy fences. **When scaffolding, copy from the per-mode reference's fenced template, not from this block.**

````markdown
## How to use this skill

This skill is a thin pass-through to the <hosted MCP server at `<BASE_URL>` | local stdio MCP `<COMMAND_DESCRIPTION>`>. The live <server | MCP> is the source of truth for what tools exist, what they're called, what arguments they take, and any per-server instructions <the server | it> publishes.

**Step 1 — Discover the live tool catalog and any server-published usage instructions.** Always run this first; do not rely on tool names from memory:

```sh
<INVOKE> list <SLUG> --schema
```

The output includes the server's `Instructions:` field (read it) and a JSON Schema for every tool's parameters. Treat this as the authoritative reference for the rest of the session.

**Step 2 — Call any tool from the catalog** using the form `<SLUG>.<tool>`:

```sh
<INVOKE> call <SLUG>.<tool> <arg>=<value> ...
```

Add `--output json` for structured output (also surfaces transport errors as JSON envelopes):

```sh
<INVOKE> call --output json <SLUG>.<tool> ...
```
````

`<INVOKE>` resolves per mode. OAuth uses `bash {baseDir}/scripts/invoke.sh`; non-OAuth modes use `mcporter --config {baseDir}/mcporter.json`.

The per-mode references resolve the `<a | b>` alternations and produce fences ready to substitute and write. Per-mode prose deltas (cold-start note for stdio, "publicly callable" framing for no-auth) come **after** the canonical Step 1/Step 2 block — not as inline edits to it.

## Authentication block

Each per-mode reference owns a fenced Authentication block tailored to its credential model — OAuth's two-paragraph vault-and-refresh form, bearer's static-token form, headers' per-env-var bullet form, no-auth's two-line form, stdio's subprocess-env-passthrough form. The block contract is the same across all five:

- **Mode-level credential contract.** Each block documents how mcporter sources credentials and what failure mode is *not* recoverable in-process: vault auto-refresh + grant-revocation for OAuth; static-token retry for bearer; env-resolution per request for headers; subprocess-env passthrough for stdio; "no credentials" for no-auth. This contract is uniform across any MCP using that mode — Linear and Sentry both use the same OAuth Authentication block content (after substitution).
- **Required expansion.** Some modes need bullet-list or placeholder expansion before writing — `<TOKEN_ENV>` substitution for bearer; one bullet per `<HEADER_NAME>=<ENV_VAR_NAME>` pair for headers; one bullet per env var for stdio. This is part of writing the block, not editing it.
- **Vendor-neutral wording.** The phrase "the upstream service's UI" (and similar mode-level credential phrasing) is intentionally generic — do not vendor-substitute (e.g. to "Linear's UI") inside the canonical paragraphs.

The exact content per mode lives in the per-mode reference's "Authentication" section.

## Editability — Discovery flow and Authentication block

The Discovery flow and the Authentication block are both *canonical* — they share a structure that comes from the per-mode reference's fenced template. They differ in how much prose flexibility they allow once the structure is in place. Single policy across all modes.

**Discovery flow — canonical in structure, prose-flexible.** The shape (opening "thin pass-through" sentence, Step 1/Step 2 progression, the three fenced shell blocks, the `Instructions:`/JSON-Schema follow-up paragraph) is load-bearing and must be preserved. The *prose* inside that structure is editable for clarity:

- *Allowed:* vendor naming substitutions inside the canonical paragraphs ("the server" → "Linear", "the live MCP" → "Linear's hosted MCP server"); small explanatory clarifications that don't add tool-catalog detail (e.g. "where `<server>` is `<slug>` (the local registration key, not Linear's announced name)"); inline examples of *what kind of guidance* the `Instructions:` field publishes ("e.g. how to format markdown content").
- *Not allowed:* tool names, parameter shapes, or domain-entity lists in the Discovery prose (these drift the moment the upstream MCP changes its catalog — see [Skill-vs-MCP boundary](#skill-vs-mcp-boundary)); prose that contradicts `--schema` output; removing or reordering the canonical paragraphs/fences.

**Authentication block — canonical + optional addendum.** Stricter than the Discovery flow.

- *Canonical paragraphs.* Copy from the per-mode reference verbatim after required expansion (see [Authentication block](#authentication-block) above for which modes need expansion). Do not paraphrase the canonical paragraphs and do not vendor-substitute the mode-level credential phrasing.
- *Optional addendum.* You may append a short vendor-specific paragraph (or short subsection under a `### …` heading) after the canonical block when, and only when, the upstream MCP documents auth behavior not already covered. The bar is high — most skills should ship without an addendum. Required properties: verified (cite or point to upstream docs when making a non-trivial claim, e.g. "tokens expire 24h after issuance per `<vendor docs URL>`" is fine; "tokens probably expire after a while" is not); public-safe (no internal orchestrators, employees, customers, or private repos); doesn't contradict the canonical block (if the canonical block says mcporter handles refresh automatically and the upstream MCP requires manual refresh, that's a mode mismatch — switch modes, don't paper over it); doesn't duplicate troubleshooting guesses or list tool behavior (tool behavior belongs to `--schema`; troubleshooting belongs in the body's relevant section, not Authentication).
- *Default to omission.* When in doubt, leave the addendum out.

**Why this asymmetry?** The Discovery flow is narrative and per-skill — vendor naming strengthens it. The Authentication block is mechanical and documents the mode-level credential contract that holds for any MCP using that mode; vendor edits to the canonical paragraphs tend to drift, contradict mcporter's actual behavior, or bloat the body. The addendum exists for the rare case where verified vendor-specific auth behavior really doesn't fit anywhere else.

## Files generated by scaffolding

Every bundle has the same minimal shape. OAuth mode adds the runtime-wrapper scripts; the other four modes ship without `scripts/`.

```
<slug>/
├── SKILL.md
└── mcporter.json
```

For OAuth mode only, additionally:

```
<slug>/
└── scripts/
    ├── invoke.sh          # OAuth runtime wrapper — slug-agnostic, copied byte-for-byte
    └── init-mcporter.sh   # idempotent vault seeder — slug-agnostic, copied byte-for-byte
```

**Why the asymmetry.** OAuth needs a vault seed before mcporter can call the server. The runtime wrapper hashes the env-supplied OAuth credential material to detect rotation and writes the OAuth vault entry mcporter reads at request time. Bearer / headers / no-auth use mcporter's per-request env interpolation — credentials read from process env on every call, no vault seeding. stdio passes env through to the spawned subprocess, also no vault seeding. So only OAuth ships shell scripts.

Per-mode reference notes that genuinely add information (e.g. stdio's pointer to its `install` spec for binary provisioning) live in the per-mode reference's "Files to generate" section. Per-mode references that have nothing mode-specific to add can omit the section entirely.

## Reporting back to the user

After scaffolding succeeds, tell the user what was written and what they need to do before testing. The shape is the same across modes; only the credential/runtime bullets differ.

**Universal bullets — say these every time:**

- The file paths that were written (`<out>/<slug>/SKILL.md`, `<out>/<slug>/mcporter.json`, plus `<out>/<slug>/scripts/{invoke,init-mcporter}.sh` for OAuth mode).
- A reminder that the SKILL.md `description` is a placeholder and must be refined before publishing — the description is the agent's primary triggering signal.
- A smoke-test command suggestion appropriate for the mode.

**Mode-specific bullets — pick the row for the chosen mode:**

| Mode | What to add |
|---|---|
| OAuth | Three required env vars (`<PREFIX>REFRESH_TOKEN`, `<PREFIX>CLIENT_ID`, `<PREFIX>ACCESS_TOKEN`). Tell the user to smoke-test through the wrapper with those env vars set: `bash <out>/<slug>/scripts/invoke.sh list <slug> --schema`. |
| Bearer | One env var (`<TOKEN_ENV>`) the user must populate. mcporter reads it per request, so changes take effect on the next call — no install hook to run. |
| Headers | The env vars referenced by `headers` interpolations (every entry in `requires.env`). No install hook to run. |
| No auth | No env vars to set. No install hook. Add a sanity-check note: confirm with the user that no auth is genuinely correct for this endpoint — a misconfigured no-auth skill against an authenticated server fails every call with 401. |
| stdio | Split the binaries: name what OpenClaw will auto-install (anything covered by an `install` entry — `mcporter` and any spawn-binary entry you emitted) vs. what the user must install manually (anything in `requires.bins` not covered by an `install` entry). Don't skip the manual list — an absent binary silently filters the skill out. Plus any env vars passed via the spawn process's `env` field. No `scripts/install.sh`. |

**Keep the report under ~10 lines.** The user already saw the file writes happen; this is the orientation pass, not a tutorial.

## Optional sections — Conventions worth knowing & Safety

Two SKILL.md sections are *opt-in template slots*. Include them only when they apply; omit entirely otherwise. They live between the discovery flow and Authentication.

### Conventions worth knowing

Section heading: `## Conventions worth knowing`. Include when the upstream MCP has cross-tool invocation conventions that aren't obvious from `--schema` alone. Examples observed in production:

- **Upsert pattern.** Tools that accept an optional `id` parameter — present means update, absent means create. Required fields differ between the two cases.
- **Per-server `Instructions:` field.** Some MCPs publish guidance in the protocol-level `instructions` field (visible in `mcporter list <slug> --schema` output) that applies across every applicable tool — markdown formatting rules, ID handling, etc. The discovery flow already tells the agent to read it, but a one-line reminder helps.
- **ID-vs-slug flexibility.** A parameter typed as "ID" that also accepts human-readable identifiers (issue identifiers, project slugs, team names).

Template shape (substitute the conventions that apply; omit ones that don't):

````markdown
## Conventions worth knowing

These hold across most tools but are not contracts — `--schema` is. Use them as defaults; trust the per-tool schema when it disagrees.

- **<Convention name>.** <One-or-two-sentence description of the convention and where it applies.>
````

This section names *invocation conventions*, not specific tools — so it stays on the right side of the [skill-vs-MCP boundary](#skill-vs-mcp-boundary). If you find yourself listing tool names, you're in the wrong section.

### Safety

Section heading: `## Safety`. Include when the MCP's tool surface has a stable read/write prefix split — most do (Linear's `list_*`/`save_*`/`delete_*` is the canonical example). Standard shape:

````markdown
## Safety

<SERVICE>'s MCP tools split cleanly by name prefix. Read tools (`<READ_PREFIXES>`) are safe to call freely while exploring. Write/delete tools (`<WRITE_PREFIXES>`) modify <SCOPE_DESCRIPTION> visible to <AUDIENCE> — confirm clear user intent before invoking them.
````

This section handles the middle ground that [`allowedTools`/`blockedTools`](#tool-filtering-at-the-config-layer) can't: tools the agent *can* call but *should confirm intent first*. Pure-read MCPs and read-only public APIs (typical of no-auth mode) can omit it. For stdio mode, the Safety section is *additional* to the per-mode "Data flow" section, not a replacement — Data flow covers local-subprocess concerns (host filesystem/network access), Safety covers tool-surface concerns (write semantics).

## Skill-vs-MCP boundary

The MCP server (hosted or stdio) is the catalog. The skill is the deterministic seam between OpenClaw and that MCP — it owns invocation shape, credential plumbing, and a small amount of agent-facing usage guidance, and nothing else.

This boundary drives every other decision:

- **SKILL.md describes how to discover and invoke, not what's available.** The MCP's `--schema` output is the source of truth for tool names, parameters, and the per-server `instructions` field that MCP servers may publish over the protocol ([MCP spec § "Initialization"](https://modelcontextprotocol.io/specification/2025-03-26/basic/lifecycle#initialization), [mcporter call-syntax docs](https://github.com/openclaw/mcporter/blob/main/docs/call-syntax.md)). Do not enumerate tool names, parameter shapes, or domain entities in SKILL.md prose — they will drift the moment the MCP server adds, renames, or removes a tool.
- **The skill description must describe the integration's *purpose*, not its surface.** "Read and write Linear workspace data" is durable; "issues, comments, projects, cycles, milestones, …" is a future PR. Use durable framing.
- **Examples in SKILL.md use generic `<tool>` placeholders** wherever possible, with at most one or two illustrative concrete calls. The agent runs `--schema` first; that's the contract.
- **Mirror the MCP's published guidance via reference, not copy.** When the MCP server publishes per-server `instructions` over the protocol (visible in `mcporter list <slug> --schema`), point the agent at it rather than reproducing it in SKILL.md. Reproductions go stale.

## One skill per MCP server

Direct from mcporter's [agent-skill guidance](https://github.com/openclaw/mcporter/blob/main/docs/agent-skills.md): prefer one small skill per MCP server, not a generic catch-all. Per-server skills keep the agent prompt small, name the useful tools directly, and avoid loading schemas for servers irrelevant to the current task. A generic skill recreates the large-schema context problem mcporter is trying to avoid.

## Naming conventions

Four things must stay in lockstep, or invocation breaks silently:

- **Skill directory name** = `name` field in SKILL.md frontmatter
- = **mcporter server key** in `mcporter.json` (under `mcpServers`)
- = **Invocation prefix** in SKILL.md examples (`mcporter ... call <prefix>.<tool>`)

For modes that use env-var-prefix-derived credentials (OAuth, bearer, headers):
- **Env-var prefix** = uppercased dir name, hyphens → underscores. Slug `acme-linear` typically reads env vars prefixed with `ACME_LINEAR_*`. The exact suffix depends on the auth shape (OAuth uses `_MCP_<TOKEN_KIND>`; bearer/headers can use any naming the user prefers as long as the env var matches the `mcporter.json` reference).

Naming spec per [skill-creator playbook § "Skill Naming"](https://github.com/openclaw/openclaw/blob/main/skills/skill-creator/SKILL.md#skill-naming): lowercase + hyphens + digits only, ≤64 chars, no leading/trailing hyphens, prefer short verb-led phrases. Vendor-prefix where it improves clarity (`acme-linear`, `acme-sentry`) so your variant is distinguishable on ClawHub from any community version.

## `requires.bins` is for the agent runtime only

OpenClaw's `requires.bins` is checked at agent-load time per [OpenClaw skills reference § "Gating (load-time filters)"](https://github.com/openclaw/openclaw/blob/main/docs/tools/skills.md#gating-load-time-filters): each listed bin must exist on `PATH` or the skill is filtered out and invisible to the agent. Declare only what the agent itself invokes.

By mode:
- **OAuth mode**: `["mcporter", "jq", "flock", "shasum"]`. The agent invokes `bash {baseDir}/scripts/invoke.sh`; that wrapper calls `jq`, `init-mcporter.sh` calls `flock` and `shasum`, and the wrapper finally calls `mcporter`.
- **Other HTTP modes** (bearer, headers, none): `["mcporter"]`. The agent calls `mcporter` directly; nothing else is needed at runtime.
- **stdio mode**: `["mcporter", "<binary>"]` where `<binary>` is the stdio MCP's executable. mcporter spawns the binary at call time, so it must be on PATH at the agent runtime.

**Concrete failure mode if an OAuth helper is missing:** OpenClaw may still load the skill if the missing helper is not declared, but the first runtime invocation fails inside `invoke.sh` or `init-mcporter.sh` before the tool call reaches the MCP server. Declare every runtime helper the wrapper actually executes.

## Required env vars are required

When the skill declares any env vars at all (most modes; no-auth is the exception), every declared var must be required — there's no "soft optional" tier. OpenClaw's `metadata.openclaw.requires.env` has dual purpose ([OpenClaw skills reference § "Gating"](https://github.com/openclaw/openclaw/blob/main/docs/tools/skills.md#gating-load-time-filters) for the eligibility gate; [`src/agents/skills/env-overrides.ts`](https://github.com/openclaw/openclaw/blob/main/src/agents/skills/env-overrides.ts) for the sanitizer behavior): it gates skill eligibility on credential presence AND allowlists the env vars past OpenClaw's env-override sanitizer (which drops `*_TOKEN` / `*_KEY` / `*_SECRET` by default).

- **For OAuth and bearer modes**, declare every credential env var as required. Sensitive-named env vars not in `requires.env` get sanitized away. There's no way to declare a "soft optional" sensitive credential — the eligibility gate filters the skill out anyway.
- **For headers mode**, every env var referenced in the `headers` interpolations must be in `requires.env`. mcporter resolves `${VAR}` placeholders at request time per [mcporter config docs](https://github.com/openclaw/mcporter/blob/main/docs/config.md); missing vars cause runtime errors, not load-time filtering.
- **For no-auth mode**, `requires.env` is empty.
- **For stdio mode**, declare any env vars the stdio MCP needs (passed through `mcporter.json`'s `env` field). stdio MCPs commonly need API tokens via env, same as the bearer pattern.

Pick `primaryEnv` as the rotation discriminator — the env var the OAuth wrapper or the agent's auth (bearer) hashes/reads. For OAuth, use `<PREFIX>REFRESH_TOKEN`. For bearer, use the bearer token's env var name. For headers/stdio, pick whichever env var is most representative.

## Per-skill mcporter config

Use the skill-local `mcporter.json` on every invocation. OAuth SKILL.md examples do this through `bash {baseDir}/scripts/invoke.sh`, which exports `MCPORTER_CONFIG={baseDir}/mcporter.json` before execing mcporter. Non-OAuth examples pass `--config {baseDir}/mcporter.json` directly. Per [mcporter config docs § "Config Resolution Order"](https://github.com/openclaw/mcporter/blob/main/docs/config.md#config-resolution-order), either form makes mcporter use exactly that file with no merging of home/project configs.

- **Skill-isolated config.** No cross-skill name collisions in the global `~/.mcporter/mcporter.json` namespace.
- **Self-healing on redeploy.** No mtime-based daemon reload edge cases.
- **For OAuth mode, the vault is shared** across all mcporter callers (keyed by server name + URL hash per [`openclaw/mcporter src/oauth-vault.ts`](https://github.com/openclaw/mcporter/blob/main/src/oauth-vault.ts), so isolation across skills holds even with a shared vault). Just the *config* is per-skill.
- **Trade-off accepted:** daemon connection-caching is forfeit ([mcporter daemon docs](https://github.com/openclaw/mcporter/blob/main/docs/daemon.md)). For HTTP MCPs the cold-start cost is negligible. For stdio MCPs it's the cost of `npx`/`uvx` warming, which is meaningful — consider whether the user needs daemon mode for high-volume stdio workflows (rarely).

## Body sizing and progressive disclosure

OpenClaw uses a three-level loading model (documented authoritatively in the [skill-creator playbook](https://github.com/openclaw/openclaw/blob/main/skills/skill-creator/SKILL.md)):

1. **Metadata** (`name` + `description`) — always in context.
2. **SKILL.md body** — loaded when the skill triggers. **≤500 lines** per skill-creator's hard guidance.
3. **Bundled resources** (`references/`, `scripts/`, `assets/`) — loaded on-demand by the agent.

Practical implications:

- **Description is the trigger.** The body is only loaded *after* the skill has triggered, so trigger-level guidance buried there is invisible to the routing decision. Include "use when …" cues in the description.
- **The agent is already smart.** Default assumption from skill-creator: only add context the agent doesn't already have. Challenge each paragraph: "Does the agent really need this explanation? Does it justify its token cost?"
- **Push detail to `references/`.** Document fragile patterns, schemas, examples in `references/<topic>.md` and link from SKILL.md with a "see X for Y" pointer.

## Anti-patterns

Per [skill-creator playbook § "What to Not Include in a Skill"](https://github.com/openclaw/openclaw/blob/main/skills/skill-creator/SKILL.md#what-to-not-include-in-a-skill), a bundle should only contain files needed for the agent to do the job. **Do not include:**

- `README.md`, `INSTALLATION_GUIDE.md`, `QUICK_REFERENCE.md`, `CHANGELOG.md` — auxiliary docs go on the ClawHub publish page or in the parent repo.
- Symlinks — rejected by the workspace skill loader's realpath check ([OpenClaw skills reference § "Security"](https://github.com/openclaw/openclaw/blob/main/docs/tools/skills.md#security)) and by the [`package_skill.py` validator](https://github.com/openclaw/openclaw/blob/main/skills/skill-creator/scripts/package_skill.py).
- Scripts invoked any way other than `bash <path>` — OpenClaw never spawns skill scripts itself (the agent emits `Bash` tool calls verbatim from SKILL.md, per [skill-creator § "Anatomy of a Skill"](https://github.com/openclaw/openclaw/blob/main/skills/skill-creator/SKILL.md#anatomy-of-a-skill)). SKILL.md examples and internal script-to-script calls must use `bash {baseDir}/scripts/<file>.sh`, not the bare path.

## Tool filtering at the config layer

When the upstream MCP exposes tools that should not be available to the agent, restrict at the config layer, not via SKILL.md prose. Two mutually-exclusive options, both **exact-name** (no globs, no wildcards) per [mcporter config docs](https://github.com/openclaw/mcporter/blob/main/docs/config.md):

```jsonc
// Allowlist: only the listed tools appear in `mcporter list` and can be called.
{
  "mcpServers": {
    "<slug>": {
      "baseUrl": "https://...",
      "transport": "http",
      "auth": "oauth",
      "allowedTools": ["read_issue", "list_issues", "create_comment"]
    }
  }
}
```

```jsonc
// Blocklist: listed tools are hidden from `mcporter list` and rejected by `mcporter call`.
{
  "mcpServers": {
    "<slug>": {
      "baseUrl": "https://...",
      "transport": "http",
      "auth": "oauth",
      "blockedTools": ["delete_workspace", "transfer_ownership"]
    }
  }
}
```

Pick one — `allowedTools` and `blockedTools` cannot be combined in the same server entry. Use `allowedTools` when the safe surface is small and known; use `blockedTools` when the unsafe surface is small and the rest is fine. Both work across HTTP and stdio transports. SKILL.md prose telling the agent "don't call X" is unreliable; these fields make X invisible at the protocol layer.

## Public-distribution discipline

Skill bundles ship to public ClawHub. Do not put internal project names, employee names, customer names, live ticket numbers, or links to private repos inside the bundle. Use generic role names ("the install orchestrator") rather than naming a specific internal service. Consumers may run their own orchestrators against the same skill contract; the skill should not assume a specific one.

## References

Authoritative sources for the conventions enforced above:

- [OpenClaw skills reference](https://github.com/openclaw/openclaw/blob/main/docs/tools/skills.md) — load-time gating (`requires.bins`, `requires.env`, `requires.config`), `metadata.openclaw` frontmatter shape, security checks (realpath, symlink rejection), `{baseDir}` placeholder
- [OpenClaw skill-creator playbook](https://github.com/openclaw/openclaw/blob/main/skills/skill-creator/SKILL.md) — naming spec, body ≤500 lines, three-level loading model, anti-pattern files, "agent is already smart" default, description-as-trigger
- [openclaw/mcporter — agent-skill pattern](https://github.com/openclaw/mcporter/blob/main/docs/agent-skills.md) — "one MCP server per skill" guidance, `allowedTools` / `blockedTools` config-layer filtering
- [openclaw/mcporter — config docs](https://github.com/openclaw/mcporter/blob/main/docs/config.md) — `--config` resolution, XDG path resolution, transport selection, env-var interpolation in `headers` and stdio `env`
- [openclaw/mcporter — `src/oauth-vault.ts`](https://github.com/openclaw/mcporter/blob/main/src/oauth-vault.ts) — vault key derivation (used by OAuth mode's `init-mcporter.sh`)
- [openclaw/mcporter — daemon docs](https://github.com/openclaw/mcporter/blob/main/docs/daemon.md) — connection-caching trade-offs vs per-skill `--config`
- [openclaw/openclaw — `src/agents/skills/env-overrides.ts`](https://github.com/openclaw/openclaw/blob/main/src/agents/skills/env-overrides.ts) — env-override sanitizer that drops sensitive-named vars not in `requires.env`
- [Model Context Protocol — `Initialization` spec](https://modelcontextprotocol.io/specification/2025-03-26/basic/lifecycle#initialization) — the per-server `instructions` field that mcporter surfaces in `--schema` output
