vercel/ai · error
Claude Code MCP server name "harness-tools" is reserved for
Error message
Claude Code MCP server name "harness-tools" is reserved for HarnessAgent tools.
What it means
`createClaudeCode` reserves the MCP server key `harness-tools` for the tools the HarnessAgent itself injects into the Claude Code session. If `settings.mcpServers` contains a property named `harness-tools`, the harness throws immediately to prevent a collision between user-supplied and built-in tools.
Source
Thrown at packages/harness-claude-code/src/claude-code-harness.ts:827
* relying on the SDK's `continue` flag — "most recent thread in this
* workdir" — which silently picks the wrong one once a second thread
* exists there. Hosts that captured the id themselves (it is surfaced as
* `harnessMetadata['claude-code'].sessionId` on `finish` parts) may also
* set it explicitly.
*/
claudeSessionId: z.string().optional(),
});
type ClaudeCodeBridgeCoords = z.infer<typeof claudeCodeBridgeCoordsSchema>;
export function createClaudeCode(
settings: ClaudeCodeHarnessSettings = {},
): HarnessV1<typeof CLAUDE_CODE_BUILTIN_TOOLS> {
if (
settings.mcpServers != null &&
Object.prototype.hasOwnProperty.call(settings.mcpServers, 'harness-tools')
) {
throw new Error(
'Claude Code MCP server name "harness-tools" is reserved for HarnessAgent tools.',
);
}
const thinking = settings.thinking ?? {
type: 'adaptive',
display: 'summarized',
};
return {
specificationVersion: 'harness-v1',
harnessId: 'claude-code',
builtinTools: CLAUDE_CODE_BUILTIN_TOOLS,
supportsBuiltinToolApprovals: true,
supportsBuiltinToolFiltering: true,
lifecycleStateSchema: claudeCodeResumeStateSchema,
getBootstrap: getClaudeCodeBootstrap,
doStart: async startOpts => {
const sandboxSession = startOpts.sandboxSession;View on GitHub (pinned to 69428b1f8b)
Solutions
- Rename your MCP server entry to any other key, e.g. `my-tools`, in `settings.mcpServers`.
- Delete the `harness-tools` key if it was added by a shared/merged config; harness built-in tools are provided automatically and need no manual registration.
- Sanitize merged config objects: `const { 'harness-tools': _, ...mcpServers } = merged` before passing to `createClaudeCode`.
- If you actually intended to expose harness tools, rely on the built-in `CLAUDE_CODE_BUILTIN_TOOLS` instead of registering an MCP server.
Example fix
// before
createClaudeCode({ mcpServers: { 'harness-tools': { command: './my-tools' } } });
// after
createClaudeCode({ mcpServers: { 'my-tools': { command: './my-tools' } } }); Defensive patterns
Strategy: validation
Validate before calling
function assertNoReservedMcpServers(settings) {
if (settings.mcpServers != null &&
Object.prototype.hasOwnProperty.call(settings.mcpServers, 'harness-tools')) {
throw new TypeError('mcpServers must not contain the reserved key "harness-tools"');
}
}
assertNoReservedMcpServers(settings); Type guard
function hasReservedMcpServer(settings) {
return settings.mcpServers != null &&
Object.prototype.hasOwnProperty.call(settings.mcpServers, 'harness-tools');
} Try / catch
try {
const harness = createClaudeCode(settings);
} catch (err) {
if (err instanceof Error && err.message.includes('"harness-tools" is reserved')) {
const { 'harness-tools': _, ...mcpServers } = settings.mcpServers ?? {};
return createClaudeCode({ ...settings, mcpServers });
}
throw err;
} Prevention
- Never name a user MCP server 'harness-tools'; treat it as reserved
- Sanitize merged/shared MCP config objects by stripping the reserved key
- Rely on CLAUDE_CODE_BUILTIN_TOOLS instead of re-registering harness tools
When it happens
Trigger: Calling `createClaudeCode({ mcpServers: { 'harness-tools': {...} } })` — i.e. any settings object whose `mcpServers` record has its own `harness-tools` property (detected via `Object.prototype.hasOwnProperty`, so even `hasOwnProperty`-true inherited-style keys and explicit `undefined` values trigger it).
Common situations: Reusing a shared MCP server config object across harnesses where another setup already used the reserved name; copy-pasting example config that registered `harness-tools` manually; merging user MCP servers with defaults that include the reserved key.
Related errors
- ACP MCP server name "ai-sdk-harness-tools" is reserved for H
- ACP MCP server name "ai-sdk-harness-tools" is reserved for H
- ACP MCP server ${JSON.stringify(name)} must be configured wi
- ACP-transport MCP servers require client-side mcp/connect ha
- The Claude Code harness cannot use `mintBridgeToken` with a
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/ad0b625ada9085a7.
Report an issue: GitHub.