openclaw - 💡(How to fix) Fix [Bug]: ${VAR} placeholders in mcp.servers.<name>.headers.* are not added to gateway service-env on daemon install

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

${VAR} placeholders inside mcp.servers.<name>.headers.* are not picked up by the env-key scanner during openclaw daemon install, so the launchd-managed gateway never receives the referenced env var even when it is declared in ~/.openclaw/.env. Combined with the schema rejecting structured {source, provider, id} ref objects in both headers.* and env.vars.*, there is no in-config way to wire a secret HTTP header for an MCP server that survives daemon install --force.

Error Message

$ openclaw config set env.vars.GITHUB_PAT
--ref-provider env --ref-source env --ref-id GITHUB_PAT Error: invalid env.vars.GITHUB_PAT: expected string, received object

Root Cause

${VAR} placeholders inside mcp.servers.<name>.headers.* are not picked up by the env-key scanner during openclaw daemon install, so the launchd-managed gateway never receives the referenced env var even when it is declared in ~/.openclaw/.env. Combined with the schema rejecting structured {source, provider, id} ref objects in both headers.* and env.vars.*, there is no in-config way to wire a secret HTTP header for an MCP server that survives daemon install --force.

Fix Action

Fix / Workaround

Affected: anyone configuring an HTTP MCP server with a secret header via OpenClaw config. Severity: blocks the feature unless the operator maintains an out-of-band workaround. Frequency: 100% of daemon install --force runs wipe the workaround. Consequence: the documented config shape for secret HTTP MCP headers (${VAR} placeholders) does not work; operators must hand-edit service-env/ai.openclaw.gateway.env after every install and re-paste their secrets there.

Current workaround in use: hand-append export GITHUB_PAT=… to ~/.openclaw/service-env/ai.openclaw.gateway.env after every daemon install --force. Wiped on the next install. Documented in our internal runbook as a stopgap.

Code Example

"mcp": {
     "servers": {
       "github": {
         "transport": "http",
         "url": "https://api.githubcopilot.com/mcp/",
         "headers": {
           "Authorization": "Bearer ${GITHUB_PAT}"
         }
       }
     }
   }

---

$ openclaw doctor
warn  Missing env var "GITHUB_PAT" (referenced by mcp.servers.github.headers.Authorization)

---

$ openclaw config set env.vars.GITHUB_PAT \
    --ref-provider env --ref-source env --ref-id GITHUB_PAT
Error: invalid env.vars.GITHUB_PAT: expected string, received object

---

$ cat ~/.openclaw/service-env/ai.openclaw.gateway.env | grep -i github
# (no output — var not added by daemon install)

---

Authorization: Bearer ${GITHUB_PAT}

---

HTTP/1.1 400 Bad Request
{"error": "Authorization header is badly formatted"}
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

${VAR} placeholders inside mcp.servers.<name>.headers.* are not picked up by the env-key scanner during openclaw daemon install, so the launchd-managed gateway never receives the referenced env var even when it is declared in ~/.openclaw/.env. Combined with the schema rejecting structured {source, provider, id} ref objects in both headers.* and env.vars.*, there is no in-config way to wire a secret HTTP header for an MCP server that survives daemon install --force.

Steps to reproduce

  1. Add an HTTP MCP server to ~/.openclaw/openclaw.json:
    "mcp": {
      "servers": {
        "github": {
          "transport": "http",
          "url": "https://api.githubcopilot.com/mcp/",
          "headers": {
            "Authorization": "Bearer ${GITHUB_PAT}"
          }
        }
      }
    }
  2. Add GITHUB_PAT=ghp_… to ~/.openclaw/.env.
  3. Run openclaw daemon install --force.
  4. Inspect ~/.openclaw/service-env/ai.openclaw.gateway.env.
  5. Have the agent invoke a tool from the github MCP server.

Expected behavior

After step 3, service-env/ai.openclaw.gateway.env contains a GITHUB_PAT=… line (the scanner having resolved the ${GITHUB_PAT} reference in headers.Authorization). The launchd-managed gateway process inherits the var, the MCP authenticates against api.githubcopilot.com, and tool calls succeed.

Actual behavior

After step 3, service-env/ai.openclaw.gateway.env contains no entry for GITHUB_PAT. openclaw doctor warns Missing env var "GITHUB_PAT". MCP requests fail with an upstream auth error consistent with the literal string Bearer ${GITHUB_PAT} being sent on the wire instead of the resolved value (upstream returns 400 with Authorization header is badly formatted).

A parallel attempt to declare the var via env.vars.GITHUB_PAT = { source, provider, id } is rejected at config-validation time with expected string, received object, confirming that ref objects are not currently accepted in either headers.* or env.vars.*.

OpenClaw version

2026.5.12

Operating system

macOS 26.5 (Darwin 25.5.0, arm64)

Install method

npm global

Model

anthropic/claude-opus-4-7

Provider / routing chain

openclaw -> github MCP (https://api.githubcopilot.com/mcp/, HTTP transport)

Additional provider/model setup details

HTTP MCP. headers.Authorization = "Bearer ${GITHUB_PAT}". GITHUB_PAT exists in ~/.openclaw/.env with a valid GitHub PAT (Contents + Metadata read scopes). Confirmed via direct curl against https://api.githubcopilot.com/mcp/ that the same PAT returns HTTP 200 on tools/initialize when passed in the header explicitly — the issue is not the PAT itself.

Logs, screenshots, and evidence

$ openclaw doctor
warn  Missing env var "GITHUB_PAT" (referenced by mcp.servers.github.headers.Authorization)
$ openclaw config set env.vars.GITHUB_PAT \
    --ref-provider env --ref-source env --ref-id GITHUB_PAT
Error: invalid env.vars.GITHUB_PAT: expected string, received object
$ cat ~/.openclaw/service-env/ai.openclaw.gateway.env | grep -i github
# (no output — var not added by daemon install)

Gateway → MCP request body during agent tool call (relevant header):

Authorization: Bearer ${GITHUB_PAT}

Upstream response:

HTTP/1.1 400 Bad Request
{"error": "Authorization header is badly formatted"}

Impact and severity

Affected: anyone configuring an HTTP MCP server with a secret header via OpenClaw config. Severity: blocks the feature unless the operator maintains an out-of-band workaround. Frequency: 100% of daemon install --force runs wipe the workaround. Consequence: the documented config shape for secret HTTP MCP headers (${VAR} placeholders) does not work; operators must hand-edit service-env/ai.openclaw.gateway.env after every install and re-paste their secrets there.

Additional information

Current workaround in use: hand-append export GITHUB_PAT=… to ~/.openclaw/service-env/ai.openclaw.gateway.env after every daemon install --force. Wiped on the next install. Documented in our internal runbook as a stopgap.

Suggested directions for a fix (not part of grounded evidence):

  • Option A (smaller surface): extend the env-key scanner in the daemon install path to recurse all string values under mcp.servers.* (both headers.* and the stdio env.* block) looking for ${VAR} patterns, union the result with the existing structured-ref env-key set, and write the union into service-env/ai.openclaw.gateway.env.
  • Option B (more invasive): accept the structured {source, provider, id} ref object as a header value in the headers.* schema, and resolve it at request time alongside the existing ref-resolution paths. The parallel env.vars.* validator gap (also rejecting ref objects) is worth addressing in the same change.

Either option would let operators declare secret HTTP MCP headers without an out-of-band hand-edit that gets wiped on every reinstall.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

After step 3, service-env/ai.openclaw.gateway.env contains a GITHUB_PAT=… line (the scanner having resolved the ${GITHUB_PAT} reference in headers.Authorization). The launchd-managed gateway process inherits the var, the MCP authenticates against api.githubcopilot.com, and tool calls succeed.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Bug]: ${VAR} placeholders in mcp.servers.<name>.headers.* are not added to gateway service-env on daemon install