authorgravatar for electricvoxel@gmail.comHwanseo Choi <electricvoxel@gmail.com> 2026-08-05 12:03:15+09:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-04 23:03:15-04:00
log3d429662c9bd7b731c059dc3a84ccdfc43bf3701
treee0604021d570cc34e6c5f643562ce07b25a9e6c0
parent7b38fb5c6b0fb46a7dadaf33e1739726be3dc104
signature Signed by PGP key B5690EEEBB952194

fix(mcp): unblock Kimi models in OpenCode with preview tools (#5128)


2 files changed, 22 insertions(+), 11 deletions(-)

apps/server/src/mcp/toolkits/preview/tools.test.ts+16
......@@ -12,6 +12,19 @@ const schemaHasDescription = (schema: unknown): boolean => {
1212 .some((members) => members.some(schemaHasDescription));
1313};
1414
15const schemaHasMultipleAllOfDescriptions = (schema: unknown): boolean => {
16 if (!schema || typeof schema !== "object") return false;
17 const record = schema as Record<string, unknown>;
18 const allOf = Array.isArray(record.allOf) ? record.allOf : [];
19 const descriptionCount = allOf.filter(
20 (member) =>
21 member !== null &&
22 typeof member === "object" &&
23 typeof (member as Record<string, unknown>).description === "string",
24 ).length;
25 return descriptionCount > 1 || Object.values(record).some(schemaHasMultipleAllOfDescriptions);
26};
27
1528it("exports provider-compatible object schemas with described parameters", () => {
1629 for (const tool of Object.values(PreviewToolkit.tools)) {
1730 const schema = Tool.getJsonSchema(tool) as {
......@@ -27,6 +40,9 @@ it("exports provider-compatible object schemas with described parameters", () =>
2740 expect(schema.type, `${tool.name} must export a top-level object schema`).toBe("object");
2841 expect(schema.anyOf, `${tool.name} must not export a root anyOf`).toBeUndefined();
2942 expect(schema.oneOf, `${tool.name} must not export a root oneOf`).toBeUndefined();
43 if (tool.name === "preview_navigate") {
44 expect(schemaHasMultipleAllOfDescriptions(schema)).toBe(false);
45 }
3046 expect(
3147 schema.properties?.tabId,
3248 `${tool.name} must allow an explicit collaborative browser tab target`,
packages/contracts/src/previewAutomation.ts+6-11
......@@ -12,13 +12,10 @@ import {
1212import { ProviderInstanceId } from "./providerInstance.ts";
1313
1414const BoundedUrl = Schema.String.check(Schema.isTrimmed())
15 .check(
16 Schema.isNonEmpty({
17 description:
18 "Absolute http(s) URL or a schemeless host such as t3.chat or localhost:5173. Schemeless public hosts use https; loopback hosts use http.",
19 }),
20 )
15 .check(Schema.isNonEmpty())
2116 .check(Schema.isMaxLength(2048));
17const URL_GUIDANCE =
18 "Absolute http(s) URL or a schemeless host such as t3.chat or localhost:5173. Schemeless public hosts use https; loopback hosts use http.";
2219const OptionalTimeoutMs = Schema.optional(
2320 Schema.Int.check(Schema.isGreaterThan(0))
2421 .check(Schema.isLessThanOrEqualTo(60_000))
......@@ -83,8 +80,7 @@ export type PreviewAutomationStatus = typeof PreviewAutomationStatus.Type;
8380export const PreviewAutomationOpenInput = Schema.Struct({
8481 ...PreviewAutomationTabTargetFields,
8582 url: Schema.optional(BoundedUrl).annotate({
86 description:
87 "Optional initial page URL, for example https://t3.chat or localhost:5173. Omit to open a blank tab.",
83 description: `Optional initial page URL. ${URL_GUIDANCE} Omit to open a blank tab.`,
8884 }),
8985 open: Schema.optional(
9086 Schema.Boolean.annotate({
......@@ -124,7 +120,7 @@ export const BrowserNavigationTarget = Schema.Union([
124120 description: "Selects direct URL navigation.",
125121 }),
126122 url: BoundedUrl.annotate({
127 description: "Direct website URL.",
123 description: `Direct website URL. ${URL_GUIDANCE}`,
128124 }),
129125 }),
130126 Schema.Struct({
......@@ -151,8 +147,7 @@ export type BrowserNavigationTarget = typeof BrowserNavigationTarget.Type;
151147export const PreviewAutomationNavigateInput = Schema.Struct({
152148 ...PreviewAutomationTabTargetFields,
153149 url: Schema.optional(BoundedUrl).annotate({
154 description:
155 "Website URL, for example https://t3.chat. Use this for public pages and directly reachable URLs.",
150 description: `Website URL. ${URL_GUIDANCE} Use this for public pages and directly reachable URLs.`,
156151 }),
157152 target: Schema.optional(
158153 BrowserNavigationTarget.annotate({