upstash/context7 · error

Unterminated TOML array in MCP args

Error message

Unterminated TOML array in MCP args

What it means

Thrown by parseTomlStringArray when the loop over the args array runs off the end of the file without ever seeing the closing `]`. It is a safety guard: the byte-preserving TOML editor refuses to rewrite an array it cannot fully delimit, since splicing at the wrong offset would corrupt the config.

Solutions

  1. Open the TOML file and add the missing closing `]` at the end of the args array
  2. Check for merge-conflict markers (<<<<<<< / >>>>>>>) inside or right after the array and resolve them
  3. If the file looks truncated, restore it from version control or re-run the CLI setup to regenerate the server entry

Example fix

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

Strategy: validation

Validate before calling

const open = (raw.match(/\[/g) || []).length;
const close = (raw.match(/\]/g) || []).length;
if (open !== close) throw new Error("Unbalanced brackets in TOML file");

Try / catch

try {
  await patchTomlStdioApiKey(tomlPath, serverName, apiKey);
} catch (e) {
  if (e.message.includes("Unterminated TOML array")) {
    console.error(`${tomlPath} has an unclosed args array — restore from git or fix manually`);
    // offer: await restoreFromGit(tomlPath)
  }
}

Prevention

When it happens

Trigger: Calling patchTomlStdioApiKey on a config where the `[mcp_servers.<name>]` args array has an opening `[` but no matching `]` anywhere after it — e.g. `args = ["-y",` at end of file, or the closing bracket was deleted during manual editing or a bad merge.

Common situations: Files truncated by an interrupted write, merge conflicts where the closing bracket ended up inside conflict markers, or users hand-deleting the last line of the array.

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/8b839d8488bf071f. Report an issue: GitHub.

Appendix: source

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

    }
    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;

  const bodyStart = raw.indexOf("\n", header.index + header[0].length) + 1;
  const effectiveBodyStart = bodyStart === 0 ? raw.length : bodyStart;

View on GitHub (pinned to 4416fb855b)