SmartGateSmartGate

Connect OpenClaw to SmartGate over MCP: Config and Guardrails

Connecting OpenClaw to SmartGate is one MCP server entry: point mcp.servers.smartgate at a Streamable HTTP endpoint, send Authorization: Bearer <key> plus an X-SmartGate-Agent-Platform: OpenClaw header, and OpenClaw gains the gateway's seven tools.

Short answer: Connecting OpenClaw to SmartGate is one MCP server entry: point mcp.servers.smartgate at a Streamable HTTP endpoint, send Authorization: Bearer <key> plus an X-SmartGate-Agent-Platform: OpenClaw header, and OpenClaw gains the gateway's seven tools. The openclaw mcp set path takes one command, mcp.* changes hot-apply without a gateway restart, and every call after that is metered, rate-limited per plan, and written to the team's audit log.

Key takeaways

  • One endpoint, seven tools. mcpStreamableUpstreamUrl resolves the gateway's MCP root to <backend>/mcp/; OpenClaw talks Streamable HTTP (stateless POST), not stdio.
  • Two headers, and the second one is the one people forget. buildMcpAuthHeaders emits Authorization: Bearer … plus the agent-platform header — without the platform header your Audit Logs attribute every call to the default label.
  • openclaw mcp set beats hand-editing JSON. buildOpenClawMcpSetCommand produces a single shell command that writes the same server entry the JSON template does.
  • Do not merge OpenClaw config into Cursor's shape. OpenClaw reads mcp.servers, not mcpServers; the hint text in getMcpPlatformHints says so explicitly, and a wrong key silently produces a server that never connects.
  • Per-plan MCP limits are per key, with a team ceiling. Free allows 120 MCP requests per minute per key, Pro 300, Teams 600, Enterprise 1,200 — and Teams adds a 3,000/min team ceiling.
  • Add the cap before you add autonomy: run smart_budget_guard check/record around the loop and set the team's monthly token limit, so an OpenClaw agent that loops cannot bill silently.

The short version for whoever signs the invoice

OpenClaw is an open-source personal AI assistant that grew fast enough to dominate the MCP integration conversation: "openclaw" carries roughly 246,000 monthly US searches, and "openclaw mcp" already returns an AI Overview on the first page — meaning the question "how do I give OpenClaw tools?" is being answered by search engines, not only by docs. The interesting part for a team is not installation. It is what happens on the ten thousandth tool call: which ones were allowed, what they cost, and who can prove it.

SmartGate is an MCP-native algorithm gateway for token control, traffic shaping, and agent audit. It is not a model host and not a wrapper around one: you keep OpenClaw and its host model, and connect the gateway as one more MCP server. The difference is that the gateway governs the tool side of the loop — fetch, search, compression, dedup, budget, memory, and pipelines — with a rate limit per key, a hard budget cap, and an audit row per call. Those controls are the application-side half of a gateway, and the decisions they rest on are surveyed in the enterprise AI gateway architecture guide.

The bill is "Pay for the platform. Share only when you save." On the Free plan you get 2M tokens/month, all seven tools, 120 MCP requests/min per key, and 7-day log retention, no card required. Pro starts at $18/month ($5 for the first month), and the savings share only begins after $15 of measured savings — capped at roughly $36/month on Pro (pricing).

What OpenClaw expects from an MCP server

OpenClaw's own MCP documentation describes servers added through the gateway config or the CLI, with Streamable HTTP and stdio both supported (OpenClaw MCP servers). A remote server therefore needs three things: a URL, a transport, and credentials that travel as headers. Everything else — which tools exist, what they accept, what they return — is negotiated over the protocol after the connection is established. Anything placed in front of that URL that does more than forward the connection is a different layer, and the boundary between a proxy, a router and a gateway is drawn in which layer decides what.

That is the same shape the Model Context Protocol specification defines for HTTP transports: one endpoint that accepts JSON-RPC messages, with sessions optional for stateless servers (MCP transports). SmartGate's MCP surface is deliberately stateless, which is why the configuration below needs no session id.

If the server on the other end is one you are writing yourself rather than pointing at ours, the Python MCP server walkthrough covers that side end to end — the transport, the tool list and the auth check — before you wire it into this config.

Practically, people connecting OpenClaw to remote MCP servers hit the same three problems, and the community threads read like a checklist: the config key is wrong for the client, the auth header is missing or malformed, or the server is assumed to be stdio-only (Reddit: running OpenClaw with MCP tools). Each of the next sections is one of those problems, answered with the gateway's own code.

buildMcpAuthHeaders: the two headers OpenClaw sends

Authentication is two headers, and they do different jobs. The first authorizes the request; the second tells the gateway which agent platform is calling, which is what makes per-host attribution in Audit Logs possible.

# lib/connect/mcp-config-templates.ts — source lines 26–34 (buildMcpAuthHeaders)
function buildMcpAuthHeaders(
  apiKeyPlaceholder: string,
  agentPlatform: string,
): Record<string, string> {
  return {
    Authorization: `Bearer ${apiKeyPlaceholder}`,
    [AGENT_PLATFORM_HEADER]: agentPlatform,
  };
}

Authorization carries the API key exactly as issued (sk_live_… in the hint text below); the platform header is a label, not a secret, and it is what separates "some agent called smart_fetch" from "OpenClaw called smart_fetch". Nothing else is required — no session cookie, no OAuth handshake, because the gateway's MCP endpoint is stateless by design.

One operational note that saves an hour of debugging: 401 means an invalid or missing Bearer, not a broken server. The hint text shipped with the OpenClaw setup says precisely that, and it is the single most common cause of a server entry that looks correct but never connects.

mcpStreamableUpstreamUrl: which URL OpenClaw actually calls

The URL is derived, not typed by hand. The gateway resolves its own backend root and appends the MCP path, normalizing a trailing slash first:

# lib/connect/mcp-proxy.ts — source lines 8–11 (mcpStreamableUpstreamUrl)
function mcpStreamableUpstreamUrl(base?: string): string {
  const root = (base ?? smartgateBackendBase()).replace(/\/$/, "");
  return `${root}/mcp/`;
}

This is the backend root the gateway's own MCP route proxies to — the app-side endpoint clients actually dial is https://smartgate.network/api/mcp (POST), as the endpoint docs list it. Keep the two apart when you debug: the public endpoint is what goes in url, and this helper is what the proxy layer resolves internally. Per-session paths and stream identifiers are negotiated by the client, not configured by you. A self-hosted deployment publishes its own equivalent of that public endpoint, and the contract for running one inside your own network is deploying a gateway in a private cloud.

buildOpenClawMcpConfigJson: the server entry, exactly

Here is the entry OpenClaw needs, generated by the gateway so the shapes cannot drift:

# lib/connect/mcp-config-templates.ts — source lines 137–159 (buildOpenClawMcpConfigJson)
function buildOpenClawMcpConfigJson(
  mcpUrl: string,
  apiKeyPlaceholder: string = API_KEY_PLACEHOLDER,
): string {
  return JSON.stringify(
    {
      mcp: {
        servers: {
          smartgate: {
            url: mcpUrl,
            transport: "streamable-http",
            headers: buildMcpAuthHeaders(
              apiKeyPlaceholder,
              PLATFORM_AGENT_ID.OpenClaw,
            ),
          },
        },
      },
    },
    null,
    2,
  );
}

Three details matter more than the pretty-printing. First, the nesting is mcp.servers — OpenClaw's own key, not the mcpServers object that Cursor and Claude Desktop use. Second, transport: "streamable-http" is explicit: choosing stdio here is the mistake that produces a client which spawns nothing and reports no error. Third, the headers are exactly the two from the previous section, with the platform id pinned to OpenClaw so every downstream audit row carries the right label.

buildOpenClawMcpSetCommand: setup as one line

For OpenClaw the gateway does not stop at JSON — it emits the CLI command that installs the same entry:

# lib/connect/mcp-config-templates.ts — source lines 191–204 (buildOpenClawMcpSetCommand)
function buildOpenClawMcpSetCommand(
  mcpUrl: string,
  apiKeyEnvVar: string = "SMARTGATE_API_KEY",
): string {
  const payload = JSON.stringify({
    url: mcpUrl,
    transport: "streamable-http",
    headers: {
      Authorization: `Bearer \${${apiKeyEnvVar}}`,
      [AGENT_PLATFORM_HEADER]: PLATFORM_AGENT_ID.OpenClaw,
    },
  });
  return `openclaw mcp set smartgate '${payload}'`;
}

The placeholder comes from the caller's snippet, so the command is copy-pasteable once and does not leak a key into shell history if you export it first. This is also the path the gateway's own hint text recommends, for a reason that matters during iteration: mcp.* changes hot-apply, so you can add the server, test a tool call, and adjust without restarting the assistant.

mcpConfigFilename: the file names are not interchangeable

When someone does prefer files over the CLI, the gateway hands them the right name per host instead of a generic example:

# lib/connect/mcp-config-templates.ts — source lines 249–264 (mcpConfigFilename)
function mcpConfigFilename(platform: McpPlatform): string {
  switch (platform) {
    case "Claude Desktop":
      return "claude_desktop_config.json";
    case "Cursor":
      return "mcp.json";
    case "Windsurf":
      return "mcp_config.json";
    case "Hermes":
      return "mcp.json";
    case "OpenClaw":
      return "openclaw-smartgate-snippet.json";
    default:
      return "smartgate-mcp.json";
  }
}

OpenClaw's snippet file is named for its purpose, and the Cursor/Hermes/Windsurf/Claude Desktop names are the ones those clients actually load. One universal "mcp.json" would be simpler — and wrong for four of the five clients, which is how a five-minute integration becomes a support thread.

getMcpPlatformInstallCommand: install vs. "figure it out yourself"

Not every host documents its setup equally well, so the gateway only offers an install command where one exists and stays honest where it does not:

# lib/connect/mcp-config-templates.ts — source lines 213–225 (getMcpPlatformInstallCommand)
function getMcpPlatformInstallCommand(
  platform: McpPlatform,
  mcpUrl: string,
): string | null {
  switch (platform) {
    case "OpenClaw":
      return buildOpenClawMcpSetCommand(mcpUrl);
    case "Claude Desktop":
      return buildClaudeDesktopMcpAddCommand(mcpUrl);
    default:
      return null;
  }
}

OpenClaw and Claude Desktop get a real command; every other platform gets null and relies on the config file plus the hint text. Returning an empty string or a plausible-looking command would be worse than returning nothing: a silent no-op command is indistinguishable from a broken server. The Claude Desktop entry in that list is the same server seen from Anthropic's MCP clients: one endpoint, a different file name, and a differently named key for the transport.

getMcpPlatformHints: the OpenClaw hints, in the gateway's words

The hints are the closest thing to first-line support text, and the OpenClaw branch is specific about failure modes:

# lib/connect/mcp-config-templates.ts — source lines 387–416 (getMcpPlatformHints)
    case "OpenClaw":
      return [
        docsLink,
        {
          kind: "text",
          children: `Merge under mcp.servers in ${PLATFORM_CONFIG_PATH.OpenClaw}. Not Cursor mcpServers.`,
        },
        {
          kind: "text",
          children:
            "Recommended: run the openclaw mcp set command below. mcp.* changes hot-apply; gateway restart usually not required.",
        },
        {
          kind: "code",
          before: "",
          code: "transport: streamable-http",
          after:
            " — SmartGate MCP Streamable HTTP (stateless POST).",
        },
        {
          kind: "text",
          children:
            "401 = invalid Bearer. Ensure Authorization header contains a valid sk_live_… key.",
        },
        {
          kind: "text",
          children: `Include ${AGENT_PLATFORM_HEADER}: ${PLATFORM_AGENT_ID.OpenClaw} in headers (included in the snippet below) so Audit Logs shows the correct agent platform.`,
        },
        ...authAndUrlHints(),
      ];

Four things are worth quoting back. Merge under mcp.servers, not Cursor's mcpServers. Run the openclaw mcp set command when you can — mcp.* changes hot-apply, so a gateway restart is usually not required. The transport is Streamable HTTP with stateless POST. And a 401 means invalid Bearer, so check that the Authorization header contains a valid sk_live_… key before suspecting the server.

forwardMcpRequestHeaders: what survives the hop

If you front the gateway with your own proxy or middleware, the header forwarding is specified rather than implied:

# lib/connect/mcp-proxy.ts — source lines 14–37 (forwardMcpRequestHeaders)
function forwardMcpRequestHeaders(incoming: Headers): Headers {
  const out = new Headers();
  const auth = incoming.get("Authorization");
  if (auth) out.set("Authorization", auth);
  const contentType = incoming.get("Content-Type");
  if (contentType) out.set("Content-Type", contentType);
  out.set("Accept", "application/json");

  const platform =
    incoming.get("X-SmartGate-Agent-Platform") ??
    incoming.get("x-smartgate-agent-platform");
  if (platform) {
    out.set("X-SmartGate-Agent-Platform", platform);
  } else {
    out.set("X-SmartGate-Agent-Platform", "cursor");
  }

  const trace =
    incoming.get("X-SmartGate-Trace-Id") ??
    incoming.get("x-smartgate-trace-id");
  if (trace) out.set("X-SmartGate-Trace-Id", trace);

  return out;
}

The auth header and content type pass through untouched, Accept: application/json is set for the JSON-RPC exchange, and the platform and trace identifiers are forwarded when present. When they are absent, the platform defaults to cursor — legacy behaviour kept for compatibility, and exactly why the explicit X-SmartGate-Agent-Platform: OpenClaw header is worth the four extra characters. What that outer proxy is allowed to act on depends on whether it is a classic API gateway or an AI-aware one, which is the split drawn in AI gateway versus API gateway.

getPlanRateLimits: per-key MCP limits, with a team ceiling

Rate limits are read from the plan catalog, not configured per deployment:

# lib/plan-rate-limits.ts — source lines 5–12 (getPlanRateLimits)
function getPlanRateLimits(plan: Plan) {
  const f = getPlanCatalogEntry(plan).features;
  return {
    restWriteRpm: f.max_team_rpm,
    mcpRpmPerKey: f.mcp_rpm_per_key,
    mcpRpmTeamCeiling: f.mcp_rpm_team_ceiling,
  };
}

The numbers behind that lookup, per the plan catalog, are 120 MCP requests/min per key on Free, 300 on Pro, 600 on Teams, and 1,200 on Enterprise, with team ceilings of 120 / 600 / 3,000 / 9,999 respectively. The two numbers answer different questions: the per-key limit protects the gateway from one runaway agent, and the team ceiling protects your whole workspace when several agents run at once. A personal OpenClaw setup will never see the ceiling. A team running OpenClaw plus two other clients will.

smart_budget_guard: the cap an agent cannot argue with

Rate limits bound the burst; the budget guard bounds the month. It is exposed as an MCP tool with three actions — check, count, record — and it runs every call through the audit wrapper:

# backend/smartgate/api/mcp.py — source lines 233–252 (smart_budget_guard)
        _, registry = _app_state()
        module = registry.get("budget_guard")
        tid = (team_id or "").strip() or bound_team_id()
        ctx = _tool_ctx(tid)
        params = _non_empty(
            action=action,
            team_id=tid or None,
            text=text,
            messages=messages,
            model=model,
            tokens=tokens or None,
            monthly_limit=monthly_limit or None,
            completion_tokens=completion_tokens or None,
        )
        return await _run_with_audit(
            "budget_guard",
            ctx,
            module.process(ctx, **params),
            params,
        )

check returns an allowance decision against the team's monthly cap (overridable per call), count estimates tokens for text or chat messages against a named model, and record logs what was actually used. The parameter shape matters in practice: an empty team_id falls back to the API key tenant, which is what you want for a single-user OpenClaw install, and the explicit override exists for integrators who route several tenants through one key.

runAuditRetention: the logs you will actually be asked for

Audit rows are telemetered per plan and pruned on a schedule — the retention job walks teams, resolves each plan's retention window, and deletes older rows:

# lib/jobs/audit-retention.ts — source lines 6–24 (runAuditRetention)
async function runAuditRetention() {
  const teams = await prisma.team.findMany({
    select: { id: true, plan: true, features: true },
  });
  let deleted = 0;
  for (const team of teams) {
    const days = planEntitlements(
      team.plan as Plan,
      team.features as Record<string, unknown> | null,
    ).activity_log_retention_days;
    const cutoff = new Date();
    cutoff.setDate(cutoff.getDate() - days);
    const result = await prisma.auditLog.deleteMany({
      where: { teamId: team.id, timestamp: { lt: cutoff } },
    });
    deleted += result.count;
  }
  return { teams: teams.length, deleted };
}

Retention is a plan entitlement: 7 days on Free, 30 on Pro, 90 on Teams, 180 on Enterprise. That is enough for the two questions that arrive after an incident — what did the agent call, and in what order — but it is not an archive. If a compliance requirement says "keep a year of tool-call history", the gateway's job is to give you the rows; keeping them longer than the plan window is yours.

smart_pipe: four steps, one audited call

The last piece is the one that changes how an OpenClaw workflow is written. Instead of asking the agent to chain fetch → compress → store as four separate tool calls, smart_pipe runs the chain inside the gateway and reports per-step success:

# backend/smartgate/api/mcp.py — source lines 343–387 (smart_pipe)
        payload = await engine.run(
            ctx,
            template=template,
            steps=steps,
            inputs=run_inputs,
        )
        data = payload if isinstance(payload, dict) else {"result": payload}
        merged_data = {
            **data,
            "results": payload.get("results") or [],
        }
        steps_meta = payload.get("pipeline_steps") or []
        pipeline_ok = bool(steps_meta) and all(s.get("success") for s in steps_meta)
        failed_step = next((s for s in steps_meta if not s.get("success")), None)
        failed_result = next(
            (r for r in (payload.get("results") or []) if not r.get("success")),
            None,
        )
        step_error = None
        if failed_result:
            step_error = failed_result.get("error")
        elif failed_step:
            step_error = failed_step.get("error")
        if not pipeline_ok:
            merged_data["failed_step"] = failed_step.get("step") if failed_step else None
            merged_data["failed_tool"] = failed_step.get("tool") if failed_step else None
            merged_data["step_error"] = step_error
        tool_result = ToolResult(
            success=pipeline_ok,
            data=merged_data,
            error=None if pipeline_ok else (step_error or "pipeline step failed"),
            meta={},
        )
        audit_extra = {
            **params,
            "trace_kind": "pipeline",
            "pipeline_template": template or None,
            "pipeline_steps": payload.get("pipeline_steps") or [],
        }
        return await _run_with_audit(
            "pipe",
            ctx,
            _identity_result(tool_result),
            audit_extra,
        )

Two details matter in that return path. A failed step does not vanish: the response carries failed_step, failed_tool, and step_error, so the agent can tell "the pipeline broke at fetch" from "the query returned nothing". And the run is written as one audit trace with trace_kind: pipeline, so a research workflow is one entry instead of four unrelated calls.

How SmartGate compares

The category splits by what sits in the request path and what it can actually stop. SmartGate's scope is narrow on purpose: it governs tool traffic and only charges a share when it has saved you money.

What it governs How you run it What you pay
SmartGate MCP tool calls from OpenClaw and other hosts: fetch, search, compression, dedup, budget, memory, pipes Hosted gateway; one MCP server entry per client Free: 2M tokens/mo, all 7 tools, 120 req/min/key. Pro from $18/mo (first month $5), capped ~$36/mo, share only after $15 saved (pricing)
Local stdio MCP servers One capability each, in-process (e.g. a filesystem or browser server) Installed locally, spawned by the client Free/open source; you own the runtime and the blast radius (OpenClaw MCP docs)
Self-hosted MCP bridges Per-server compatibility shims between hosts and tools You run and patch the bridge Engineering time; no budget, rate-limit, or audit layer (openclaw-mcp-bridge)
LLM routers / proxies Model calls and prompt routing Hosted or self-hosted Usage-based on model traffic — a different line item from tool traffic

Two honest readings. If your OpenClaw install needs one local capability on your own machine, a local stdio server is the right answer: nothing leaves the box and nothing is metered. The moment you want to know what the agent did or cap what it may spend across more than one client, you are describing gateway concerns — and a bridge script is not one.

If the proxy you are weighing leaving is a self-hosted one, that move has its own decision framework, set out on the LiteLLM alternative page.

Routing model traffic is a separate line item from governing tool traffic, and what separates this gateway from an OpenRouter-style router is set out in OpenRouter Alternative Explained.

How to get started

  1. Get a key and the snippet. Create a team, mint an API key, and open the Connect page: it generates the OpenClaw entry and the openclaw mcp set command with your own key placeholder.
  2. Install the server. Run the command (or merge the JSON under mcp.servers), then call one tool to confirm — smart_fetch on any URL is the fastest end-to-end check.
  3. Label the host. Keep X-SmartGate-Agent-Platform: OpenClaw in the headers so this client's calls are separable in Audit Logs from your other agents.
  4. Cap it before you automate. Set the team's monthly token limit and wrap the loop with smart_budget_guard check/record; move multi-step work into smart_pipe so it stays one audited call.

Start on Free — 2M tokens/month, all seven tools, no card: start free, then compare caps and retention windows against your workload on the pricing page.

Frequently Asked Questions

What is OpenClaw and what does it do?

OpenClaw is an open-source personal AI assistant. On this integration it stays the client and keeps its own host model, and the gateway is added as one more MCP server — OpenClaw then gains the gateway's seven smart_* tools, whose calls are metered, rate-limited per plan and written to the audit log.

Is OpenClaw the same as Claude?

No — the page treats them as two different MCP clients. OpenClaw is configured under mcp.servers, while Claude Desktop is one of Anthropic's MCP clients with its own config file name and a differently named transport key for the same server.

Where does OpenClaw's MCP config go?

Under mcp.servers in the OpenClaw config, or wherever the openclaw mcp set command writes the entry. It is not the mcpServers key that Cursor and Claude Desktop use, and mixing the two produces a server that never connects.

Do I need to restart OpenClaw after adding the server?

Usually not. MCP config changes hot-apply, which is why the gateway recommends the openclaw mcp set path: you can install the server and test a tool call in the same shell session.

What does a 401 from the MCP endpoint mean?

An invalid or missing Bearer token. Check that the Authorization header carries a valid key; the server itself is almost certainly reachable if it answered with a 401 rather than a connection error.

Is Streamable HTTP required, or can I use stdio?

Streamable HTTP is what the configuration templates emit and what the hosted gateway serves: stateless POST to the MCP root path. Stdio is the shape for servers that run on the same machine, not for a remote gateway.

How many tools appear in OpenClaw once connected?

Seven: smart_fetch, smart_search, smart_context_gate, smart_dedup, smart_budget_guard, smart_memory, and smart_pipe. All seven are available on the Free plan.

What stops an OpenClaw loop from running all night?

Two different limits. The per-plan MCP rate limit bounds the burst (120 requests/min per key on Free, up to 1,200 on Enterprise), and the monthly token cap enforced through smart_budget_guard bounds the total. Alerts alone do not stop an agent loop; enforcement does.

Can I keep several OpenClaw instances on one key?

Yes, within the per-key rate limit and the team ceiling above it: 120/600/3,000/9,999 requests per minute for Free/Pro/Teams/Enterprise.

Limitations and what this does not do

  • The platform header is a label, not a control. It improves attribution in Audit Logs; it does not authenticate the client beyond the Bearer token, so per-client authorization still needs separate keys.
  • Log retention is per plan (7/30/90/180 days) and the retention job prunes on a schedule. If you need longer history, export it before the window closes — the gateway is not an archive.
  • A budget cap is not a sandbox. Capping spend does not make an unsafe tool safe, and the gateway cannot judge whether a fetched page should have been fetched.
  • Rate limits are per key and per team, not per agent role. Two agents sharing a key share the limit; split keys when you need independent budgets.
  • OpenClaw is not ours. Its configuration surface, CLI flags, and MCP behaviour are documented by its maintainers and can change; the gateway's templates track the shape we support today.

Sources

Method note

The code in this article is not transcribed. Each block was cut directly out of the slice body returned by the SmartGate slice API and then re-asserted byte-for-byte as a substring of that body before publication; the first line inside every fence records the file and the exact source lines. Symbols were pinned with whole-name containment (rule A level 2) and confirmed by the service's slot-proof endpoint before being written into the prose. Only the OpenClaw branch of the platform hints is reproduced here; the other host branches were left out deliberately rather than paraphrased.

Slice provenance

# SERP keyword Symbol File Source lines How it was pinned sha256(12)
1 buildMcpAuthHeaders bearer auth headers for the OpenClaw MCP connection buildMcpAuthHeaders lib/connect/mcp-config-templates.ts 26–34 rule A L2 → slot-proof e47d2e879ac0
2 mcpStreamableUpstreamUrl OpenClaw MCP streamable HTTP upstream URL mcpStreamableUpstreamUrl lib/connect/mcp-proxy.ts 8–11 rule A L2 → slot-proof 5772cf940885
3 buildOpenClawMcpConfigJson OpenClaw MCP config JSON buildOpenClawMcpConfigJson lib/connect/mcp-config-templates.ts 137–159 rule A L2 → slot-proof ede08601b46c
4 buildOpenClawMcpSetCommand OpenClaw MCP set command one line buildOpenClawMcpSetCommand lib/connect/mcp-config-templates.ts 191–204 rule A L2 → slot-proof 161c6769bc60
5 mcpConfigFilename which MCP config file OpenClaw reads mcpConfigFilename lib/connect/mcp-config-templates.ts 249–264 rule A L2 → slot-proof d60503ebfb68
6 getMcpPlatformInstallCommand install command per MCP host platform getMcpPlatformInstallCommand lib/connect/mcp-config-templates.ts 213–225 rule A L2 → slot-proof 8ee797e82a2b
7 getMcpPlatformHints MCP host auth and URL hints getMcpPlatformHints lib/connect/mcp-config-templates.ts 387–416 rule A L2 → slot-proof 097aa9ab5578
8 forwardMcpRequestHeaders forward MCP request headers to the gateway forwardMcpRequestHeaders lib/connect/mcp-proxy.ts 14–37 rule A L2 → slot-proof 8b0ca1e1970b
9 getPlanRateLimits per plan MCP request rate limits getPlanRateLimits lib/plan-rate-limits.ts 5–12 rule A L2 → slot-proof 6d29a819fd91
10 smart_budget_guard hard budget cap for OpenClaw agent loops smart_budget_guard backend/smartgate/api/mcp.py 233–252 rule A L2 → slot-proof 1f5f74bc48b7
11 runAuditRetention audit log retention for MCP tool calls runAuditRetention lib/jobs/audit-retention.ts 6–24 rule A L2 → slot-proof 9e549a91c008
12 smart_pipe multi step MCP pipeline for OpenClaw research tasks smart_pipe backend/smartgate/api/mcp.py 343–387 rule A L2 → slot-proof 91ee6d5bb70b

Every fenced block above was cut from the slice body and re-asserted against it byte-for-byte before publication. 12 of 12 sections pinned, 0 abstentions, 0 misses.