fix(mcp): keep numeric bundle tool names provider-safe

This commit is contained in:
Peter Steinberger
2026-05-10 06:29:04 +01:00
parent 66a8ff178c
commit f43dc9aa61
4 changed files with 20 additions and 2 deletions

View File

@@ -67,6 +67,7 @@ Docs: https://docs.openclaw.ai
- Models/OpenRouter: hide missing-auth direct provider rows in `/model status` when they are only duplicated by a nested OpenRouter model id such as `openrouter/google/...`, while preserving explicitly configured direct providers. Fixes #62317.
- Models: preserve an explicitly selected provider/model such as `opencode-go/deepseek-v4-pro` when another provider owns the same bare model alias. Fixes #79325.
- Models/config: explain missing `models.providers.<provider>.models[]` registration when a model exists only in `agents.defaults.models`, instead of returning a bare unknown-model error. Fixes #80089.
- MCP/tools: prefix bundle MCP server/tool fragments that would start with digits, keeping generated tool names valid for Moonshot/Kimi and other strict providers. Fixes #79179.
- Kimi Code: use Kimi's stable `kimi-for-coding` API model id in bundled catalog, onboarding, and docs while normalizing legacy `kimi-code` and `k2p5` refs. Fixes #79965.
- Volcengine/Kimi: strip provider-unsupported tool schema length and item constraint keywords for direct and coding-plan models so hosted Kimi runs do not reject message tools with `minLength`. Fixes #38817.
- DeepSeek: backfill V4 `reasoning_content` replay fields for unowned OpenAI-compatible proxy providers, preventing follow-up request failures outside the bundled DeepSeek and OpenRouter routes. Fixes #79608.

View File

@@ -165,6 +165,8 @@ OpenClaw registers bundle MCP tools with provider-safe names in the form
`memory_search` tool registers as `vigil-harbor__memory_search`.
- characters outside `A-Za-z0-9_-` are replaced with `-`
- fragments that would start with a non-letter get a letter prefix, so numeric
server keys such as `12306` become provider-safe tool prefixes
- server prefixes are capped at 30 characters
- full tool names are capped at 64 characters
- empty server names fall back to `mcp`

View File

@@ -14,6 +14,20 @@ describe("pi bundle MCP names", () => {
expect(sanitizeServerName("vigil:harbor", usedNames)).toBe("vigil-harbor-2");
});
it("keeps server and tool fragments provider-safe when they start with digits", () => {
const usedNames = new Set<string>();
const serverName = sanitizeServerName("12306", usedNames);
expect(serverName).toBe("mcp-12306");
expect(
buildSafeToolName({
serverName,
toolName: "2024-query",
reservedNames: new Set(),
}),
).toBe(`mcp-12306${TOOL_NAME_SEPARATOR}tool-2024-query`);
});
it("builds provider-safe tool names and avoids collisions", () => {
const reservedNames = normalizeReservedToolNames(["memory__status"]);

View File

@@ -11,10 +11,11 @@ const TOOL_NAME_MAX_TOTAL = 64;
function sanitizeToolFragment(raw: string, fallback: string, maxChars?: number): string {
const cleaned = raw.trim().replace(TOOL_NAME_SAFE_RE, "-");
const normalized = cleaned || fallback;
const providerSafe = /^[A-Za-z]/.test(normalized) ? normalized : `${fallback}-${normalized}`;
if (!maxChars) {
return normalized;
return providerSafe;
}
return normalized.length > maxChars ? normalized.slice(0, maxChars) : normalized;
return providerSafe.length > maxChars ? providerSafe.slice(0, maxChars) : providerSafe;
}
export function sanitizeServerName(raw: string, usedNames: Set<string>): string {