Compare commits

...

41 Commits

Author SHA1 Message Date
Bryan Thompson
a1d0fa6d93 Update coderabbit plugin source URL 2026-04-28 07:22:26 -05:00
Tobin South
18113ade5c Add adobe-for-creativity plugin (#1625)
Adobe's Creative Cloud skills for image editing, design automation,
background removal, vectorization, and retouching. Points at the
plugins/creative-cloud/adobe-for-creativity subdir of adobe/skills.
2026-04-28 06:43:59 -05:00
Octavian Guzu
99832739a1 Merge pull request #1621 from anthropics/fix/validate-frontmatter-shell-injection
Harden validate-frontmatter workflow
2026-04-28 11:41:07 +01:00
Bryan Thompson
c5837a2c23 Add aws-dev-toolkit plugin (#1617) 2026-04-28 06:40:28 +01:00
Tobin South
f4b5494fb4 mcp-server-dev: hosting, payload-cap, lifecycle, and directory guidance (#1566) 2026-04-28 04:46:23 +01:00
Dickson Tsai
068a59e000 Fix shell injection in validate-frontmatter workflow
The 'Validate frontmatter' step interpolated step output directly into a
double-quoted shell string, allowing a fork PR that adds a file named
e.g. agents/$(curl ...).md to execute arbitrary commands on the runner.

- Pass the file list via env: and reference as "$FILES" so the shell
  never re-evaluates the contents
- Pass PR number via env: for consistency (no ${{ }} inside run:)
- Gate the job on same-repo PRs only, since fork PRs are auto-closed by
  close-external-prs.yml anyway

Impact was bounded (fork PRs get a read-only token with no secrets), but
this closes the RCE-on-runner vector entirely.
2026-04-27 17:38:18 -07:00
Bryan Thompson
1c81b81299 Add logfire plugin (#1613) 2026-04-27 12:37:20 -07:00
Bryan Thompson
7d42fe2132 Add 42crunch-api-security-testing plugin (#1580) 2026-04-27 12:37:15 -07:00
Bryan Thompson
71545a2994 Add datarobot-agent-skills plugin (#1579) 2026-04-27 12:37:11 -07:00
Bryan Thompson
458b2799c5 Add aiven plugin (#1578) 2026-04-27 12:37:07 -07:00
Bryan Thompson
26973b887b Add fullstory plugin (#1577) 2026-04-27 12:37:03 -07:00
Bryan Thompson
6fc0a4b36a Add jfrog plugin (#1576) 2026-04-27 12:36:58 -07:00
Bryan Thompson
27cab8ee35 Add rails-query plugin (#1575) 2026-04-27 12:36:54 -07:00
Bryan Thompson
020446a429 Add quarkus-agent plugin (#1534) 2026-04-23 22:45:48 +01:00
Bryan Thompson
740e9d5513 Add vanta-mcp-plugin (#1563) 2026-04-23 22:29:25 +01:00
Noah Zweben
5a71459c03 telegram: gate /start, /help, /status behind dmPolicy (#894)
The bot command handlers bypassed access control — they responded to
any DM user regardless of dmPolicy, leaking bot presence and
contradicting ACCESS.md's "Drop silently. No reply." contract for
allowlist mode.

Add dmCommandGate() that applies the same disabled/allowlist checks
as gate() without the pairing side effects, and route all three
handlers through it. Also prune expired pending codes before /status
iterates them.

Fixes #854

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-23 12:02:34 -07:00
Noah Zweben
ae54b113c4 Add Apache 2.0 LICENSE to math-olympiad plugin (#868)
Co-authored-by: Claude <noreply@anthropic.com>
2026-04-23 12:02:30 -07:00
jschwar2552
2a40fd2e7c skill-creator: sync from anthropics/skills (drop ANTHROPIC_API_KEY requirement) (#1523)
Ports anthropics/skills#547 (b0cbd3d) so this repo matches the upstream
skills repo.

improve_description.py and run_loop.py now shell out to `claude -p` instead
of using the Anthropic SDK directly, so the description optimizer uses the
session's existing Claude Code auth and no longer requires a separate
ANTHROPIC_API_KEY. SKILL.md drops the stale extended-thinking reference and
adds guidance for updating an existing skill.

Several enterprise customers sync exclusively from this repo (not
anthropics/skills, whose README disclaims production use), so they have been
stuck on the old SDK-based path.
2026-04-23 12:02:26 -07:00
Bryan Thompson
95f6172405 Add zscaler plugin (#1552) 2026-04-23 12:01:19 -07:00
Bryan Thompson
7bbdb8434e Add data-agent-kit-starter-pack plugin (#1551) 2026-04-23 12:01:12 -07:00
Bryan Thompson
4bbf944de1 Add atlassian-forge-skills plugin (#1539) 2026-04-23 12:01:06 -07:00
Bryan Thompson
06830b2ccd Add apollo plugin (#1538) 2026-04-23 12:01:00 -07:00
Bryan Thompson
bd6f1d7f48 Add windsor-ai plugin (#1536) 2026-04-23 12:00:53 -07:00
Bryan Thompson
808e70ffb9 Add auth0 plugin (#1535) 2026-04-23 12:00:47 -07:00
Bryan Thompson
187a267738 Add cloud-sql-postgresql plugin (#1533)
* Add cloud-sql-postgresql plugin

* Remove SHA pin from cloud-sql-postgresql entry
2026-04-23 12:00:37 -07:00
Bryan Thompson
42e980340d Add alloydb plugin (#1532)
* Add alloydb plugin

* Remove SHA pin from alloydb entry
2026-04-23 12:00:31 -07:00
Bryan Thompson
c15eada2e9 Add qt-development-skills plugin (#1519) 2026-04-23 12:00:25 -07:00
Bryan Thompson
f9f07aa2d3 Add versori-skills plugin (#1501) 2026-04-23 12:00:18 -07:00
Bryan Thompson
81952cabc5 Merge pull request #1499 from anthropics/add-exa
Add exa plugin
2026-04-23 13:59:15 -05:00
Bryan Thompson
0852f6647a Merge pull request #1437 from anthropics/rename-azure-skills-to-azure
Rename azure-skills to azure
2026-04-23 13:58:58 -05:00
Bryan Thompson
b0724d7a16 Rename azure-skills to azure per developer request 2026-04-22 06:42:35 -05:00
Bryan Thompson
cf62a6c02d Merge pull request #1439 from anthropics/add-datadog
Add datadog plugin
2026-04-21 16:04:18 -05:00
Bryan Thompson
3bd94cc810 Bump SHA pins for 39 plugins (>7d stale) (#1502)
Rebased on latest main to resolve conflict with cockroachdb unpin (#1514)
and liquid-lsp addition (#1520). Excludes netsuite-suitecloud (4d).
2026-04-21 20:56:31 +01:00
Bryan Thompson
a8be018317 Merge pull request #1514 from anthropics/update-cockroachdb
Update cockroachdb plugin — add author + category, bump SHA
2026-04-21 14:38:05 -05:00
Bryan Thompson
33e62b9bd6 Remove SHA pin from cockroachdb entry
Let installs follow the repo's default branch instead of a fixed SHA.
Removes the plugin from the weekly SHA-bump rotation and lets developer
updates reach users directly on `claude plugin install`.
2026-04-21 14:32:10 -05:00
Bryan Thompson
9f103c621d Add liquid-lsp plugin (#1520) 2026-04-21 19:07:52 +01:00
Bryan Thompson
caa8c1a539 Update cockroachdb description + author per developer request
- Description: expand to reflect current capabilities (14 tools, 2 MCP
  backends, 3 agents, 32 skills, safety hooks)
- Author: "CockroachDB" → "Cockroach Labs" (company name)
2026-04-21 12:33:39 -05:00
Bryan Thompson
33fd73c8b9 Update cockroachdb plugin — add author + category, bump SHA 2026-04-21 07:03:06 -05:00
Bryan Thompson
777db5c30b Add liquid-skills plugin (#1507) 2026-04-20 22:01:55 +01:00
Karandeep Johar
aeecad8f43 fix(amplitude): use git-subdir source to point at plugins/amplitude (#1505)
The amplitude entry used source type "url" which clones the root of
https://github.com/amplitude/mcp-marketplace — a multi-plugin repo
where the actual plugin lives at plugins/amplitude/. Claude Code found
no skills there, so /reload-plugins loaded 0 skills for amplitude.

Switching to "git-subdir" with path "plugins/amplitude" (the same
pattern used by awslabs, bigdata-com, zapier, etc.) makes Claude Code
resolve the correct subdirectory and load all 27 amplitude skills.

Removing the pinned sha so the plugin tracks main, consistent with
how posthog and other unpinned entries behave.
2026-04-20 20:34:29 +01:00
Bryan Thompson
db52e65c44 Add datadog plugin 2026-04-17 07:28:58 -05:00
12 changed files with 754 additions and 150 deletions

View File

@@ -7,6 +7,22 @@
"email": "support@anthropic.com"
},
"plugins": [
{
"name": "42crunch-api-security-testing",
"description": "Automate API security directly in Claude Code with 42Crunch - automatically audit OpenAPI specs, detect vulnerabilities aligned with OWASP API Security risks (including BOLA/BFLA), and apply AI-powered fixes. Designed for AI-assisted development workflows, it provides continuous guardrails through an audit->scan->remediate->validate loop, ensuring APIs meet enterprise security standards before deployment.",
"author": {
"name": "42Crunch"
},
"category": "security",
"source": {
"source": "git-subdir",
"url": "https://github.com/42Crunch-AI/claude-plugins.git",
"path": "plugins/api-security-testing",
"ref": "v1.0.1",
"sha": "56273e0e20762d76640838300a7431c4260cad32"
},
"homepage": "https://42crunch.com"
},
{
"name": "adlc",
"description": "Agentforce Agent Development Life Cycle — author, discover, scaffold, deploy, test, and optimize .agent files",
@@ -17,6 +33,21 @@
},
"homepage": "https://github.com/SalesforceAIResearch/agentforce-adlc"
},
{
"name": "adobe-for-creativity",
"description": "Harness Adobe's creative AI-powered tools to edit images, automate design workflows, and bring creative visions to life — from background removal to vectorization and professional retouching.",
"author": {
"name": "Adobe"
},
"category": "design",
"source": {
"source": "git-subdir",
"url": "https://github.com/adobe/skills.git",
"path": "plugins/creative-cloud/adobe-for-creativity",
"ref": "main"
},
"homepage": "https://github.com/adobe/skills/tree/main/plugins/creative-cloud/adobe-for-creativity"
},
{
"name": "adspirer-ads-agent",
"description": "Cross-platform ad management for Google Ads, Meta Ads, TikTok Ads, and LinkedIn Ads. 91 tools for keyword research, campaign creation, performance analysis, and budget optimization.",
@@ -24,7 +55,7 @@
"source": {
"source": "url",
"url": "https://github.com/amekala/adspirer-mcp-plugin.git",
"sha": "aa70dbdbbbb843e94a794c10c2b13f5dd66b5e40"
"sha": "c40623f1aa7b568e960d3f2e2558a6fcf10e6c18"
},
"homepage": "https://www.adspirer.com"
},
@@ -47,7 +78,7 @@
"url": "https://github.com/techwolf-ai/ai-first-toolkit.git",
"path": "plugins/ai-firstify",
"ref": "main",
"sha": "7f18e11d694b9ae62ea3009fbbc175f08ae913df"
"sha": "852272ec21cebab98202df967dffee127209b6bc"
},
"homepage": "https://ai-first.techwolf.ai"
},
@@ -57,7 +88,7 @@
"source": {
"source": "url",
"url": "https://github.com/endorlabs/ai-plugins.git",
"sha": "a0f1d5632b6f9e6c26eaa9806f5d8d454ca5b06f"
"sha": "975f0ce422b1f2677681ffd085aef34ea1826b70"
},
"homepage": "https://www.endorlabs.com"
},
@@ -67,10 +98,37 @@
"source": {
"source": "url",
"url": "https://github.com/AikidoSec/aikido-claude-plugin.git",
"sha": "d7fa8b8e192680d9a26c1a5dcaead7cf5cdb7139"
"sha": "5d9c13d367218e9b43a11d4502f623ab98859225"
},
"homepage": "https://github.com/AikidoSec/aikido-claude-plugin"
},
{
"name": "aiven",
"description": "Easily deploy managed PostgreSQL, Kafka, OpenSearch, Clickhouse, and other databases, streaming, and apps through Aiven. Free tier available, up and running in minutes.",
"author": {
"name": "Aiven"
},
"category": "database",
"source": {
"source": "github",
"repo": "aiven/aiven-ai-plugins",
"commit": "d2a7697b53826588d0faf795f39d2aa2362330da"
},
"homepage": "https://aiven.io"
},
{
"name": "alloydb",
"description": "Create, connect, and interact with an AlloyDB for PostgreSQL database and data.",
"author": {
"name": "Google LLC"
},
"category": "database",
"source": {
"source": "url",
"url": "https://github.com/gemini-cli-extensions/alloydb.git"
},
"homepage": "https://cloud.google.com/alloydb"
},
{
"name": "amazon-location-service",
"description": "Guide developers through adding maps, places search, geocoding, routing, and other geospatial features with Amazon Location Service, including authentication setup, SDK integration, and best practices.",
@@ -86,14 +144,28 @@
{
"name": "amplitude",
"source": {
"source": "url",
"source": "git-subdir",
"url": "https://github.com/amplitude/mcp-marketplace.git",
"sha": "be54ccb66b10593721dd3a31e47b2db20ea02d2f"
"path": "plugins/amplitude",
"ref": "main"
},
"description": "Use Amplitude as an expert analyst — instrument Amplitude, discover product opportunities, analyze charts, create dashboards, manage experiments, and understand users and accounts.",
"category": "monitoring",
"homepage": "https://github.com/amplitude/mcp-marketplace"
},
{
"name": "apollo",
"description": "Prospect, enrich leads, load outreach sequences, and query sales analytics with Apollo.io — one-click MCP server integration for Claude Code and Cowork.",
"author": {
"name": "Apollo.io"
},
"category": "productivity",
"source": {
"source": "url",
"url": "https://github.com/apolloio/apollo-mcp-plugin.git"
},
"homepage": "https://www.apollo.io/"
},
{
"name": "asana",
"description": "Asana project management integration. Create and manage tasks, search projects, update assignments, track progress, and integrate your development workflow with Asana's work management platform.",
@@ -108,7 +180,7 @@
"source": {
"source": "url",
"url": "https://github.com/astronomer/agents.git",
"sha": "7ef022b02f5296b5ecc52ba0db3ba9345ec03c9e"
"sha": "5935c4330dea4dfb8e93568956b10a543ecdb3d1"
},
"homepage": "https://github.com/astronomer/agents"
},
@@ -132,6 +204,19 @@
},
"homepage": "https://github.com/atlassian/atlassian-mcp-server"
},
{
"name": "atlassian-forge-skills",
"description": "Forge-focused skill bundle and MCP tooling for Atlassian Forge: scaffold apps, review before deploy, debug production issues, and stay current on Forge APIs and the Atlassian Design System.",
"author": {
"name": "Atlassian Labs"
},
"category": "development",
"source": {
"source": "url",
"url": "https://github.com/atlassian/forge-skills.git"
},
"homepage": "https://developer.atlassian.com"
},
{
"name": "atomic-agents",
"description": "Comprehensive development workflow for building AI agents with the Atomic Agents framework. Includes specialized agents for schema design, architecture planning, code review, and tool development. Features guided workflows, progressive-disclosure skills, and best practice validation.",
@@ -146,6 +231,21 @@
"community-managed"
]
},
{
"name": "auth0",
"description": "Add authentication to any app with Auth0. This plugin detects your framework, scaffolds the right Auth0 SDK integration, and guides you through login, logout, sessions, and protected routes — using current SDK patterns.",
"author": {
"name": "Auth0"
},
"category": "security",
"source": {
"source": "git-subdir",
"url": "https://github.com/auth0/agent-skills.git",
"path": "plugins/auth0",
"ref": "main"
},
"homepage": "https://auth0.com/docs/quickstart/agent-skills"
},
{
"name": "autofix-bot",
"description": "Code review agent that detects security vulnerabilities, code quality issues, and hardcoded secrets. Combines 5,000+ static analyzers to scan your code and dependencies for CVEs.",
@@ -168,6 +268,22 @@
},
"homepage": "https://github.com/awslabs/agent-plugins"
},
{
"name": "aws-dev-toolkit",
"description": "AWS development toolkit — 34 skills, 11 agents, and 3 MCP servers for building, migrating, and performing architecture reviews on AWS.",
"author": {
"name": "aws-samples"
},
"category": "development",
"source": {
"source": "git-subdir",
"url": "https://github.com/aws-samples/sample-claude-code-plugins-for-startups.git",
"path": "plugins/aws-dev-toolkit",
"ref": "main",
"sha": "ddea7fdd605b42ed3900374815f358a2d4600db5"
},
"homepage": "https://github.com/aws-samples/sample-claude-code-plugins-for-startups"
},
{
"name": "aws-serverless",
"description": "Design, build, deploy, test, and debug serverless applications with AWS Serverless services.",
@@ -181,19 +297,8 @@
"homepage": "https://github.com/awslabs/agent-plugins"
},
{
"name": "azure-cosmos-db-assistant",
"source": {
"source": "url",
"url": "https://github.com/AzureCosmosDB/cosmosdb-claude-code-plugin.git",
"sha": "56e6da0cae93cdee8bcfa5e624ecdd9a0a483181"
},
"description": "Expert assistant for Azure Cosmos DB — data modeling, query optimization, performance tuning, and best practices.",
"category": "database",
"homepage": "https://github.com/AzureCosmosDB/cosmosdb-claude-code-plugin"
},
{
"name": "azure-skills",
"description": "Microsoft Azure MCP integration for cloud resource management, deployments, and Azure services. Manage your Azure infrastructure, monitor applications, and deploy resources directly from Claude Code.",
"name": "azure",
"description": "Transform Claude into an Azure expert. This plugin integrates the Azure MCP server and specialized Azure skills to move beyond generic advice. It enables Claude to perform real-world tasks: listing resources, validating deployments, diagnosing infrastructure issues, and optimizing costs across 50+ Azure services.",
"category": "deployment",
"source": {
"source": "url",
@@ -201,6 +306,17 @@
},
"homepage": "https://github.com/microsoft/azure-skills"
},
{
"name": "azure-cosmos-db-assistant",
"source": {
"source": "url",
"url": "https://github.com/AzureCosmosDB/cosmosdb-claude-code-plugin.git",
"sha": "23c168856e4435793bd27a72d4714f022a3a1e90"
},
"description": "Expert assistant for Azure Cosmos DB — data modeling, query optimization, performance tuning, and best practices.",
"category": "database",
"homepage": "https://github.com/AzureCosmosDB/cosmosdb-claude-code-plugin"
},
{
"name": "base44",
"description": "Build and deploy Base44 full-stack apps with CLI project management and JavaScript/TypeScript SDK development skills",
@@ -234,7 +350,7 @@
"source": {
"source": "url",
"url": "https://github.com/box/box-for-ai.git",
"sha": "6f4ec3549f3e869b115628403555b1c9220b2b34"
"sha": "0fb23244e3c35cd562206c80eff1e22c456046ea"
},
"homepage": "https://github.com/box/box-for-ai"
},
@@ -244,7 +360,7 @@
"source": {
"source": "url",
"url": "https://github.com/brightdata/skills.git",
"sha": "e671da495f7ec0ed6be5e9fa71e260f886a1dc36"
"sha": "44b24797d82cfd535c5b97831d5c6ba86c9d60df"
},
"homepage": "https://docs.brightdata.com"
},
@@ -266,7 +382,7 @@
"source": {
"source": "url",
"url": "https://github.com/ChromeDevTools/chrome-devtools-mcp.git",
"sha": "c2d8009ff75f76bce1ec4cf79c2467b50d81725e"
"sha": "a1612be8e01401cf1711c64bc2ef5da5763ba956"
},
"homepage": "https://github.com/ChromeDevTools/chrome-devtools-mcp"
},
@@ -333,12 +449,25 @@
"category": "productivity",
"homepage": "https://github.com/anthropics/claude-plugins-official/tree/main/plugins/claude-md-management"
},
{
"name": "cloud-sql-postgresql",
"description": "Create, connect, and interact with a Cloud SQL for PostgreSQL database and data.",
"author": {
"name": "Google LLC"
},
"category": "database",
"source": {
"source": "url",
"url": "https://github.com/gemini-cli-extensions/cloud-sql-postgresql.git"
},
"homepage": "https://cloud.google.com/sql"
},
{
"name": "cloudflare",
"source": {
"source": "url",
"url": "https://github.com/cloudflare/skills.git",
"sha": "5ec03da67e230df52b698255c8e5979dc9b124b6"
"sha": "0397d7d88fa6ac7517a88389622eb0799e86ded2"
},
"description": "Skills for the Cloudflare developer platform: Workers, Durable Objects, Agents SDK, MCP servers, Wrangler CLI, and web performance.",
"category": "deployment",
@@ -350,17 +479,20 @@
"source": {
"source": "url",
"url": "https://github.com/cloudinary-devs/cloudinary-plugin.git",
"sha": "137c5d7acd9c3f10e80cd2a400486971e1664f31"
"sha": "7b443d7dbd607bfe4850d8cfcab6ba4cbf1a57c3"
},
"homepage": "https://cloudinary.com/documentation"
},
{
"name": "cockroachdb",
"description": "CockroachDB plugin for Claude Code — explore schemas, write optimized SQL, debug queries, and manage distributed database clusters directly from your AI coding agent.",
"description": "Connect Claude Code directly to your CockroachDB clusters for hands-on database work — explore schemas, write optimized SQL, debug queries, and manage distributed database clusters. This plugin provides 14 tools across two active MCP backends (self-hosted MCP Toolbox and managed CockroachDB Cloud MCP Server), three specialized agents (DBA, Developer, Operator), 32 skills across 6 operational domains, and built-in safety hooks.",
"author": {
"name": "Cockroach Labs"
},
"category": "database",
"source": {
"source": "url",
"url": "https://github.com/cockroachdb/claude-plugin.git",
"sha": "a54566e03c852567589ef85bb449d1e4de229667"
"url": "https://github.com/cockroachdb/claude-plugin.git"
},
"homepage": "https://github.com/cockroachdb/claude-plugin"
},
@@ -392,9 +524,9 @@
"category": "productivity",
"source": {
"source": "url",
"url": "https://github.com/coderabbitai/claude-plugin.git"
"url": "https://github.com/coderabbitai/skills.git"
},
"homepage": "https://github.com/coderabbitai/claude-plugin.git"
"homepage": "https://github.com/coderabbitai/skills"
},
{
"name": "commit-commands",
@@ -444,17 +576,30 @@
"source": {
"source": "url",
"url": "https://github.com/astronomer/agents.git",
"sha": "7ef022b02f5296b5ecc52ba0db3ba9345ec03c9e"
"sha": "5935c4330dea4dfb8e93568956b10a543ecdb3d1"
},
"homepage": "https://github.com/astronomer/agents"
},
{
"name": "data-agent-kit-starter-pack",
"description": "Specialized suite of skills for data engineers on Google Cloud — architect data pipelines, transform data with dbt, write Spark and BigQuery SQL notebooks, and orchestrate end-to-end workflows across BigQuery, Spanner, BigLake, and Dataproc.",
"author": {
"name": "Google LLC"
},
"category": "development",
"source": {
"source": "url",
"url": "https://github.com/gemini-cli-extensions/data-agent-kit-starter-pack.git"
},
"homepage": "https://cloud.google.com/bigquery"
},
{
"name": "data-engineering",
"description": "Data engineering plugin - warehouse exploration, pipeline authoring, Airflow integration",
"source": {
"source": "url",
"url": "https://github.com/astronomer/agents.git",
"sha": "85d6053b1e21724f9cefb1e3f5219bd54fc77224"
"sha": "5935c4330dea4dfb8e93568956b10a543ecdb3d1"
},
"homepage": "https://github.com/astronomer/agents"
},
@@ -470,6 +615,33 @@
},
"homepage": "https://github.com/awslabs/agent-plugins"
},
{
"name": "datadog",
"description": "Use Datadog directly in Claude Code through a preconfigured Datadog MCP server. Query logs, metrics, traces, dashboards, and more through natural conversation. This plugin is in preview.",
"author": {
"name": "Datadog"
},
"category": "monitoring",
"source": {
"source": "url",
"url": "https://github.com/datadog-labs/claude-code-plugin.git"
},
"homepage": "https://www.datadoghq.com/"
},
{
"name": "datarobot-agent-skills",
"description": "DataRobot skills for AI/ML workflows — model training, deployment, predictions, feature engineering, monitoring, explainability, data preparation, App Framework CI/CD, and external agent monitoring.",
"author": {
"name": "DataRobot"
},
"category": "development",
"source": {
"source": "url",
"url": "https://github.com/datarobot-oss/datarobot-agent-skills.git",
"sha": "b3e8fd33d7c36592c802359026c15f3e067a0646"
},
"homepage": "https://datarobot.com"
},
{
"name": "dataverse",
"description": "Agent skills for building on, analyzing, and managing Microsoft Dataverse — with Dataverse MCP, PAC CLI, and Python SDK.",
@@ -559,7 +731,7 @@
"source": {
"source": "url",
"url": "https://github.com/fastly/fastly-agent-toolkit.git",
"sha": "d9ba949011e725be55cae11acc741aa1f1f393d3"
"sha": "329331c887512850f13e481b45c4298c0387a4d2"
},
"homepage": "https://github.com/fastly/fastly-agent-toolkit/blob/main/README.md"
},
@@ -580,7 +752,7 @@
"source": {
"source": "url",
"url": "https://github.com/voxel51/fiftyone-skills.git",
"sha": "593e0553fc9fd94db52386ada2c9e2074a6ecf89"
"sha": "02bd4ea170ca01a751c2d2dd6bf2df8f62e65626"
},
"homepage": "https://docs.voxel51.com/"
},
@@ -637,7 +809,7 @@
"source": {
"source": "url",
"url": "https://github.com/followrabbit-ai/awesome-rabbit.git",
"sha": "f59ec3d1f6337a6ed825ef06836a221ed3d2ffb0"
"sha": "6926154501300d348a7b50d47479648fe87985b6"
},
"homepage": "https://subscriptions.agentic.followrabbit.ai/"
},
@@ -652,6 +824,20 @@
"category": "development",
"homepage": "https://github.com/anthropics/claude-plugins-public/tree/main/plugins/frontend-design"
},
{
"name": "fullstory",
"description": "Connect Claude to Fullstory to query behavioral analytics, session replays, and customer experience insights.",
"author": {
"name": "Fullstory"
},
"category": "monitoring",
"source": {
"source": "github",
"repo": "fullstorydev/fullstory-skills",
"commit": "1ec5865e7ab1449f9a0859d164c4b6a8c53b6e2f"
},
"homepage": "https://www.fullstory.com"
},
{
"name": "github",
"description": "Official GitHub MCP server for repository management. Create issues, manage pull requests, review code, search repositories, and interact with GitHub's full API directly from Claude Code.",
@@ -672,7 +858,7 @@
"source": {
"source": "url",
"url": "https://github.com/PAIR-Systems-Inc/goodmem-claude-code-plugin.git",
"sha": "215568baf203887b5d7f8245e0503dd4a81336c2"
"sha": "4e23ab2b3bc7cb4167c99e10d9640ad7089744d7"
},
"homepage": "https://github.com/PAIR-Systems-Inc/goodmem-claude-code-plugin"
},
@@ -711,7 +897,7 @@
"url": "https://github.com/helius-labs/core-ai.git",
"path": "helius-plugin",
"ref": "main",
"sha": "05ea4d1128d46618266bbcc23a5e7019c57be0d6"
"sha": "d9d252497bcf1e4bd5073a76715cd50a8353f9c3"
},
"homepage": "https://www.helius.dev/docs"
},
@@ -749,7 +935,7 @@
"source": {
"source": "url",
"url": "https://github.com/intercom/claude-plugin-external.git",
"sha": "eeef353eead2e3dc5f33f64dbaae54e1309e0d45"
"sha": "52653572c47700443eb61154c4e4334a355e755e"
},
"homepage": "https://github.com/intercom/claude-plugin-external"
},
@@ -774,6 +960,21 @@
}
}
},
{
"name": "jfrog",
"description": "Use the JFrog Platform from Claude Code: Artifactory repos and artifacts, security findings and exposures, Catalog package safety and downloads, workflows across the SDLC, and platform administration.",
"author": {
"name": "JFrog Ltd.",
"url": "https://jfrog.com"
},
"category": "security",
"source": {
"source": "github",
"repo": "jfrog/claude-plugin",
"commit": "761921eaa12b845beba1688d699a2d45091dfe83"
},
"homepage": "https://jfrog.com"
},
{
"name": "kotlin-lsp",
"description": "Kotlin language server for code intelligence",
@@ -837,6 +1038,53 @@
"source": "./external_plugins/linear",
"homepage": "https://github.com/anthropics/claude-plugins-public/tree/main/external_plugins/linear"
},
{
"name": "liquid-lsp",
"description": "LSP integration for Shopify Liquid templates via the Shopify CLI theme language server.",
"author": {
"name": "Shopify"
},
"category": "development",
"source": {
"source": "git-subdir",
"url": "https://github.com/Shopify/liquid-skills.git",
"path": "plugins/liquid-lsp",
"ref": "main",
"sha": "a00ca039d82114a7af1b4cbc3025b16c624a42fa"
},
"homepage": "https://github.com/Shopify/liquid-skills/tree/main/plugins/liquid-lsp"
},
{
"name": "liquid-skills",
"description": "Liquid language fundamentals, CSS/JS/HTML coding standards, and WCAG accessibility patterns for Shopify themes",
"author": {
"name": "Shopify"
},
"category": "development",
"source": {
"source": "git-subdir",
"url": "https://github.com/Shopify/liquid-skills.git",
"path": "plugins/liquid-skills",
"ref": "main",
"sha": "bf7a7aa9f9809b0dcd80cb5f7fd2795a7208a7a3"
},
"homepage": "https://github.com/Shopify/liquid-skills/tree/main/plugins/liquid-skills"
},
{
"name": "logfire",
"description": "Add Logfire observability to Python applications with auto-instrumentation for FastAPI, httpx, asyncpg, SQLAlchemy, and more",
"author": {
"name": "Pydantic"
},
"category": "monitoring",
"source": {
"source": "git-subdir",
"url": "https://github.com/pydantic/skills.git",
"path": "plugins/logfire",
"ref": "main"
},
"homepage": "https://github.com/pydantic/skills/tree/main/plugins/logfire"
},
{
"name": "lua-lsp",
"description": "Lua language server for code intelligence",
@@ -896,7 +1144,7 @@
"source": {
"source": "url",
"url": "https://github.com/mintlify/mintlify-claude-plugin.git",
"sha": "ce435be18a700dc849d6a63a80da4816d1e2128c"
"sha": "acd6d2e0128c4f235d55cfb8d8c91ecbdd5df8cc"
},
"homepage": "https://www.mintlify.com/"
},
@@ -922,7 +1170,7 @@
"source": {
"source": "url",
"url": "https://github.com/mongodb/agent-skills.git",
"sha": "c47079f65e88a113c52d1ce0618684cef300246c"
"sha": "24529d9540b962d57f30e75d25071bebea5809ad"
},
"homepage": "https://www.mongodb.com/docs/mcp-server/overview/"
},
@@ -935,7 +1183,7 @@
"url": "https://github.com/neondatabase/agent-skills.git",
"path": "plugins/neon-postgres",
"ref": "main",
"sha": "54d7a9db2ddd476f84d5d1fd7bac323907858a8b"
"sha": "1438d7db4560a649d62eba99e9d5008b77ac5758"
},
"homepage": "https://github.com/neondatabase/agent-skills/tree/main/plugins/neon-postgres"
},
@@ -1016,7 +1264,7 @@
"source": {
"source": "url",
"url": "https://github.com/Optimal-AI/optibot-skill.git",
"sha": "981db1f630c3116d7df0a71e5967af55b08e813c"
"sha": "ce2be448ee713606aa653fc93ef2f98a200fe327"
},
"homepage": "https://getoptimal.ai"
},
@@ -1120,7 +1368,7 @@
"source": {
"source": "url",
"url": "https://github.com/gitroomhq/postiz-agent.git",
"sha": "c5d1bf5f7e95a71e230fc19ae2150ddd9c549854"
"sha": "37d627244c53a4b3a7ca94c52cc2db13aaaf468e"
},
"homepage": "https://postiz.com/agent"
},
@@ -1131,7 +1379,7 @@
"source": {
"source": "url",
"url": "https://github.com/Postman-Devrel/postman-claude-code-plugin.git",
"sha": "40b11ac3466c500cf4625ac016d5c01cd00046f4"
"sha": "416e40da03a237df7bf03f4362cf6fc7b989b567"
},
"homepage": "https://learning.postman.com/docs/developer/postman-mcp-server/"
},
@@ -1212,6 +1460,48 @@
},
"homepage": "https://github.com/qodo-ai/qodo-skills.git"
},
{
"name": "qt-development-skills",
"description": "Agentic engineering skills for Qt software development — Qt C++/QML code review, QML coding, and Qt C++/QML code documentation.",
"author": {
"name": "Qt Group"
},
"category": "development",
"source": {
"source": "url",
"url": "https://github.com/TheQtCompanyRnD/agent-skills.git",
"sha": "62a98e2339e6eefcff108cfc3fe9db8a7301856c"
},
"homepage": "https://www.qt.io/"
},
{
"name": "quarkus-agent",
"description": "MCP server for AI coding agents to create, manage, and interact with Quarkus applications. Provides tools for project scaffolding, dev mode lifecycle, extension skills, Dev MCP proxy, and documentation search.",
"author": {
"name": "Quarkus"
},
"category": "development",
"source": {
"source": "url",
"url": "https://github.com/quarkusio/quarkus-agent-mcp.git"
},
"homepage": "https://quarkus.io"
},
{
"name": "rails-query",
"description": "Run read-only database queries against a Ruby on Rails 8.2+ app's database via `rails query` — ActiveRecord or SQL, schema/model introspection, EXPLAIN, pagination, and remote execution via Kamal.",
"author": {
"name": "Lewis Buckley",
"url": "https://github.com/lewispb"
},
"category": "development",
"source": {
"source": "github",
"repo": "lewispb/rails-query-skill",
"commit": "0f53fa861089e1f46097db9a92aea311f340c355"
},
"homepage": "https://github.com/lewispb/rails-query-skill"
},
{
"name": "railway",
"description": "Deploy and manage apps, databases, and infrastructure on Railway. Covers project setup, deploys, environment configuration, networking, troubleshooting, and monitoring.",
@@ -1221,7 +1511,7 @@
"url": "https://github.com/railwayapp/railway-skills.git",
"path": "plugins/railway",
"ref": "main",
"sha": "d52f3741a6a33a3191d6138eb3d6c3355cb970d1"
"sha": "eaa89d8f594412b0b837b6531241e7d166e12202"
},
"homepage": "https://docs.railway.com/ai/claude-code-plugin"
},
@@ -1253,7 +1543,7 @@
"source": {
"source": "url",
"url": "https://github.com/Digital-Process-Tools/claude-remember.git",
"sha": "779ab61d8d412230eeec1840b8ca104bebea4358"
"sha": "914445ac5f06a164800ea90ba4db41a0486321ae"
},
"homepage": "https://github.com/Digital-Process-Tools/claude-remember"
},
@@ -1334,7 +1624,7 @@
"source": {
"source": "url",
"url": "https://github.com/sanity-io/agent-toolkit.git",
"sha": "4b1fb10bd707a22cf0cdfad5374ffc885f2ffa8d"
"sha": "bc09fa9854507c538a856648aafbd4e1a775a95c"
},
"homepage": "https://www.sanity.io"
},
@@ -1478,7 +1768,7 @@
"source": {
"source": "url",
"url": "https://github.com/sourcegraph-community/sourcegraph-claudecode-plugin.git",
"sha": "cfe3d44476957b16d1575261bef6b2dc7cb1e0b7"
"sha": "332ee0ca9a409ccd791abee43c7abf2606469017"
},
"homepage": "https://sourcegraph.com"
},
@@ -1489,7 +1779,7 @@
"source": {
"source": "url",
"url": "https://github.com/spotify/ads-claude-plugin.git",
"sha": "a4bce9912db071d47dfb410086a48004e0539efa"
"sha": "63585cc919da51dd24fab594d829869595301922"
},
"homepage": "https://github.com/spotify/ads-claude-plugin"
},
@@ -1536,7 +1826,7 @@
"source": {
"source": "url",
"url": "https://github.com/sumup/sumup-skills.git",
"sha": "802476c39a0422d3277e37288b03968ad731bc30"
"sha": "0fd0a911ecaffd7187fe35e914d8ead6de584ffd"
},
"homepage": "https://www.sumup.com/"
},
@@ -1636,7 +1926,7 @@
"url": "https://github.com/UI5/plugins-claude.git",
"path": "plugins/ui5",
"ref": "main",
"sha": "5070dfc1cef711d6efad40beb43750027039d71f"
"sha": "cec940abd4b7b6866de8e7e4522f3dba0449379d"
},
"homepage": "https://github.com/UI5/plugins-claude"
},
@@ -1649,10 +1939,24 @@
"url": "https://github.com/UI5/plugins-claude.git",
"path": "plugins/ui5-typescript-conversion",
"ref": "main",
"sha": "5070dfc1cef711d6efad40beb43750027039d71f"
"sha": "cec940abd4b7b6866de8e7e4522f3dba0449379d"
},
"homepage": "https://github.com/UI5/plugins-claude"
},
{
"name": "vanta-mcp-plugin",
"description": "The Vanta plugin connects Claude Code to Vanta's security and compliance platform through the Vanta MCP server. It combines Vanta's test-specific remediation intelligence with your local repository context to help you fix compliance failures faster.",
"author": {
"name": "Vanta"
},
"category": "security",
"source": {
"source": "url",
"url": "https://github.com/VantaInc/vanta-mcp-plugin.git",
"sha": "46e5bebf0484f08fc4a3c4054437cf5ec06298c9"
},
"homepage": "https://help.vanta.com/en/articles/14094979-connecting-to-vanta-mcp#h_887ce3f337"
},
{
"name": "vercel",
"description": "Vercel deployment platform integration. Manage deployments, check build status, access logs, configure domains, and control your frontend infrastructure directly from Claude Code.",
@@ -1663,16 +1967,44 @@
},
"homepage": "https://github.com/vercel/vercel-plugin"
},
{
"name": "versori-skills",
"description": "Skills for building data integrations using the Versori platform and versori-run SDK. Claude can bootstrap projects, configure systems and connections, generate type-safe TypeScript workflows, run local validation via Deno, and deploy to production — with a research-first approach that grounds code generation in gathered API documentation.",
"author": {
"name": "Versori"
},
"category": "development",
"source": {
"source": "url",
"url": "https://github.com/versori/cli.git",
"sha": "134cf334c3065509eee39a5361fd0bcf969dc867"
},
"homepage": "https://docs.versori.com/latest/ai-tooling/overview"
},
{
"name": "voila-api",
"description": "Definitive guide for the Voila API. Covers shipment creation (Manual/Smart Shipping), real-time tracking, detailed history, manifesting, collections, webhooks, and third-party integrations (Sorted, Peoplevox, Mintsoft, Veeqo, JD).",
"source": {
"source": "url",
"url": "https://github.com/TSedmanDC/Voila-API-Skill.git",
"sha": "b9cfcb860cb5ae4ece57d67422a6cdd92ef96739"
"sha": "422c7beb772a0de4592a204584e0e990fc5dc139"
},
"homepage": "https://github.com/TSedmanDC/Voila-API-Skill"
},
{
"name": "windsor-ai",
"description": "Connect Claude Code to 325+ business data sources via Windsor.ai. Query marketing, sales, CRM, ecommerce, finance, and analytics data from Google Ads, Meta, HubSpot, Salesforce, Shopify, Stripe, and hundreds more — directly from your terminal.",
"author": {
"name": "Windsor.ai"
},
"category": "productivity",
"source": {
"source": "url",
"url": "https://github.com/windsor-ai/claude-windsor-ai-plugin.git",
"sha": "248a6994b15b410cc025b105bb4ed5558e9b1af9"
},
"homepage": "https://windsor.ai"
},
{
"name": "wix",
"description": "Build, manage, and deploy Wix sites and apps. CLI development skills for dashboard extensions, backend APIs, site widgets, and service plugins with the Wix Design System, plus MCP server for site management.",
@@ -1680,7 +2012,7 @@
"source": {
"source": "url",
"url": "https://github.com/wix/skills.git",
"sha": "15dda227e34959b1340e33bb9aede7e23a273f42"
"sha": "bf25b5a45b2413b3581f3dcbcd63f3737791a051"
},
"homepage": "https://dev.wix.com/docs/wix-cli/guides/development/about-wix-skills"
},
@@ -1690,7 +2022,7 @@
"source": {
"source": "url",
"url": "https://github.com/Automattic/claude-code-wordpress.com.git",
"sha": "e4d23c3bffdcdb7f70134ab6a1a110258ff75cfd"
"sha": "052ca970df2c577d7c651e784935186ff93e6779"
},
"homepage": "https://developer.wordpress.com/wordpress-com-claude-code-plugin/"
},
@@ -1703,7 +2035,7 @@
"url": "https://github.com/zapier/zapier-mcp.git",
"path": "plugins/zapier",
"ref": "main",
"sha": "b93007e9a726c6ee93c57a949e732744ef5acbfd"
"sha": "76c4669321847c8f72a6e0462c17f29fd437519a"
},
"homepage": "https://github.com/zapier/zapier-mcp/tree/main/plugins/zapier"
},
@@ -1716,6 +2048,19 @@
"url": "https://github.com/zoom/zoom-plugin.git"
},
"homepage": "https://developers.zoom.us/"
},
{
"name": "zscaler",
"description": "Manage Zscaler cloud security platform including ZPA (private access), ZIA (internet access), ZDX (digital experience), ZCC (client connector), EASM (attack surface), and Z-Insights (analytics). Create and manage policies, troubleshoot connectivity, audit security configurations, and investigate incidents across the full Zscaler ecosystem.",
"author": {
"name": "Zscaler"
},
"category": "security",
"source": {
"source": "url",
"url": "https://github.com/zscaler/zscaler-mcp-server.git"
},
"homepage": "https://github.com/zscaler/zscaler-mcp-server"
}
]
}

View File

@@ -9,6 +9,10 @@ on:
jobs:
validate:
# Fork PRs are auto-closed by close-external-prs.yml, so skip validation
# for them entirely. This also prevents untrusted filenames from forks
# from ever reaching the shell steps below.
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -20,16 +24,19 @@ jobs:
- name: Get changed frontmatter files
id: changed
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
# Use diff-filter=AMRC to exclude deleted files (D) - only Added, Modified, Renamed, Copied
FILES=$(gh pr diff ${{ github.event.pull_request.number }} --name-only --diff-filter=AMRC | grep -E '(agents/.*\.md|skills/.*/SKILL\.md|commands/.*\.md)$' || true)
FILES=$(gh pr diff "$PR_NUMBER" --name-only --diff-filter=AMRC | grep -E '(agents/.*\.md|skills/.*/SKILL\.md|commands/.*\.md)$' || true)
echo "files<<EOF" >> "$GITHUB_OUTPUT"
echo "$FILES" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ github.token }}
- name: Validate frontmatter
if: steps.changed.outputs.files != ''
env:
FILES: ${{ steps.changed.outputs.files }}
run: |
echo "${{ steps.changed.outputs.files }}" | xargs bun .github/scripts/validate-frontmatter.ts
printf '%s\n' "$FILES" | xargs bun .github/scripts/validate-frontmatter.ts

View File

@@ -284,6 +284,19 @@ function gate(ctx: Context): GateResult {
return { action: 'drop' }
}
// Like gate() but for bot commands: no pairing side effects, just allow/drop.
function dmCommandGate(ctx: Context): { access: Access; senderId: string } | null {
if (ctx.chat?.type !== 'private') return null
if (!ctx.from) return null
const senderId = String(ctx.from.id)
const access = loadAccess()
const pruned = pruneExpired(access)
if (pruned) saveAccess(access)
if (access.dmPolicy === 'disabled') return null
if (access.dmPolicy === 'allowlist' && !access.allowFrom.includes(senderId)) return null
return { access, senderId }
}
function isMentioned(ctx: Context, extraPatterns?: string[]): boolean {
const entities = ctx.message?.entities ?? ctx.message?.caption_entities ?? []
const text = ctx.message?.text ?? ctx.message?.caption ?? ''
@@ -669,12 +682,7 @@ setInterval(() => {
// the gate's behavior for unrecognized groups.
bot.command('start', async ctx => {
if (ctx.chat?.type !== 'private') return
const access = loadAccess()
if (access.dmPolicy === 'disabled') {
await ctx.reply(`This bot isn't accepting new connections.`)
return
}
if (!dmCommandGate(ctx)) return
await ctx.reply(
`This bot bridges Telegram to a Claude Code session.\n\n` +
`To pair:\n` +
@@ -685,7 +693,7 @@ bot.command('start', async ctx => {
})
bot.command('help', async ctx => {
if (ctx.chat?.type !== 'private') return
if (!dmCommandGate(ctx)) return
await ctx.reply(
`Messages you send here route to a paired Claude Code session. ` +
`Text and photos are forwarded; replies and reactions come back.\n\n` +
@@ -695,14 +703,12 @@ bot.command('help', async ctx => {
})
bot.command('status', async ctx => {
if (ctx.chat?.type !== 'private') return
const from = ctx.from
if (!from) return
const senderId = String(from.id)
const access = loadAccess()
const gated = dmCommandGate(ctx)
if (!gated) return
const { access, senderId } = gated
if (access.allowFrom.includes(senderId)) {
const name = from.username ? `@${from.username}` : senderId
const name = ctx.from!.username ? `@${ctx.from!.username}` : senderId
await ctx.reply(`Paired as ${name}.`)
return
}

View File

@@ -14,10 +14,15 @@ The UI layer is **additive**. Under the hood it's still tools, resources, and th
## Claude host specifics
- `_meta.ui.prefersBorder: false` on a `ui://` resource removes the outer card border (mobile).
| `_meta.ui.*` key | Where | Effect |
|---|---|---|
| `resourceUri` | tool | Which `ui://` resource the host renders for this tool's results. |
| `visibility: ["app"]` | tool | Hide a widget-only helper tool (e.g. geometry/image fetcher called via `callServerTool`) from Claude's tool list. |
| `prefersBorder: false` | resource | Drop the host's outer card border (mobile). |
| `csp.{connectDomains, resourceDomains, baseUriDomains}` | resource | Declare external origins; default is block-all. `frameDomains` is currently restricted in Claude. |
- `hostContext.safeAreaInsets: {top, right, bottom, left}` (px) — honor these for notches and the composer overlay.
- `_meta.ui.csp.{connectDomains, resourceDomains, baseUriDomains}`declare external origins per resource; default is block-all. `frameDomains` is currently restricted in Claude.
- Directory submission for MCP Apps requires 35 PNG screenshots, ≥1000px wide, cropped to the app response only (no prompt in the image). See https://claude.com/docs/connectors/building/submission#asset-specifications.
- Directory submission requires OAuth or **authless** (`none`)static bearer is private-deploy only and blocks listing — plus tool `annotations` and 35 PNG screenshots; see `references/directory-checklist.md`.
---
@@ -104,6 +109,7 @@ const server = new McpServer({ name: "contacts", version: "1.0.0" });
// 1. The tool — returns DATA, declares which UI to show
registerAppTool(server, "pick_contact", {
description: "Open an interactive contact picker",
annotations: { title: "Pick Contact", readOnlyHint: true },
inputSchema: { filter: z.string().optional() },
_meta: { ui: { resourceUri: "ui://widgets/contact-picker.html" } },
}, async ({ filter }) => {
@@ -172,7 +178,10 @@ The `/*__EXT_APPS_BUNDLE__*/` placeholder gets replaced by the server at startup
| `app.updateModelContext({...})` | Widget → host | Update context silently (no visible message) |
| `app.callServerTool({name, arguments})` | Widget → server | Call another tool on your server |
| `app.openLink({url})` | Widget → host | Open a URL in a new tab (sandbox blocks `window.open`) |
| `app.getHostContext()` / `app.onhostcontextchanged` | Host → widget | Theme (`light`/`dark`), locale, etc. |
| `app.getHostContext()` / `app.onhostcontextchanged` | Host → widget | Theme, host CSS vars, `containerDimensions`, `displayMode`, `deviceCapabilities` |
| `app.requestDisplayMode({mode})` | Widget → host | Ask for `inline` / `pip` / `fullscreen` |
| `app.downloadFile({name, mimeType, content})` | Widget → host | Host-mediated download (base64 content) |
| `new App(info, caps, {autoResize: true})` | — | Iframe height tracks rendered content |
`sendMessage` is the typical "user picked something, tell Claude" path. `updateModelContext` is for state that Claude should know about but shouldn't clutter the chat. `openLink` is **required** for any outbound navigation — `window.open` and `<a target="_blank">` are blocked by the sandbox attribute.
@@ -225,6 +234,7 @@ const pickerHtml = readFileSync("./widgets/picker.html", "utf8")
registerAppTool(server, "pick_contact", {
description: "Open an interactive contact picker. User selects one contact.",
annotations: { title: "Pick Contact", readOnlyHint: true },
inputSchema: { filter: z.string().optional().describe("Name/email prefix filter") },
_meta: { ui: { resourceUri: "ui://widgets/picker.html" } },
}, async ({ filter }) => {
@@ -348,6 +358,24 @@ Desktop caches UI resources aggressively. After editing widget HTML, **fully qui
The `sleep` keeps stdin open long enough to collect all responses. Parse the jsonl output with `jq` or a Python one-liner.
**Widget dev loop** — avoid the ⌘Q-relaunch cycle entirely by serving the inlined widget HTML at a plain GET route with a fake `ExtApps` shim that fires `ontoolresult` from a query param:
```ts
app.get("/widget-preview", (_req, res) => {
const shim = `globalThis.ExtApps={applyHostStyleVariables:()=>{},App:class{
constructor(){this.h={}} ontoolresult;onhostcontextchanged;
async connect(){const p=new URLSearchParams(location.search).get("payload");
if(p)this.ontoolresult?.({content:[{type:"text",text:p}]});}
getHostContext(){return{theme:"light"}}
sendMessage(m){console.log("sendMessage",m)} updateModelContext(){}
callServerTool(){return Promise.resolve({content:[]})} openLink(){} downloadFile(){}
}};`;
res.type("html").send(widgetHtml.replace("/*__EXT_APPS_BUNDLE__*/", shim));
});
```
Open `http://localhost:3000/widget-preview?payload={"rows":[...]}` in a normal browser tab and iterate with ordinary devtools.
**Host fallback** — use a host without the apps surface (or MCP Inspector) and confirm the tool's text content degrades gracefully.
**CSP debugging** — open the iframe's own devtools console. CSP violations are the #1 reason widgets silently fail (blank rectangle, no error in the main console). See `references/iframe-sandbox.md`.
@@ -356,6 +384,9 @@ The `sleep` keeps stdin open long enough to collect all responses. Parse the jso
## Reference files
- `references/iframe-sandbox.md` — CSP/sandbox constraints, the bundle-inlining pattern, image handling
- `references/iframe-sandbox.md` — CSP/sandbox constraints, the bundle-inlining pattern, image handling, host theming
- `references/widget-templates.md` — reusable HTML scaffolds for picker / confirm / progress / display
- `references/apps-sdk-messages.md` — the `App` class API: widget ↔ host ↔ server messaging
- `references/apps-sdk-messages.md` — the `App` class API: widget ↔ host ↔ server messaging, lifecycle & supersession
- `references/payload-budgeting.md` — host tool-result size caps, prune-then-truncate, heavy assets via `callServerTool`
- `references/abuse-protection.md` — Anthropic egress CIDRs, tiered rate limiting, `trust proxy`, response caching
- `references/directory-checklist.md` — pre-flight for connector-directory submission

View File

@@ -0,0 +1,60 @@
# Abuse protection for authless hosted servers
An authless StreamableHTTP server is reachable by anything on the internet.
There are three resources to protect: your compute, any upstream API quota
your tools consume, and egress bandwidth for large `callServerTool` payloads.
## You don't get a per-user identity
In authless mode there is no token and stateless transport gives no session
ID. Traffic from claude.ai is proxied through Anthropic's egress — every web
user arrives from the same small set of IPs:
```
160.79.104.0/21
2607:6bc0::/48
```
(See https://platform.claude.com/docs/en/api/ip-addresses.)
Claude Desktop, Claude Code, and other hosts connect **directly from the
user's machine**, so those *do* have distinct per-user IPs. Per-IP limiting
therefore works for direct-connect clients; for claude.ai you can only limit
the aggregate Anthropic pool. If true per-user limits matter, that's the
trigger to add OAuth.
## Tiered token-bucket (per-replica backstop)
```ts
const ANTHROPIC_CIDRS = ["160.79.104.0/21", "2607:6bc0::/48"];
const TIERS = {
anthropic: { capacity: 600, refillPerSec: 100 }, // shared pool
other: { capacity: 30, refillPerSec: 2 }, // per-IP
};
```
Match `req.ip` against the CIDRs, pick a bucket (`"anthropic"` or
`"ip:<addr>"`), 429 + `Retry-After` on exhaust. This is a per-replica
backstop — cross-replica enforcement belongs at the edge (Cloudflare, Cloud
Armor), which keeps the containers stateless.
## `trust proxy` must match your topology
`req.ip` only honours `X-Forwarded-For` if `app.set('trust proxy', N)` is
set. `true` trusts every hop, which lets a direct client send
`X-Forwarded-For: 160.79.108.42` and claim the Anthropic tier. Set it to the
exact number of trusted hops (e.g. `1` behind a single LB, `2` behind
Cloudflare → origin LB) and **never `true` in production**.
## Hard-allowlisting Anthropic IPs is a product decision
Blocking everything outside `160.79.104.0/21` locks out Desktop, Claude Code,
and every other MCP host. Use the CIDRs to **tier** rate limits, not to gate
access, unless claude.ai-only is an explicit goal.
## Cache upstream responses
For tools that wrap a third-party API, an in-process LRU keyed on the
normalized query (TTL hours, no secrets in the key) is the primary cost
control — repeat queries become free and absorb thundering-herd. Rate limits
are the safety net, not the first line.

View File

@@ -2,6 +2,18 @@
The `@modelcontextprotocol/ext-apps` package provides the `App` class (browser side) and `registerAppTool`/`registerAppResource` helpers (server side). Messaging is bidirectional and persistent.
## Construction
```js
const app = new App(
{ name: "MyWidget", version: "1.0.0" },
{}, // capabilities
{ autoResize: true }, // options
);
```
`autoResize: true` wires a `ResizeObserver` that emits `ui/notifications/size-changed` so the host iframe height tracks your rendered content. Without it the frame is fixed-height and tall renders get clipped — set it for any widget whose height depends on data.
---
## Widget → Host
@@ -63,6 +75,26 @@ card.querySelector("a").addEventListener("click", (e) => {
Host-mediated download (sandbox blocks direct `<a download>`). `content` is a base64 string.
```js
const csv = rows.map((r) => Object.values(r).join(",")).join("\n");
app.downloadFile({
name: "export.csv",
mimeType: "text/csv",
content: btoa(unescape(encodeURIComponent(csv))),
});
```
### `app.requestDisplayMode({ mode })`
Ask the host to switch the widget between `"inline"`, `"pip"`, or `"fullscreen"`. Check `getHostContext().availableDisplayModes` first; hide the control if the mode isn't offered. The host responds by firing `onhostcontextchanged` with new `displayMode` and `containerDimensions` — re-render at the new size.
```js
if (app.getHostContext()?.availableDisplayModes?.includes("fullscreen")) {
expandBtn.hidden = false;
expandBtn.onclick = () => app.requestDisplayMode({ mode: "fullscreen" });
}
```
---
## Host → Widget
@@ -84,9 +116,22 @@ app.ontoolresult = ({ content }) => {
Fires with the arguments Claude passed to the tool. Useful if the widget needs to know what was asked for (e.g., highlight the search term).
### `app.ontoolinputpartial = ({ arguments }) => {...}` / `app.ontoolcancelled = () => {...}`
`ontoolinputpartial` fires while Claude is still streaming arguments — use it to show a skeleton ("Preparing: <title>…") before the result lands. `ontoolcancelled` fires if the call is aborted; clear the skeleton.
### `app.getHostContext()` / `app.onhostcontextchanged = (ctx) => {...}`
Read and subscribe to host context`theme` (`"light"` / `"dark"`), locale, etc. Call `getHostContext()` **after** `connect()`. Subscribe for live updates (user toggles dark mode mid-conversation).
Read and subscribe to host context. Call `getHostContext()` **after** `connect()`. Subscribe for live updates (user toggles dark mode, expands to fullscreen).
| `ctx.` field | Use |
|---|---|
| `theme` | `"light"` / `"dark"` — toggle a `.dark` class |
| `styles.variables` | Host CSS tokens — pass to `applyHostStyleVariables()` so colors/fonts match host chrome |
| `displayMode` / `availableDisplayModes` | Current mode and which `requestDisplayMode` targets are valid |
| `containerDimensions.{maxHeight,width}` | Size your render to this instead of hard-coded px |
| `deviceCapabilities.touch` | Switch hover-only affordances to tap (`pointerdown`) |
| `safeAreaInsets` | Padding for notches / composer overlay |
```js
const applyTheme = (t) =>
@@ -129,14 +174,36 @@ No `{ notify }` destructure — `extra` is `RequestHandlerExtra`; progress goes
## Lifecycle
1. Claude calls a tool with `_meta.ui.resourceUri` declared
2. Host fetches the resource (your HTML) and renders it in an iframe
2. Host fetches the resource (your HTML) and mounts a **fresh iframe** for this call
3. Widget script runs, sets handlers, calls `await app.connect()`
4. Host pipes the tool's return value → `ontoolresult` fires
5. Widget renders, user interacts
6. Widget calls `sendMessage` / `updateModelContext` / `callServerTool` as needed
7. Widget persists until conversation context moves on — subsequent calls to the same tool reuse the iframe and fire `ontoolresult` again
7. Iframe persists in the transcript; **the next call to the same tool mounts another iframe** alongside it
There's no explicit "submit and close" — the widget is a long-lived surface.
There's no explicit "submit and close" — each instance is long-lived, but instances are not reused across calls.
### Supersession
Because earlier instances stay mounted, a click on a stale widget can `sendMessage` after a newer one has rendered. Detect this with a `BroadcastChannel` and make older instances inert:
```js
let superseded = false;
const seq = Date.now() + Math.random();
const bc = new BroadcastChannel("my-widget");
bc.onmessage = (e) => {
if (e.data?.seq > seq) {
superseded = true;
document.body.classList.add("superseded"); // opacity:.45; pointer-events:none
}
};
bc.postMessage({ seq });
// Guard outbound calls:
function safeSend(msg) {
if (!superseded) app.sendMessage(msg);
}
```
---

View File

@@ -0,0 +1,18 @@
# Connector-directory submission checklist
Pre-flight before submitting a remote MCP app to the Claude connector
directory. Each item is a hard review criterion.
| Area | Requirement |
|---|---|
| **Auth** | OAuth (DCR or CIMD) or **`none`** (authless). Static bearer tokens are private-deploy only and block listing. Authless is valid for public-data servers — the server holds any upstream API keys. |
| **Tool annotations** | Every tool sets `annotations.title` plus the relevant hints: `readOnlyHint: true` for fetch/search tools, `destructiveHint` / `idempotentHint` for writes, `openWorldHint: true` if the tool reaches an external system. |
| **Tool names** | ≤ 64 characters, snake/kebab case. |
| **Widget layout** | Inline height ≤ 500px, no nested scroll containers, 44pt minimum touch targets, WCAG-AA contrast in both themes. |
| **Theming** | `html, body { background: transparent }`, `<meta name="color-scheme" content="light dark">`, adopt host CSS tokens via `applyHostStyleVariables`. |
| **External links** | Use `app.openLink`. Declare each origin (e.g. `https://api.example.com`) in the connector's *Allowed link URIs* so the link skips the confirm modal. |
| **Helper tools** | Widget-only tools (geometry/image fetchers) carry `_meta.ui.visibility: ["app"]` so they don't appear in Claude's tool list. |
| **Screenshots** | 35 PNGs, ≥ 1000px wide, cropped to the app response only — no prompt text in frame. |
See `abuse-protection.md` for rate-limit and IP-tiering guidance once the
authless endpoint is public.

View File

@@ -122,23 +122,38 @@ that survives un-inlined.
---
## Dark mode
## Theme & host styles
```js
const applyTheme = (theme) =>
document.documentElement.classList.toggle("dark", theme === "dark");
The host renders the iframe inside its own card chrome — paint a **transparent** background and adopt host CSS tokens so the widget blends in across light/dark and across hosts.
app.onhostcontextchanged = (ctx) => applyTheme(ctx.theme);
await app.connect();
applyTheme(app.getHostContext()?.theme);
```html
<meta name="color-scheme" content="light dark" />
```
```css
:root { --ink:#0f1111; --bg:#fff; color-scheme:light; }
:root.dark { --ink:#e6e6e6; --bg:#1f2428; color-scheme:dark; }
:root {
--ink: var(--color-text-primary, #0f1111);
--sub: var(--color-text-secondary, #5a6270);
--line: var(--color-border-default, #e3e6ea);
}
html, body { background: transparent; color: var(--ink); }
:root.dark .thumb { mix-blend-mode: normal; } /* multiply → images vanish in dark */
```
```js
const { App, applyHostStyleVariables } = globalThis.ExtApps;
function applyHostContext(ctx) {
document.documentElement.classList.toggle("dark", ctx?.theme === "dark");
if (ctx?.styles?.variables) applyHostStyleVariables(ctx.styles.variables);
}
app.onhostcontextchanged = applyHostContext;
await app.connect();
applyHostContext(app.getHostContext());
```
`applyHostStyleVariables` writes the host's `--color-*` / `--font-*` / `--border-radius-*` tokens onto `:root`; the hex values above are fallbacks for hosts that don't supply them.
---
## Debugging

View File

@@ -0,0 +1,54 @@
# Payload budgeting
Hosts cap tool-result text. claude.ai and Claude Desktop truncate at roughly
**150,000 characters**; Claude Code at ~25k tokens. When a tool result exceeds
the cap, the host substitutes a file-pointer string in place of your JSON. The
widget then receives non-JSON in `ontoolresult`, `JSON.parse` throws, and the
user sees something like *"Bad payload: SyntaxError: Unexpected token 'E'"*
with no hint that size was the cause.
## Symptom → cause
| Symptom | Likely cause |
|---|---|
| Widget shows a JSON parse error on `content[0].text` | Result over the host cap; host swapped in a file-pointer string |
| Works for one query, breaks for "all of X" | Row count × column count crossed the cap |
| Works in MCP Inspector, breaks in Desktop | Inspector has no cap; Desktop does |
## Strategy
Cap your own payload at ~130KB and degrade in order:
1. **Ship full rows** when `JSON.stringify(rows).length` is under the cap.
2. **Prune columns** to those the rendering spec actually references. Walk the
spec for both `field: "..."` keys *and* `datum.X` / `datum['X']` inside
expression strings — if the spec aliases a column via a `calculate`
transform, the alias appears as `field:` but the source column only appears
as `datum.X`, and dropping it leaves the widget with NaN.
3. **Truncate rows** as a last resort and include `{ truncated: N }` in the
payload so the widget can label it.
```ts
const MAX = 130_000;
let out = rows;
if (JSON.stringify(out).length > MAX) {
const keep = referencedFields(spec); // field: + datum.X refs
out = rows.map((r) => pick(r, keep));
if (JSON.stringify(out).length > MAX) {
const per = JSON.stringify(out[0] ?? {}).length || 1;
out = out.slice(0, Math.floor(MAX / per));
}
}
```
## Heavy assets go via `callServerTool`, not the result
Geometry, image bytes, or any blob the widget needs but Claude doesn't should
be served by a separate tool the widget calls after mount:
```js
const topo = await app.callServerTool({ name: "get-topojson", arguments: { level } });
```
Mark that helper tool with `_meta.ui.visibility: ["app"]` so it doesn't appear
in Claude's tool list.

View File

@@ -1,6 +1,6 @@
---
name: skill-creator
description: Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, update or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.
description: Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.
---
# Skill Creator
@@ -391,7 +391,7 @@ Use the model ID from your system prompt (the one powering the current session)
While it runs, periodically tail the output to give the user updates on which iteration it's on and what the scores look like.
This handles the full optimization loop automatically. It splits the eval set into 60% train and 40% held-out test, evaluates the current description (running each query 3 times to get a reliable trigger rate), then calls Claude with extended thinking to propose improvements based on what failed. It re-evaluates each new description on both train and test, iterating up to 5 times. When it's done, it opens an HTML report in the browser showing the results per iteration and returns JSON with `best_description` — selected by test score rather than train score to avoid overfitting.
This handles the full optimization loop automatically. It splits the eval set into 60% train and 40% held-out test, evaluates the current description (running each query 3 times to get a reliable trigger rate), then calls Claude to propose improvements based on what failed. It re-evaluates each new description on both train and test, iterating up to 5 times. When it's done, it opens an HTML report in the browser showing the results per iteration and returns JSON with `best_description` — selected by test score rather than train score to avoid overfitting.
### How skill triggering works
@@ -435,6 +435,11 @@ In Claude.ai, the core workflow is the same (draft → test → review → impro
**Packaging**: The `package_skill.py` script works anywhere with Python and a filesystem. On Claude.ai, you can run it and the user can download the resulting `.skill` file.
**Updating an existing skill**: The user might be asking you to update an existing skill, not create a new one. In this case:
- **Preserve the original name.** Note the skill's directory name and `name` frontmatter field -- use them unchanged. E.g., if the installed skill is `research-helper`, output `research-helper.skill` (not `research-helper-v2`).
- **Copy to a writeable location before editing.** The installed skill path may be read-only. Copy to `/tmp/skill-name/`, edit there, and package from the copy.
- **If packaging manually, stage in `/tmp/` first**, then copy to the output directory -- direct writes may fail due to permissions.
---
## Cowork-Specific Instructions
@@ -447,6 +452,7 @@ If you're in Cowork, the main things to know are:
- Feedback works differently: since there's no running server, the viewer's "Submit All Reviews" button will download `feedback.json` as a file. You can then read it from there (you may have to request access first).
- Packaging works — `package_skill.py` just needs Python and a filesystem.
- Description optimization (`run_loop.py` / `run_eval.py`) should work in Cowork just fine since it uses `claude -p` via subprocess, not a browser, but please save it until you've fully finished making the skill and the user agrees it's in good shape.
- **Updating an existing skill**: The user might be asking you to update an existing skill, not create a new one. Follow the update guidance in the claude.ai section above.
---

View File

@@ -2,22 +2,52 @@
"""Improve a skill description based on eval results.
Takes eval results (from run_eval.py) and generates an improved description
using Claude with extended thinking.
by calling `claude -p` as a subprocess (same auth pattern as run_eval.py —
uses the session's Claude Code auth, no separate ANTHROPIC_API_KEY needed).
"""
import argparse
import json
import os
import re
import subprocess
import sys
from pathlib import Path
import anthropic
from scripts.utils import parse_skill_md
def _call_claude(prompt: str, model: str | None, timeout: int = 300) -> str:
"""Run `claude -p` with the prompt on stdin and return the text response.
Prompt goes over stdin (not argv) because it embeds the full SKILL.md
body and can easily exceed comfortable argv length.
"""
cmd = ["claude", "-p", "--output-format", "text"]
if model:
cmd.extend(["--model", model])
# Remove CLAUDECODE env var to allow nesting claude -p inside a
# Claude Code session. The guard is for interactive terminal conflicts;
# programmatic subprocess usage is safe. Same pattern as run_eval.py.
env = {k: v for k, v in os.environ.items() if k != "CLAUDECODE"}
result = subprocess.run(
cmd,
input=prompt,
capture_output=True,
text=True,
env=env,
timeout=timeout,
)
if result.returncode != 0:
raise RuntimeError(
f"claude -p exited {result.returncode}\nstderr: {result.stderr}"
)
return result.stdout
def improve_description(
client: anthropic.Anthropic,
skill_name: str,
skill_content: str,
current_description: str,
@@ -99,7 +129,7 @@ Based on the failures, write a new and improved description that is more likely
1. Avoid overfitting
2. The list might get loooong and it's injected into ALL queries and there might be a lot of skills, so we don't want to blow too much space on any given description.
Concretely, your description should not be more than about 100-200 words, even if that comes at the cost of accuracy.
Concretely, your description should not be more than about 100-200 words, even if that comes at the cost of accuracy. There is a hard limit of 1024 characters — descriptions over that will be truncated, so stay comfortably under it.
Here are some tips that we've found to work well in writing these descriptions:
- The skill should be phrased in the imperative -- "Use this skill for" rather than "this skill does"
@@ -111,70 +141,41 @@ I'd encourage you to be creative and mix up the style in different iterations si
Please respond with only the new description text in <new_description> tags, nothing else."""
response = client.messages.create(
model=model,
max_tokens=16000,
thinking={
"type": "enabled",
"budget_tokens": 10000,
},
messages=[{"role": "user", "content": prompt}],
)
text = _call_claude(prompt, model)
# Extract thinking and text from response
thinking_text = ""
text = ""
for block in response.content:
if block.type == "thinking":
thinking_text = block.thinking
elif block.type == "text":
text = block.text
# Parse out the <new_description> tags
match = re.search(r"<new_description>(.*?)</new_description>", text, re.DOTALL)
description = match.group(1).strip().strip('"') if match else text.strip().strip('"')
# Log the transcript
transcript: dict = {
"iteration": iteration,
"prompt": prompt,
"thinking": thinking_text,
"response": text,
"parsed_description": description,
"char_count": len(description),
"over_limit": len(description) > 1024,
}
# If over 1024 chars, ask the model to shorten it
# Safety net: the prompt already states the 1024-char hard limit, but if
# the model blew past it anyway, make one fresh single-turn call that
# quotes the too-long version and asks for a shorter rewrite. (The old
# SDK path did this as a true multi-turn; `claude -p` is one-shot, so we
# inline the prior output into the new prompt instead.)
if len(description) > 1024:
shorten_prompt = f"Your description is {len(description)} characters, which exceeds the hard 1024 character limit. Please rewrite it to be under 1024 characters while preserving the most important trigger words and intent coverage. Respond with only the new description in <new_description> tags."
shorten_response = client.messages.create(
model=model,
max_tokens=16000,
thinking={
"type": "enabled",
"budget_tokens": 10000,
},
messages=[
{"role": "user", "content": prompt},
{"role": "assistant", "content": text},
{"role": "user", "content": shorten_prompt},
],
shorten_prompt = (
f"{prompt}\n\n"
f"---\n\n"
f"A previous attempt produced this description, which at "
f"{len(description)} characters is over the 1024-character hard limit:\n\n"
f'"{description}"\n\n'
f"Rewrite it to be under 1024 characters while keeping the most "
f"important trigger words and intent coverage. Respond with only "
f"the new description in <new_description> tags."
)
shorten_thinking = ""
shorten_text = ""
for block in shorten_response.content:
if block.type == "thinking":
shorten_thinking = block.thinking
elif block.type == "text":
shorten_text = block.text
shorten_text = _call_claude(shorten_prompt, model)
match = re.search(r"<new_description>(.*?)</new_description>", shorten_text, re.DOTALL)
shortened = match.group(1).strip().strip('"') if match else shorten_text.strip().strip('"')
transcript["rewrite_prompt"] = shorten_prompt
transcript["rewrite_thinking"] = shorten_thinking
transcript["rewrite_response"] = shorten_text
transcript["rewrite_description"] = shortened
transcript["rewrite_char_count"] = len(shortened)
@@ -216,9 +217,7 @@ def main():
print(f"Current: {current_description}", file=sys.stderr)
print(f"Score: {eval_results['summary']['passed']}/{eval_results['summary']['total']}", file=sys.stderr)
client = anthropic.Anthropic()
new_description = improve_description(
client=client,
skill_name=name,
skill_content=content,
current_description=current_description,

View File

@@ -15,8 +15,6 @@ import time
import webbrowser
from pathlib import Path
import anthropic
from scripts.generate_report import generate_html
from scripts.improve_description import improve_description
from scripts.run_eval import find_project_root, run_eval
@@ -75,7 +73,6 @@ def run_loop(
train_set = eval_set
test_set = []
client = anthropic.Anthropic()
history = []
exit_reason = "unknown"
@@ -200,7 +197,6 @@ def run_loop(
for h in history
]
new_description = improve_description(
client=client,
skill_name=name,
skill_content=content,
current_description=current_description,