diff --git a/docs/http-mcp.md b/docs/http-mcp.md index c44933f..5dcdf9c 100644 --- a/docs/http-mcp.md +++ b/docs/http-mcp.md @@ -37,6 +37,11 @@ External tools are stateless and do not share the internal research turn's 12-request budget. No tool writes to an SNS account. Tool failures return `isError: true` and a structured error in text content. +Tool input schemas must also work with non-JavaScript JSON Schema validators. +Mastodon hashtag character restrictions remain enforced by the server and are +described in the schema, without exporting JavaScript Unicode property escapes +as a `pattern` that Python JSON Schema validators reject. + Activity publication uses the same service as Home and Messages. Exact retries return the original receipt before revision checks; conflicting publications make no changes. Browser clients refresh on committed changes through the diff --git a/src/features/platforms/mastodon-source.test.ts b/src/features/platforms/mastodon-source.test.ts new file mode 100644 index 0000000..a1b27e0 --- /dev/null +++ b/src/features/platforms/mastodon-source.test.ts @@ -0,0 +1,34 @@ +import { expect, it } from "vitest"; +import { z } from "zod"; +import { mastodonSourceSchema } from "./mastodon-source"; + +it.each(["日本語_123", "café", "AB12", " hello_world "])( + "accepts Unicode hashtag %s", + (target) => { + expect(mastodonSourceSchema.parse({ platform: "mastodon", kind: "hashtag", target })).toEqual({ + platform: "mastodon", + kind: "hashtag", + target: target.trim(), + }); + }, +); + +it.each(["", " ", "#tag", "two words", "tag-name", "😀", "a".repeat(129)])( + "rejects invalid hashtag %s", + (target) => { + expect( + mastodonSourceSchema.safeParse({ platform: "mastodon", kind: "hashtag", target }).success, + ).toBe(false); + }, +); + +it("describes hashtag constraints without requiring Unicode regex support in MCP clients", () => { + const schema = z.toJSONSchema(mastodonSourceSchema.options[2].shape.target, { io: "input" }); + expect(schema).toEqual({ + $schema: "https://json-schema.org/draft/2020-12/schema", + type: "string", + minLength: 1, + maxLength: 128, + description: "Hashtag without #, containing only Unicode letters, numbers, and underscores.", + }); +}); diff --git a/src/features/platforms/mastodon-source.ts b/src/features/platforms/mastodon-source.ts index c2c2100..b9353e9 100644 --- a/src/features/platforms/mastodon-source.ts +++ b/src/features/platforms/mastodon-source.ts @@ -22,8 +22,13 @@ export const mastodonSourceSchema = z.discriminatedUnion("kind", [ target: z .string() .trim() - .regex(/^[\p{L}\p{N}_]+$/u) - .max(128), + .min(1) + .max(128) + // JSON Schema consumers do not all support Unicode property escapes. + .refine((value) => /^[\p{L}\p{N}_]+$/u.test(value), { + message: "Use only letters, numbers, and underscores in a hashtag.", + }) + .describe("Hashtag without #, containing only Unicode letters, numbers, and underscores."), }) .strict(), z