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
6 changes: 6 additions & 0 deletions .github/workflows/catalog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ on:
pull_request:
paths:
- "catalog/*/*.json"
- "catalog-icons.json"
- "icons/**"
- "ai-catalog.json"
- "scripts/generate_ai_catalog.py"
- "requirements.txt"
- "tests/*.py"
- ".github/workflows/catalog.yml"
- "CONTRIBUTING.md"
- "README.md"
push:
branches:
- main
Expand All @@ -32,6 +37,7 @@ jobs:
with:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event.pull_request.head.ref || github.ref }}
- run: python3 -m pip install -r requirements.txt
- run: python3 -m unittest discover -s tests
- run: python3 scripts/generate_ai_catalog.py
- name: Update pull request
Expand Down
152 changes: 152 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,157 @@ Do not create a copied descriptor to represent a server that is already imported
Registry references do not identify a file in this repository. Do not attach
`metadata.sourceSet` or `metadata.repoPath` pointing to a copied descriptor.

#### Reviewed resource icons

Icons are optional. Declare them in the root `catalog-icons.json` overlay, for
both contributor-managed and registry-imported resources. Do not copy a registry
descriptor or create another resource entry to attach an icon. Use the exact
generated `urn:air:` identifier from `ai-catalog.json`, not the source `urn:ai:`
identifier, a display name, or a descriptor URL.

The tooling-only change does not add an overlay file; create it when adding the
first approved declarations. Artwork and production declarations are reviewed
in a separate change.
The following is a **synthetic example**, not an available asset, real digest,
or evidence of permission:

```json
{
"icons": [
{
"identifier": "urn:air:registry.modelcontextprotocol.io:example:weather",
"url": "https://raw.githubusercontent.com/github/agentfinder-catalog/0123456789abcdef0123456789abcdef01234567/icons/example/weather.png",
"provenance": {
"sourceUrl": "https://example.com/weather-artwork",
"license": "CC0-1.0",
"permissionUrl": "https://example.com/weather-artwork-permission",
"sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
}
]
}
```

Omit `version` to cover all versions of that exact identifier. To restrict an
icon to one existing version, add a nonempty `version` string to the declaration.
Do not supply `null`. Duplicate or overlapping declarations fail validation,
including an identifier-wide declaration combined with an exact-version one.
Unmatched identifiers or versions also fail; explicitly maintain declarations
when a registry resource disappears or a version-specific reference rolls over.
Prefer identifier-wide declarations when the artwork legitimately covers all
versions.

The generator applies the overlay after normal entry selection and registry
imports, adding only the scalar
`metadata["com.github.agentfinder.icon.url"]`. It preserves identifiers, versions,
descriptor URLs, native data, and other metadata. Provenance is not published in
the generated entry. The icon key is reserved for the overlay: do not put it
directly in contributor-managed entries or registry inputs. Unknown overlay
fields and duplicate JSON keys are rejected. An absent overlay is treated as
empty for compatibility with older checkouts.

For the example above, the generated entry is:

```json
{
"identifier": "urn:air:registry.modelcontextprotocol.io:example:weather",
"displayName": "Weather",
"type": "application/mcp-server+json",
"version": "1.0.0",
"url": "https://api.mcp.github.com/v0.1/servers/example%2Fweather/versions/1.0.0",
"metadata": {
"com.github.agentfinder.icon.url": "https://raw.githubusercontent.com/github/agentfinder-catalog/0123456789abcdef0123456789abcdef01234567/icons/example/weather.png"
}
}
```

This input key is not a new client response field. Once service support is
deployed, Agent Finder emits the optional nested `metadata.github.icon.url`.
A supported curated URL takes precedence over a supported descriptor-declared
icon. Removing the curated declaration restores descriptor-icon fallback;
it does not suppress a descriptor icon. Invalid service-side declarations also
fall back. Invalid catalog-authored declarations instead fail generation.
Clients keep their resource-type fallback when no supported icon is available
or an image cannot be loaded.

##### Asset review and validation

- Place reviewed assets at `icons/<publisher>/<asset>.png`. Publisher and asset
names start with an ASCII letter, digit, underscore, or hyphen; remaining
characters may also include dots. Asset paths cannot contain symlinks.
- Use **static PNG** files, at most **256 KiB (262144 bytes)**, with width and
height between **1 and 512 pixels**. Pillow verifies PNG integrity and decodes
the image; animated images are rejected. Validation follows Pillow's PNG
decoder rather than implementing a separate strict chunk grammar (for example,
it does not reject otherwise decodable PNGs solely for trailing bytes).
These checks are not image sanitization; reviewers must inspect the rendered image.
- URLs must use HTTPS and the exact `raw.githubusercontent.com` host, this
repository, a full lowercase 40-hex commit reference, and the asset path.
Mutable refs, credentials, explicit ports, query strings, fragments, encoded
paths, other hosts/repositories, and other image formats are rejected.
- Supply `sourceUrl` identifying the original artwork, `license` identifying its
license or explicit permission, `permissionUrl` pointing to reviewable evidence
that redistribution of these bytes is permitted, and a lowercase `sha256` of
the actual file. Alternatively, when approval is given without a URL, supply
`sourceUrl`, `sha256`, and a nonempty `approval` attestation describing the
explicit authorization for public redistribution; do not invent a license or
permission link. These two provenance forms are mutually exclusive.
Source and permission URLs must be absolute HTTPS without
credentials or ports. Generator checks establish syntax and a matching local
digest, **not legal permission, public availability, or ownership**. Reviewers
must verify the evidence and any attribution or notice requirements.
- Do not infer logos from repository-owner avatars or acquire/copy vendor artwork
without verified redistribution permission. The repository's MIT license
does not establish permission for third-party artwork. An icon does not prove
vendor ownership, endorsement, or official-product approval.

Compute a file's digest with:

```bash
shasum -a 256 icons/<publisher>/<asset>.png
```

##### Adding, replacing, and removing icons

**Add:** obtain permission and fulfill any required notices first. Publish the
reviewed asset in an asset-only commit, then use that existing commit's raw URL
in a separate declaration change. A declaration cannot pin the SHA of its own
containing commit. Reviewers must fetch the public pinned URL and verify its bytes
against the recorded SHA-256: the generator checks the file in the current
checkout, not the remote asset at that commit. Regenerate and review
`ai-catalog.json`; only the intended icon metadata should change.

**Replace:** publish the newly reviewed asset first, then update its immutable URL,
provenance, and digest together. Changed image bytes must have a changed URL.
Do not merely overwrite an asset while retaining an old pinned URL. If different
resource versions need different bytes, use distinct paths so all declared assets
can be checked in the current tree.

**Remove:** remove the overlay record and regenerate. Delete an unused current
asset only after removing all declarations that reference it. Historical pinned
bytes remain retrievable; deleting the current file does not revoke old URLs.
The service owner handles enrichment invalidation and reconciliation so an
addition, replacement, or removal takes effect in responses.

Validate icon changes with the normal generation commands below and:

```bash
python3 -m unittest discover -s tests
```

Tooling may land before service support only if the empty overlay leaves generated
resources unchanged. **Production declaration publication must follow deployed
github/agentfinder#557 foundation and github/copilot-ecosystem#1625 service
support**, plus verified redistribution permission. Catalog tooling alone is
not end-to-end icon delivery.

The current ARD specification is
[v0.91 (Proposal)](https://github.com/ards-project/ard-spec/blob/49eb4df6f3841ccecc5c31d5175117337b568bdf/spec/ard.md);
the catalog envelope remains `specVersion: "1.0"`. Both current entry and catalog
schemas permit scalar metadata extensions, which is why this declaration is flat.
This change does not adopt JSON-LD contexts or imply support for every behavior
in the latest proposal.

#### Canvas-only plugins

Catalog entries for plugins whose functionality consists entirely of a GitHub Copilot
Expand All @@ -108,6 +259,7 @@ Make sure your file is valid JSON, then regenerate and check the ARD ingestion c

```bash
python -m json.tool catalog/<your-publisher>/<augment-name>.json
python3 -m pip install -r requirements.txt
python3 scripts/generate_ai_catalog.py
python3 scripts/generate_ai_catalog.py --check
```
Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,38 @@ Each augment is a single JSON file under the publisher's directory. The publishe

These per-entry files are the source of truth for contributor-managed entries. The root `ai-catalog.json` is a generated Agentic Resource Discovery (ARD) ingestion artifact that also includes missing entries from GitHub's public MCP catalog. Do not edit it by hand; regenerate it with `python3 scripts/generate_ai_catalog.py`.

Install the generator's image-validation dependency first with
`python3 -m pip install -r requirements.txt` (preferably in a virtual environment).

The Catalog workflow checks the [GitHub MCP Registry](https://api.mcp.github.com/.well-known/ai-catalog.json) hourly, independently of repository changes, and opens or updates the `automation/update-ai-catalog` pull request when the generated catalog changes. This refresh picks up registry additions and current server-version references; it does not query the general public MCP registry. Refresh changes still require the pull request to be merged before they reach the main-branch catalog. GitHub Actions schedules can be delayed, and a manual workflow run on `main` uses the same publication flow.

## Optional reviewed icons

`catalog-icons.json` is an identity-keyed overlay for both local and
registry-imported resources. This tooling-only change does not add the file;
artwork and production declarations are reviewed separately. A missing file
means no curated icons.
Declarations use the existing generated `urn:air:` identifier
and optional exact version, without duplicating resources or changing descriptor
URLs. Generation adds only the scalar `metadata["com.github.agentfinder.icon.url"]`;
source provenance stays in the overlay.

Reviewed assets belong under `icons/<publisher>/<asset>.png`, with recorded
redistribution permission or an explicit approval attestation, a matching SHA-256,
and immutable commit-pinned HTTPS
`raw.githubusercontent.com` URLs. Initial validation permits static PNG files up
to 256 KiB and 512 by 512 pixels. See
[the icon contribution guide](CONTRIBUTING.md#reviewed-resource-icons) for exact
fixtures, validation, and addition/replacement/removal instructions. Icons imply
neither endorsement nor official-product ownership.

Production publication of declarations follows deployed
[github/agentfinder#557](https://github.com/github/agentfinder/pull/557) and
[github/copilot-ecosystem#1625](https://github.com/github/copilot-ecosystem/issues/1625)
service support. Clients continue using optional `metadata.github.icon.url` and
their existing fallbacks. Catalog validation does not mean the service fetches or
validates image bytes.

## Contributing

Want to list your skill or MCP server in the catalog? See **[CONTRIBUTING.md](CONTRIBUTING.md)** for the full guide, including the JSON schema, validation steps, and PR process.
Expand Down
Loading
Loading