upstash/context7 · error

Expected a comma or closing bracket in MCP args

Error message

Expected a comma or closing bracket in MCP args

What it means

This error is thrown by the hand-rolled TOML string-array parser in parseTomlStringArray when, after parsing a string element inside an `args = [...]` array of an MCP server entry, the next meaningful character is neither a comma nor the closing `]`. The parser exists so the CLI can surgically edit a config file without a full TOML parser; it only accepts the strict shape `args = ["a", "b"]` and throws on anything it cannot safely rewrite byte-for-byte.

Solutions

  1. Open the TOML file and add a comma between every two array elements in the args line
  2. Ensure the args array ends with `]` immediately after the last element (only whitespace/comments allowed before it)
  3. Remove any non-string elements (numbers, booleans, sub-tables) from the args array — the editor only supports arrays of strings
  4. Regenerate the server entry with the CLI's setup command to get a canonical args line

Example fix

// before (invalid TOML array syntax)
args = ["-y" "@context7/mcp"]
// after
args = ["-y", "@context7/mcp"]
Defensive patterns

Strategy: validation

Validate before calling

const argsLine = raw.match(/^[\t ]*args[\t ]*=[\t ]*\[[^\]]*\]/m);
if (!argsLine || !/"|'|,|\s*\]/.test(argsLine[0]) || /["']\s+["']/.test(argsLine[0].slice(1, -1))) {
  throw new Error("args array is malformed: missing comma or bad separator");
}

Type guard

function hasWellFormedArgsArray(toml: string): boolean {
  const m = toml.match(/^[\t ]*args[\t ]*=[\t ]*(\[[^\]]*\])/m);
  return !!m && m[1].split("[")[1].trim() !== "" ? /^[^\]]*,[^\]]*$|^\s*$|^\[[^\]]*,.*\]$/.test(m[1]) || !/["']\s+["']/.test(m[1]) : true;
}

Try / catch

try {
  await patchTomlStdioApiKey(tomlPath, serverName, apiKey);
} catch (e) {
  if (e.message.includes("comma or closing bracket")) {
    console.error(`Malformed args array in ${tomlPath}: fix commas/brackets manually`, e);
  }
}

Prevention

When it happens

Trigger: Calling patchTomlStdioApiKey on a TOML file whose `[mcp_servers.<name>]` body has an args array with two adjacent string values and no comma (e.g. `args = ["x" "y"]`), a trailing element followed by a non-bracket character (e.g. a stray identifier or number like `args = ["x", -y]`), or a misplaced character after skipping whitespace/comments.

Common situations: Hand-edited or tool-generated configs using a non-standard TOML dialect (e.g. space-separated lists copied from JSON-without-commas or another format), merge conflicts that dropped commas, or truncated files that mangle the array separator.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of upstash/context7@4416fb855b (2026-09-16). Data as JSON: /api/errors/592c7e5fad348715. Report an issue: GitHub.

Appendix: source

Thrown at packages/cli/src/setup/toml-editor.ts:112

    const quote = source[index];
    if (quote !== '"' && quote !== "'") {
      throw new Error("MCP args must be a TOML array containing only strings");
    }
    if (source.slice(index, index + 3) === quote.repeat(3)) {
      throw new Error("Multiline strings are not supported in MCP args");
    }

    const token =
      quote === '"' ? parseTomlBasicString(source, index) : parseTomlLiteralString(source, index);
    tokens.push(token);
    index = skipTomlArrayTrivia(source, token.end);

    if (source[index] === ",") {
      index++;
      continue;
    }
    if (source[index] !== "]") {
      throw new Error("Expected a comma or closing bracket in MCP args");
    }
  }
  throw new Error("Unterminated TOML array in MCP args");
}

function findTomlServerArgs(
  raw: string,
  serverName: string
): { start: number; end: number; tokens: TomlStringToken[] } | null {
  const escapedName = serverName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
  const tableKey = `(?:mcp_servers|"mcp_servers"|'mcp_servers')`;
  const serverKey = `(?:${escapedName}|"${escapedName}"|'${escapedName}')`;
  const headerRe = new RegExp(
    `^[\\uFEFF\\t ]*\\[[\\t ]*${tableKey}[\\t ]*\\.[\\t ]*${serverKey}[\\t ]*\\][\\t ]*(?:#.*)?\\r?$`,
    "m"
  );
  const header = headerRe.exec(raw);
  if (!header) return null;

View on GitHub (pinned to 4416fb855b)