Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/mcp-global-timeouts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": minor
---

Add global default MCP server timeouts in `config.toml` and env vars.
9 changes: 9 additions & 0 deletions docs/en/configuration/config-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,15 @@ In print mode (`kimi -p "<prompt>"`), Kimi Code stays alive after the main agent

`timeout_ms` can be overridden by the `KIMI_SUBAGENT_TIMEOUT_MS` environment variable, which takes higher priority than `config.toml`.

## `mcp`

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `startup_timeout_ms` | `integer` | `30000` (30 seconds) | Global default connection (startup + tool discovery) timeout in milliseconds for all MCP servers. Accepts `1`–`2147483647`. A per-server `startupTimeoutMs` in `mcp.json` always wins over this section and the environment variable; when neither is set, the default applies |
| `tool_timeout_ms` | `integer` | `60000` (60 seconds) | Global default single tool-call timeout in milliseconds for all MCP servers. Accepts `1`–`2147483647`. A per-server `toolTimeoutMs` in `mcp.json` always wins over this section and the environment variable; when neither is set, the client built-in default applies |

`startup_timeout_ms` and `tool_timeout_ms` can be overridden by the `KIMI_MCP_STARTUP_TIMEOUT_MS` and `KIMI_MCP_TOOL_TIMEOUT_MS` environment variables respectively, which take higher priority than `config.toml`. See [MCP](../customization/mcp.md) for the full MCP server configuration.

## `tools`

`tools` is the global tool switch: it applies to every agent in all sessions and intersects with each agent's own `tools` / `disallowedTools` policy.
Expand Down
2 changes: 2 additions & 0 deletions docs/en/configuration/env-vars.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ Switches that control the behavior of subsystems such as telemetry, background t
| `KIMI_CODE_PLUGIN_MARKETPLACE_URL` | Override the plugin marketplace JSON loaded by `/plugins`; useful for dev loopback servers, staging CDN files, or alternate marketplace directories | `https://code.kimi.com/kimi-code/plugins/marketplace.json`; also accepts `http://`, `file://` URLs, and local paths |
| `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` | Cap how many AgentSwarm subagents run concurrently during the initial ramp; leave unset for no cap | Positive integer; invalid values fail fast |
| `KIMI_SUBAGENT_TIMEOUT_MS` | Maximum wall-clock time (ms) a single subagent (`Agent` / `AgentSwarm`) may run; takes higher priority than `[subagent] timeout_ms` in `config.toml` (default `7200000`, i.e. 2 hours) | Positive integer; invalid values fall back to the config or default |
| `KIMI_MCP_STARTUP_TIMEOUT_MS` | Global default connection timeout (ms) for all MCP servers; takes higher priority than `[mcp] startup_timeout_ms` in `config.toml`, but a per-server `startupTimeoutMs` in `mcp.json` still wins (default `30000`) | Integer from `1` to `2147483647`; invalid values are ignored |
| `KIMI_MCP_TOOL_TIMEOUT_MS` | Global default single tool-call timeout (ms) for all MCP servers; takes higher priority than `[mcp] tool_timeout_ms` in `config.toml`, but a per-server `toolTimeoutMs` in `mcp.json` still wins (default `60000`) | Integer from `1` to `2147483647`; invalid values are ignored |
| `KIMI_LOOP_MAX_STEPS_PER_TURN` | Maximum Agent steps per turn; takes higher priority than `[loop_control] max_steps_per_turn` in `config.toml` (unset or `0` means unlimited) | Non-negative integer; invalid values are ignored |
| `KIMI_LOOP_MAX_RETRIES_PER_STEP` | Maximum retries after a step failure; takes higher priority than `[loop_control] max_retries_per_step` in `config.toml` (default `10`) | Non-negative integer; invalid values are ignored |
| `KIMI_CODE_EXPERIMENTAL_FLAG` | Enable all registered experimental features for this process | `1`, `true`, `yes`, `on` |
Expand Down
6 changes: 4 additions & 2 deletions docs/en/customization/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@ Optional fields:
| `headers` | `Record<string, string>` | HTTP, SSE | Static request headers appended to every request |
| `bearerTokenEnvVar` | `string` | HTTP, SSE | Name of an environment variable that contains a bearer token |
| `enabled` | `boolean` | All | Set to `false` to disable this server |
| `startupTimeoutMs` | `number` | All | Connection timeout; default `30000` milliseconds |
| `toolTimeoutMs` | `number` | All | Timeout for a single tool call |
| `startupTimeoutMs` | `number` | All | Connection timeout from `1` to `2147483647` milliseconds; default `30000` |
| `toolTimeoutMs` | `number` | All | Timeout from `1` to `2147483647` milliseconds for a single tool call |
| `enabledTools` | `string[]` | All | Tool allowlist |
| `disabledTools` | `string[]` | All | Tool blocklist |

You do not have to set the connection timeout or the single tool-call timeout per server: `[mcp] startup_timeout_ms` / `[mcp] tool_timeout_ms` in `config.toml` or the `KIMI_MCP_STARTUP_TIMEOUT_MS` / `KIMI_MCP_TOOL_TIMEOUT_MS` environment variables change the global defaults. Precedence is: per-server field > environment variable > `config.toml` > built-in default. See [Configuration files](../configuration/config-files.md#mcp).

HTTP and SSE servers support providing static credentials via `headers` or `bearerTokenEnvVar`. When OAuth is needed, run `/mcp-config login <server-name>` to complete browser-based authorization.

Plugins can also declare MCP servers in their manifest. Servers declared by a plugin are enabled by default and can be disabled or re-enabled in `/plugins`, then a new session must be started. See [Plugins](./plugins.md) for details.
Expand Down
9 changes: 9 additions & 0 deletions docs/zh/configuration/config-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,15 @@ display_name = "Kimi for Coding (custom)"

`timeout_ms` 可被环境变量 `KIMI_SUBAGENT_TIMEOUT_MS` 覆盖,优先级高于配置文件。

## `mcp`

| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `startup_timeout_ms` | `integer` | `30000`(30 秒) | 所有 MCP server 的全局默认连接(启动 + 工具发现)超时(毫秒),取值范围为 `1`–`2147483647`。`mcp.json` 中单个 server 的 `startupTimeoutMs` 始终优先于本节与环境变量;都未设置时使用默认值 |
| `tool_timeout_ms` | `integer` | `60000`(60 秒) | 所有 MCP server 的全局默认单次工具调用超时(毫秒),取值范围为 `1`–`2147483647`。`mcp.json` 中单个 server 的 `toolTimeoutMs` 始终优先于本节与环境变量;都未设置时使用客户端内置默认值 |

`startup_timeout_ms` 和 `tool_timeout_ms` 可分别被环境变量 `KIMI_MCP_STARTUP_TIMEOUT_MS` 和 `KIMI_MCP_TOOL_TIMEOUT_MS` 覆盖,优先级高于配置文件。MCP server 的完整配置方式见 [MCP](../customization/mcp.md)。

## `tools`

`tools` 设置全局工具开关,对所有会话中的每个 Agent 生效,并在 Agent 自身的 `tools` / `disallowedTools` 策略之上再取一次交集。
Expand Down
2 changes: 2 additions & 0 deletions docs/zh/configuration/env-vars.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ kimi
| `KIMI_CODE_PLUGIN_MARKETPLACE_URL` | 覆盖 `/plugins` 加载的 plugin marketplace JSON,适合 dev loopback server、测试 CDN 文件或替换 marketplace 目录 | `https://code.kimi.com/kimi-code/plugins/marketplace.json`;也接受 `http://`、`file://` URL 和本地路径 |
| `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` | 限制 AgentSwarm 初始提升并发阶段可同时运行的子 Agent 数量;不设置表示不限制 | 正整数;非法值会立即失败 |
| `KIMI_SUBAGENT_TIMEOUT_MS` | 单个子 Agent(`Agent` / `AgentSwarm`)可运行的最长时间(毫秒);优先级高于 `config.toml` 的 `[subagent] timeout_ms`(默认 `7200000`,即 2 小时) | 正整数;非法值回退到配置或默认值 |
| `KIMI_MCP_STARTUP_TIMEOUT_MS` | 所有 MCP server 的全局默认连接超时(毫秒);优先级高于 `config.toml` 的 `[mcp] startup_timeout_ms`,但低于 `mcp.json` 中单个 server 的 `startupTimeoutMs`(默认 `30000`) | `1` 到 `2147483647` 的整数;非法值被忽略 |
| `KIMI_MCP_TOOL_TIMEOUT_MS` | 所有 MCP server 的全局默认单次工具调用超时(毫秒);优先级高于 `config.toml` 的 `[mcp] tool_timeout_ms`,但低于 `mcp.json` 中单个 server 的 `toolTimeoutMs`(默认 `60000`) | `1` 到 `2147483647` 的整数;非法值被忽略 |
| `KIMI_LOOP_MAX_STEPS_PER_TURN` | Agent 单轮最大步数;优先级高于 `config.toml` 的 `[loop_control] max_steps_per_turn`(不设或 `0` 表示无上限) | 非负整数;非法值被忽略 |
| `KIMI_LOOP_MAX_RETRIES_PER_STEP` | 单步失败后的最大重试次数;优先级高于 `config.toml` 的 `[loop_control] max_retries_per_step`(默认 `10`) | 非负整数;非法值被忽略 |
| `KIMI_CODE_EXPERIMENTAL_FLAG` | 在当前进程启用所有已注册的实验功能 | `1`、`true`、`yes`、`on` |
Expand Down
6 changes: 4 additions & 2 deletions docs/zh/customization/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@ MCP server 配置写在 `mcp.json` 中,分两层:
| `headers` | `Record<string, string>` | HTTP、SSE | 附加到每次请求的静态请求头 |
| `bearerTokenEnvVar` | `string` | HTTP、SSE | 存放 bearer token 的环境变量名 |
| `enabled` | `boolean` | 全部 | 设为 `false` 可禁用该 server |
| `startupTimeoutMs` | `number` | 全部 | 连接超时,默认 `30000` 毫秒 |
| `toolTimeoutMs` | `number` | 全部 | 单次工具调用超时 |
| `startupTimeoutMs` | `number` | 全部 | 连接超时,取值范围为 `1` 到 `2147483647` 毫秒,默认 `30000` |
| `toolTimeoutMs` | `number` | 全部 | 单次工具调用超时,取值范围为 `1` 到 `2147483647` 毫秒 |
| `enabledTools` | `string[]` | 全部 | 工具白名单 |
| `disabledTools` | `string[]` | 全部 | 工具黑名单 |

连接超时和单次工具调用超时的默认值都不必逐个 server 设置:`config.toml` 的 `[mcp] startup_timeout_ms` / `[mcp] tool_timeout_ms` 或环境变量 `KIMI_MCP_STARTUP_TIMEOUT_MS` / `KIMI_MCP_TOOL_TIMEOUT_MS` 可以调整全局默认值,优先级为 server 字段 > 环境变量 > `config.toml` > 内置默认。详见 [配置文件](../configuration/config-files.md#mcp)。

HTTP 与 SSE server 支持通过 `headers` 或 `bearerTokenEnvVar` 提供静态凭证。需要 OAuth 时,运行 `/mcp-config login <server-name>` 完成浏览器授权。

Plugins 也可以在 manifest 中声明 MCP servers。Plugin 声明的 servers 默认启用,可以在 `/plugins` 中禁用或重新启用,然后开启新会话。详见 [Plugins](./plugins.md)。
Expand Down
17 changes: 16 additions & 1 deletion packages/agent-core-v2/docs/config-manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# commented "# field: type" lines describe the remaining schema fields.
# Values resolve as: default -> config.toml -> env overlay -> memory.

# Index (20 sections · 1 overlay(s))
# Index (21 sections · 1 overlay(s))
# background src/agent/task/configSection.ts
# cron src/app/cron/configSection.ts
# defaultPermissionMode src/agent/permissionMode/configSection.ts
Expand All @@ -19,6 +19,7 @@
# hooks src/agent/externalHooks/configSection.ts
# image src/agent/media/configSection.ts
# loopControl src/agent/loop/configSection.ts
# mcp src/agent/mcp/configSection.ts
# mergeAllAvailableSkills src/app/skillCatalog/configSection.ts
# modelCatalog src/app/kosongConfig/configSection.ts
# models src/app/kosongConfig/configSection.ts
Expand Down Expand Up @@ -161,6 +162,20 @@ extra_skill_dirs = []
# reserved_context_size: integer
# compaction_trigger_ratio: number

# ##########################################################################
# mcp
# owner: src/agent/mcp/configSection.ts
# scope: core
# hooks: stripEnv
# env:
# startup_timeout_ms <- KIMI_MCP_STARTUP_TIMEOUT_MS (custom parse)
# tool_timeout_ms <- KIMI_MCP_TOOL_TIMEOUT_MS (custom parse)
# ##########################################################################

[mcp]
# startup_timeout_ms: integer
# tool_timeout_ms: integer

# ##########################################################################
# mergeAllAvailableSkills (config.toml: merge_all_available_skills)
# owner: src/app/skillCatalog/configSection.ts
Expand Down
13 changes: 11 additions & 2 deletions packages/agent-core-v2/src/agent/mcp/client-http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type { MCPClient, MCPToolDefinition, MCPToolResult } from './types';
export interface HttpMcpClientOptions {
readonly clientName?: string;
readonly clientVersion?: string;
readonly startupTimeoutMs?: number;
readonly toolCallTimeoutMs?: number;
readonly envLookup?: (name: string) => string | undefined;
readonly fetch?: typeof fetch;
Expand All @@ -28,6 +29,7 @@ export interface HttpMcpClientOptions {
export class HttpMcpClient implements MCPClient {
private readonly client: Client;
private readonly transport: StreamableHTTPClientTransport;
private readonly startupTimeoutMs?: number;
private readonly toolCallTimeoutMs?: number;
private started = false;
private closed = false;
Expand All @@ -51,6 +53,7 @@ export class HttpMcpClient implements MCPClient {
name: options.clientName ?? KIMI_MCP_CLIENT_NAME,
version: options.clientVersion ?? KIMI_MCP_CLIENT_VERSION,
});
this.startupTimeoutMs = options.startupTimeoutMs;
this.toolCallTimeoutMs = options.toolCallTimeoutMs;
}

Expand All @@ -62,7 +65,10 @@ export class HttpMcpClient implements MCPClient {
this.started = true;
this.installTransportHooks();
try {
await this.client.connect(this.transport);
await this.client.connect(
this.transport,
buildRequestOptions(this.startupTimeoutMs, undefined),
);
} catch (error) {
await this.closeStartedClient();
throw error;
Expand Down Expand Up @@ -90,7 +96,10 @@ export class HttpMcpClient implements MCPClient {
}

async listTools(): Promise<MCPToolDefinition[]> {
const result = await this.client.listTools();
const result = await this.client.listTools(
undefined,
buildRequestOptions(this.startupTimeoutMs, undefined),
);
return result.tools.map(toMcpToolDefinition);
}

Expand Down
6 changes: 3 additions & 3 deletions packages/agent-core-v2/src/agent/mcp/client-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ export interface McpRequestOptions {
}

export function buildRequestOptions(
toolCallTimeoutMs: number | undefined,
timeoutMs: number | undefined,
signal: AbortSignal | undefined,
): McpRequestOptions | undefined {
if (toolCallTimeoutMs === undefined && signal === undefined) return undefined;
return { timeout: toolCallTimeoutMs, signal };
if (timeoutMs === undefined && signal === undefined) return undefined;
return { timeout: timeoutMs, signal };
}

interface SdkListedTool {
Expand Down
13 changes: 11 additions & 2 deletions packages/agent-core-v2/src/agent/mcp/client-sse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type { MCPClient, MCPToolDefinition, MCPToolResult } from './types';
export interface SseMcpClientOptions {
readonly clientName?: string;
readonly clientVersion?: string;
readonly startupTimeoutMs?: number;
readonly toolCallTimeoutMs?: number;
readonly envLookup?: (name: string) => string | undefined;
readonly fetch?: typeof fetch;
Expand All @@ -28,6 +29,7 @@ export interface SseMcpClientOptions {
export class SseMcpClient implements MCPClient {
private readonly client: Client;
private readonly transport: SSEClientTransport;
private readonly startupTimeoutMs?: number;
private readonly toolCallTimeoutMs?: number;
private started = false;
private closed = false;
Expand All @@ -51,6 +53,7 @@ export class SseMcpClient implements MCPClient {
name: options.clientName ?? KIMI_MCP_CLIENT_NAME,
version: options.clientVersion ?? KIMI_MCP_CLIENT_VERSION,
});
this.startupTimeoutMs = options.startupTimeoutMs;
this.toolCallTimeoutMs = options.toolCallTimeoutMs;
}

Expand All @@ -62,7 +65,10 @@ export class SseMcpClient implements MCPClient {
this.started = true;
this.installTransportHooks();
try {
await this.client.connect(this.transport);
await this.client.connect(
this.transport,
buildRequestOptions(this.startupTimeoutMs, undefined),
);
} catch (error) {
await this.closeStartedClient();
throw error;
Expand Down Expand Up @@ -90,7 +96,10 @@ export class SseMcpClient implements MCPClient {
}

async listTools(): Promise<MCPToolDefinition[]> {
const result = await this.client.listTools();
const result = await this.client.listTools(
undefined,
buildRequestOptions(this.startupTimeoutMs, undefined),
);
return result.tools.map(toMcpToolDefinition);
}

Expand Down
13 changes: 11 additions & 2 deletions packages/agent-core-v2/src/agent/mcp/client-stdio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type { MCPClient, MCPToolDefinition, MCPToolResult } from './types';
export interface StdioMcpClientOptions {
readonly clientName?: string;
readonly clientVersion?: string;
readonly startupTimeoutMs?: number;
readonly toolCallTimeoutMs?: number;
readonly defaultCwd?: string;
}
Expand All @@ -29,6 +30,7 @@ const STDERR_BUFFER_CAPACITY = 4 * 1024;
export class StdioMcpClient implements MCPClient {
private readonly client: Client;
private readonly transport: StdioClientTransport;
private readonly startupTimeoutMs?: number;
private readonly toolCallTimeoutMs?: number;
private readonly stderrBuffer = new BoundedTail(STDERR_BUFFER_CAPACITY);
private started = false;
Expand Down Expand Up @@ -59,6 +61,7 @@ export class StdioMcpClient implements MCPClient {
name: options.clientName ?? KIMI_MCP_CLIENT_NAME,
version: options.clientVersion ?? KIMI_MCP_CLIENT_VERSION,
});
this.startupTimeoutMs = options.startupTimeoutMs;
this.toolCallTimeoutMs = options.toolCallTimeoutMs;
}

Expand All @@ -70,7 +73,10 @@ export class StdioMcpClient implements MCPClient {
this.started = true;
this.installTransportHooks();
try {
await this.client.connect(this.transport);
await this.client.connect(
this.transport,
buildRequestOptions(this.startupTimeoutMs, undefined),
);
} catch (error) {
await this.closeStartedClient();
throw error;
Expand Down Expand Up @@ -102,7 +108,10 @@ export class StdioMcpClient implements MCPClient {
}

async listTools(): Promise<MCPToolDefinition[]> {
const result = await this.client.listTools();
const result = await this.client.listTools(
undefined,
buildRequestOptions(this.startupTimeoutMs, undefined),
);
return result.tools.map(toMcpToolDefinition);
}

Expand Down
7 changes: 5 additions & 2 deletions packages/agent-core-v2/src/agent/mcp/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ import { z } from 'zod';

const StringRecordSchema = z.record(z.string(), z.string());

export const MAX_MCP_TIMEOUT_MS = 2_147_483_647;
export const McpTimeoutMsSchema = z.number().int().min(1).max(MAX_MCP_TIMEOUT_MS);

const McpServerCommonFields = {
enabled: z.boolean().optional(),
startupTimeoutMs: z.number().int().min(1).optional(),
toolTimeoutMs: z.number().int().min(1).optional(),
startupTimeoutMs: McpTimeoutMsSchema.optional(),
toolTimeoutMs: McpTimeoutMsSchema.optional(),
enabledTools: z.array(z.string()).optional(),
disabledTools: z.array(z.string()).optional(),
} as const;
Expand Down
44 changes: 44 additions & 0 deletions packages/agent-core-v2/src/agent/mcp/configSection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* `mcp` domain (L5) — registers MCP timeout preferences into `config`.
*
* Owns the global MCP startup and tool-call timeout preferences, including
* their environment bindings and persistence guard. Registered into `config`
* at module load. Bound at App scope.
*/

import { z } from 'zod';

import { type EnvBindings, envBindings, stripEnvBoundFields } from '#/app/config/config';
import { registerConfigSection } from '#/app/config/configSectionContributions';
import { MAX_MCP_TIMEOUT_MS, McpTimeoutMsSchema } from './config-schema';

export const MCP_SECTION = 'mcp';

export const McpSectionSchema = z.object({
startupTimeoutMs: McpTimeoutMsSchema.optional(),
toolTimeoutMs: McpTimeoutMsSchema.optional(),
});

export type McpSection = z.infer<typeof McpSectionSchema>;

export const MCP_STARTUP_TIMEOUT_ENV = 'KIMI_MCP_STARTUP_TIMEOUT_MS';
export const MCP_TOOL_TIMEOUT_ENV = 'KIMI_MCP_TOOL_TIMEOUT_MS';

function parseTimeoutMsEnv(raw: string): number | undefined {
const parsed = Number(raw);
return Number.isInteger(parsed) && parsed >= 1 && parsed <= MAX_MCP_TIMEOUT_MS
? parsed
: undefined;
}

export const mcpEnvBindings: EnvBindings<McpSection> = envBindings(McpSectionSchema, {
startupTimeoutMs: { env: MCP_STARTUP_TIMEOUT_ENV, parse: parseTimeoutMsEnv },
toolTimeoutMs: { env: MCP_TOOL_TIMEOUT_ENV, parse: parseTimeoutMsEnv },
});

export const stripMcpEnv = stripEnvBoundFields(mcpEnvBindings);

registerConfigSection(MCP_SECTION, McpSectionSchema, {
env: mcpEnvBindings,
stripEnv: stripMcpEnv,
});
Loading
Loading