diff --git a/docs/runbooks/agent-app-directories.md b/docs/runbooks/agent-app-directories.md index 940550d2..0a0b1729 100644 --- a/docs/runbooks/agent-app-directories.md +++ b/docs/runbooks/agent-app-directories.md @@ -75,3 +75,11 @@ Any paid Claude plan can submit. Use these fields in the portal. Before you submit, add the server in Claude as a custom connector and call each tool once. After submission, Anthropic scans the server and lists it as a Community connector. Status and reviewer feedback appear in the portal. Escalations go to `mcp-review@anthropic.com`. + +## Icons + +Claude shows a connector's icon from Google's favicon service (`google.com/s2/favicons?domain=skilld.dev`), not from skilld.dev directly. +Google caches that icon. Until 2026-10-07 it served a retired skilld mark, because the site declared no large icon. +The site now declares `/apple-touch-icon.png`, and the MCP server lists its icons in `serverInfo.icons`. +The Claude listing sets its custom icon URL to `https://skilld.dev/logo-icon.png`, which overrides the favicon in the directory listing only. +The chat tile updates when Google refreshes its cache. diff --git a/layers/mcp/server/mcp/index.ts b/layers/mcp/server/mcp/index.ts index b83806f0..42a7358c 100644 --- a/layers/mcp/server/mcp/index.ts +++ b/layers/mcp/server/mcp/index.ts @@ -7,6 +7,11 @@ const MAX_MCP_BODY_BYTES = 64 * 1024 export default defineMcpHandler({ description: 'Search and browse skilld.dev for agent skills, and read who wrote each one.', + // MCP clients that read server icons show these instead of a cached favicon. + icons: [ + { src: 'https://skilld.dev/logo-icon.png', mimeType: 'image/png', sizes: ['512x512'] }, + { src: 'https://skilld.dev/logo-icon.svg', mimeType: 'image/svg+xml', sizes: ['any'] }, + ], instructions: 'skilld.dev is a curated registry of agent skills. Search first, inspect provenance before recommending a skill, then return the run command for the user to approve and run. Offer the install command only when the user wants the skill in every session. Without a shell, such as in a chat app, follow the markdown from get_skill for this session, and tell the user the skill name and source repository first. skilld.dev shows who wrote a skill and where its source lives. It does not review skills for safety, so never call a skill safe or verified. This server never runs or installs anything.', tools: (event) => { const deps: McpToolDeps = { diff --git a/nuxt.config.ts b/nuxt.config.ts index 96f2008b..d12f4f67 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -386,6 +386,9 @@ export default defineNuxtConfig({ // .ico is a fixed multi-size bitmap, so it declares what it contains. { rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg', sizes: 'any' }, { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico', sizes: '16x16 32x32 48x48' }, + // Google's favicon service, which Claude uses for connector icons, prefers a + // large icon. Without one it kept serving a retired mark for skilld.dev. + { rel: 'apple-touch-icon', href: '/apple-touch-icon.png', sizes: '512x512' }, ], style: [ // A browser orders cascade layers by where each name first appears. diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 00000000..b85b7c82 Binary files /dev/null and b/public/apple-touch-icon.png differ diff --git a/worker-configuration.d.ts b/worker-configuration.d.ts index cafb6af1..250e808d 100644 --- a/worker-configuration.d.ts +++ b/worker-configuration.d.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -// Generated by Wrangler by running `wrangler types --config=wrangler.jsonc --env-file=.dev.vars.example` (hash: 91ae1b6a0c6d3e279dd2c18ecea4e0c4) +// Generated by Wrangler by running `wrangler types --config=wrangler.jsonc --env-file=.dev.vars.example` (hash: d9c17df945873e507413a75b5172eec0) // Runtime types generated with workerd@1.20260828.1 2026-08-20 nodejs_compat interface __BaseEnv_Env { KV_CACHE: KVNamespace; @@ -26,6 +26,7 @@ interface __BaseEnv_Env { ARTIFACT_KEY_WRAP_KEY_ACTIVE_SLOT: "primary"; ARTIFACT_KEY_WRAP_KEY_PRIMARY_ID: "skilld-wrap-2026-08"; ARTIFACT_KEY_WRAP_KEY_SECONDARY_ID: ""; + NUXT_OPENAI_APPS_CHALLENGE: "IygUmSBQJVU5v275Y6kWojVpQkVxqckQf4k8cVmBiys"; NUXT_SESSION_PASSWORD: string; NUXT_ADMIN_SECRET: string; NUXT_TOKEN_KEY: string; @@ -68,7 +69,7 @@ type StringifyValues> = { [Binding in keyof EnvType]: EnvType[Binding] extends string ? EnvType[Binding] : string; }; declare namespace NodeJS { - interface ProcessEnv extends StringifyValues> {} + interface ProcessEnv extends StringifyValues> {} } // Begin runtime types diff --git a/wrangler.jsonc b/wrangler.jsonc index 6f629379..dcf9ef7b 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -135,7 +135,9 @@ "ARTIFACT_PRIVATE_ACCESS_ENABLED": "false", "ARTIFACT_KEY_WRAP_KEY_ACTIVE_SLOT": "primary", "ARTIFACT_KEY_WRAP_KEY_PRIMARY_ID": "skilld-wrap-2026-08", - "ARTIFACT_KEY_WRAP_KEY_SECONDARY_ID": "" + "ARTIFACT_KEY_WRAP_KEY_SECONDARY_ID": "", + // Public token the OpenAI plugin portal reads at /.well-known/openai-apps-challenge. + "NUXT_OPENAI_APPS_CHALLENGE": "IygUmSBQJVU5v275Y6kWojVpQkVxqckQf4k8cVmBiys" }, "ai": { "binding": "AI",