Summary
An unauthenticated text tool call returns ANSI color sequences in its MCP text result even when NO_COLOR=1 is set. This contradicts the CLI's documented color setting and also occurs with the color-disabled child environment created by ai mcp. The JSON-RPC reply remains parseable and correctly sets isError: true; the observed defect concerns diagnostic presentation.
Steps to reproduce
With the released CLI from Runtime or environment on PATH, run this Python script. It starts the CLI with an isolated home and working directory, an allowlisted environment with no authentication variables, NO_COLOR=1, and no FORCE_COLOR. It sends an initialized MCP text call, then closes stdin. The CLI may read the public model catalog; no credentials or successful inference are needed.
import json
import os
import pathlib
import shutil
import subprocess
import tempfile
cli = shutil.which("ai")
node = shutil.which("node")
assert cli and node
requests = [
{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {
"protocolVersion": "2025-11-25", "capabilities": {},
"clientInfo": {"name": "color-probe", "version": "1.0.0"}}},
{"jsonrpc": "2.0", "method": "notifications/initialized"},
{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {
"name": "text", "arguments": {
"prompt": "Reply OK.", "model": "openai/gpt-4o-mini",
"output": "result.txt", "timeoutMs": 15000}}},
]
with tempfile.TemporaryDirectory() as work:
home = pathlib.Path(work) / "home"
home.mkdir()
env = {
"PATH": os.path.dirname(node) + os.pathsep + "/usr/bin:/bin",
"HOME": str(home), "XDG_CONFIG_HOME": str(home / "config"),
"NO_COLOR": "1", "TERM": "dumb", "TMPDIR": work,
}
for production in (False, True):
child_env = dict(env)
if production:
child_env["NODE_ENV"] = "production"
run = subprocess.run(
[node, os.path.realpath(cli), "mcp", "--profile", "core"],
input="".join(json.dumps(r) + "\n" for r in requests),
text=True, capture_output=True, cwd=work, env=child_env,
timeout=25,
)
replies = [json.loads(line) for line in run.stdout.splitlines()]
result = next(r["result"] for r in replies if r.get("id") == 2)
text = result["content"][0]["text"]
print(json.dumps({
"production": production, "exitCode": run.returncode,
"isError": result.get("isError"),
"escapeCount": text.count("\x1b"), "text": text,
}))Expected behavior
NO_COLOR disables ANSI color output, including the diagnostic returned by the MCP tool. Missing authentication should still produce an error result with readable authentication guidance.
Actual behavior
The default-environment run returned seven U+001B characters in the text field. The beginning of that field, JSON-escaped to expose the bytes, was:
"Error: \u001b[1m\u001b[31mUnauthenticated request to AI Gateway.\u001b[0m\n\nTo authenticate, set the \u001b[33mAI_GATEWAY_API_KEY\u001b[0m environment variable with your API key."The production-environment control returned zero escape characters and the shorter diagnostic beginning Error: Unauthenticated. Configure AI_GATEWAY_API_KEY or use a provider module. Both runs returned isError: true, the MCP server exited with status 0 after EOF, and no output artifact was created. The script was run once for each environment; an earlier equivalent isolated probe returned the same results. Successful generation was not tested.
Runtime or environment
- Executed:
ai-cli0.8.0, distributed dependencyai7.0.139 and@ai-sdk/gateway4.0.112, Node.js v26.12.1, macOS arm64. - Release source:
bd9d87a8ead2ff247b669fc6d4bcac90e8d96353. - Current CLI
maininspected:20592fdd6deb68e09856f675a54e685b05b02226, declaring 0.8.1. It was not built or executed. The MCP implementation, text implementation, color documentation, and pinned SDK dependencies are unchanged from the release. - The latest published
aipackage, 7.0.162, was inspected as a distribution artifact, without installing or executing it. Its relevant wrapper still contains the same unconditional development-mode ANSI literals.
Evidence
- Expected source: The released configuration reference documents
NO_COLORas disabling ANSI color output. - Failure source: The executed script above and the JSON-escaped diagnostic in Actual behavior show that this setting leaves seven escape characters in the MCP text result.
- Evidence provenance: observed
- Local verification: reproduced
- Reproduction completeness: complete
The released MCP child setup sets NO_COLOR=1 and deletes FORCE_COLOR. Its result mapping places the child diagnostic in the text content.
The color originates in AI SDK's wrapGatewayError, rather than the CLI's color helper. The current SDK source chooses between a plain production message and an explicitly colored development message without checking NO_COLOR. The same wrapper was inspected in the executed dependency and the latest distribution. The SDK's development styling is intentional; this report concerns the CLI's documented NO_COLOR behavior at its MCP boundary and does not prescribe which component should implement the correction.
Restoration check
Repeat the default-environment MCP call with NO_COLOR=1. Its decoded text should contain zero ANSI color sequences while preserving isError: true, parseable JSON-RPC, and useful missing-authentication guidance. Keep the authentication failure observable; suppressing the diagnostic or returning success would not restore this contract.
Co-contributor credit
No, do not credit me.
Checklist
- I have searched existing issues for duplicates.
- I have removed API keys, tokens, credentials, and private data from this report.
Triage assessment
- Impact level: P3
- Assessment status: supported
- Impact basis: The decoded MCP diagnostic contains ANSI presentation bytes despite the documented color setting. The reply remains parseable and reports the expected authentication error; no functional failure from the ANSI sequences was established.
- Workaround status: available
- Workaround basis: The executed production-environment control returned a readable authentication error with zero escape characters. This observation is limited to this diagnostic; it does not establish that changing NODE_ENV is appropriate for every CLI workflow.
Activity
0No activity yet.