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
8 changes: 8 additions & 0 deletions docs/runbooks/agent-app-directories.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
5 changes: 5 additions & 0 deletions layers/mcp/server/mcp/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
3 changes: 3 additions & 0 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Binary file added public/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions worker-configuration.d.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -68,7 +69,7 @@ type StringifyValues<EnvType extends Record<string, unknown>> = {
[Binding in keyof EnvType]: EnvType[Binding] extends string ? EnvType[Binding] : string;
};
declare namespace NodeJS {
interface ProcessEnv extends StringifyValues<Pick<Cloudflare.Env, "ARTIFACT_PUBLIC_BASE_URL" | "ARTIFACT_PRIVATE_BASE_URL" | "ARTIFACT_KEY_WRAP_KEY_ACTIVE_SLOT" | "ARTIFACT_KEY_WRAP_KEY_PRIMARY_ID" | "ARTIFACT_KEY_WRAP_KEY_SECONDARY_ID" | "NUXT_SESSION_PASSWORD" | "NUXT_ADMIN_SECRET" | "NUXT_TOKEN_KEY" | "NUXT_HEALTH_CHECK_NOTIFY_TO" | "NUXT_PUBLIC_SITE_URL" | "NUXT_OAUTH_GITHUB_CLIENT_ID" | "NUXT_OAUTH_GITHUB_CLIENT_SECRET" | "NUXT_OG_IMAGE_SECRET" | "NUXT_IMAGE_PROXY_KEY" | "NUXT_AI_READY_RUNTIME_SYNC_SECRET" | "GITHUB_TOKEN" | "ARTIFACT_GITHUB_TOKEN" | "SKILLD_READ_APP_ID" | "SKILLD_READ_APP_INSTALLATION_ID" | "SKILLD_READ_APP_PRIVATE_KEY_PKCS8" | "ARTIFACT_PRIVATE_ACCESS_ENABLED" | "GITHUB_APP_ID" | "GITHUB_APP_CLIENT_ID" | "GITHUB_APP_CLIENT_SECRET" | "GITHUB_APP_PRIVATE_KEY_PKCS8" | "GITHUB_APP_WEBHOOK_SECRET" | "ARTIFACT_KEY_WRAP_KEY_PRIMARY" | "ARTIFACT_KEY_WRAP_KEY_SECONDARY" | "ARTIFACT_GRANT_IDEMPOTENCY_KEY" | "ARTIFACT_TRUSTED_ROOT_JSON" | "ANTHROPIC_API_KEY" | "VOYAGE_API_KEY" | "X_BEARER_KEY" | "BSKY_IDENTIFIER" | "BSKY_APP_PASSWORD" | "DISCORD_WEBHOOK_URL">> {}
interface ProcessEnv extends StringifyValues<Pick<Cloudflare.Env, "ARTIFACT_PUBLIC_BASE_URL" | "ARTIFACT_PRIVATE_BASE_URL" | "ARTIFACT_KEY_WRAP_KEY_ACTIVE_SLOT" | "ARTIFACT_KEY_WRAP_KEY_PRIMARY_ID" | "ARTIFACT_KEY_WRAP_KEY_SECONDARY_ID" | "NUXT_OPENAI_APPS_CHALLENGE" | "NUXT_SESSION_PASSWORD" | "NUXT_ADMIN_SECRET" | "NUXT_TOKEN_KEY" | "NUXT_HEALTH_CHECK_NOTIFY_TO" | "NUXT_PUBLIC_SITE_URL" | "NUXT_OAUTH_GITHUB_CLIENT_ID" | "NUXT_OAUTH_GITHUB_CLIENT_SECRET" | "NUXT_OG_IMAGE_SECRET" | "NUXT_IMAGE_PROXY_KEY" | "NUXT_AI_READY_RUNTIME_SYNC_SECRET" | "GITHUB_TOKEN" | "ARTIFACT_GITHUB_TOKEN" | "SKILLD_READ_APP_ID" | "SKILLD_READ_APP_INSTALLATION_ID" | "SKILLD_READ_APP_PRIVATE_KEY_PKCS8" | "ARTIFACT_PRIVATE_ACCESS_ENABLED" | "GITHUB_APP_ID" | "GITHUB_APP_CLIENT_ID" | "GITHUB_APP_CLIENT_SECRET" | "GITHUB_APP_PRIVATE_KEY_PKCS8" | "GITHUB_APP_WEBHOOK_SECRET" | "ARTIFACT_KEY_WRAP_KEY_PRIMARY" | "ARTIFACT_KEY_WRAP_KEY_SECONDARY" | "ARTIFACT_GRANT_IDEMPOTENCY_KEY" | "ARTIFACT_TRUSTED_ROOT_JSON" | "ANTHROPIC_API_KEY" | "VOYAGE_API_KEY" | "X_BEARER_KEY" | "BSKY_IDENTIFIER" | "BSKY_APP_PASSWORD" | "DISCORD_WEBHOOK_URL">> {}
}

// Begin runtime types
Expand Down
4 changes: 3 additions & 1 deletion wrangler.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading