# Class Profiles

[![checks](https://github.com/sylin-org/classprofiles/actions/workflows/validate.yml/badge.svg)](https://github.com/sylin-org/classprofiles/actions/workflows/validate.yml)

**Shared contracts for MCP capabilities, so an agent can use a server it has never seen.**

A standards proposal and a working prototype. Not a standard, not adopted, and not yet implemented by anyone. → [classprofiles.org](https://classprofiles.org)

## The problem

One server calls it `create_event`. One calls it `add_appointment`. One went with `scheduleItem`. Same job, three dialects, and an agent that spends its attention on translation instead of the work.

MCP revision [`2026-07-28`](https://modelcontextprotocol.io/specification/2026-07-28) made tools callable and governable, and deliberately left meaning out. It even names the collision — and offers prefixing, which tells you *which server said it*, never *what it means*. It also requires clients to treat tool annotations as **untrusted**. So the wire has a slot for behavioral hints, and the specification correctly says not to believe them.

We measured how wide the gap is. Across 300 of the most-used listings in one directory:

- **9,390 declared members carry zero tool annotations.** Not one hint, anywhere.
- **Something reference-shaped appears in 164 listings under 894 distinct spellings.**
- **Three retrieval arguments — the query, how many, where from — appear under eleven names.**

Limits and full counts: [`FINDINGS.md`](research/discovery/FINDINGS.md).

## The proposal

A **Class Profile** is a contract for one kind of capability. It names a handful of operations, what goes in and comes out, which parts are optional, and what you lose when a part is missing.

Take the useful idea from USB, and take the right one — not certification, not class codes. *You plug in a display the host has never seen, and a picture appears.* Not because that display is interchangeable with every other; because the basic job of a display is defined, and every display implements it.

Three levels. Not levels of quality — levels of **universality**:

| | Display | Here |
|---|---|---|
| **Everyone** | Geometry | **Core baseline** — the floor. Mandatory, small, all-or-nothing. |
| **Some** | Other modes, declared if present | **Facet** — an optional job, declared by exact version, never assumed. |
| **One** | 3D, in its own driver's fields | **Vendor member** — a real difference that stays visible without being forced on anyone. |

The floor is governed by a **plug-in test**: *a thing that cannot do this is not a member of this class* ([`decisions/0002`](decisions/0002-the-plug-in-test.md)). Routing is on semantic identity, so a host renaming a tool changes nothing. Nothing enforces any of it — an agent that has learned a profile simply does not compose the wrong call, and a server in an unfamiliar dialect costs what it always cost.

**→ [Read the explainer](EXPLAINER.md)** for why tool search does not solve this, who benefits in what order, and what we do not know.

## Two worked classes

One example proves nothing about a framework, so there are two, picked to be as unlike each other as possible.

**[`calendar`](profiles/calendar/)** — records you own, durable identifiers, bounded effects, a credential you hold, loud failures, time as the entire subject. Six Core verbs; invitations, recurrence, reminders, RSVP and tombstone facets; one vendor member.

**[`operator`](profiles/operator/)** — driving a browser, a desktop, a terminal on someone's behalf: a live surface you do not control, references that go stale inside one turn, effects the page decides, silent failure (*did the click land?*), time irrelevant. Four Core verbs over any surface; browser, desktop and screenshot facets.

Almost nothing in common, and both describe the same way. A display and a mass-storage device share no purpose whatsoever, yet both enumerate, both present a class contract, both keep a vendor escape hatch, and both work on a host that has never seen them. **The framework is the proposal; the two contracts are only evidence that it is not domain-specific.**

Between them: two descriptors and eleven fixture documents holding 31 scenarios.

## Start here

| You want to | Read |
|---|---|
| Use a capability | [`calendar/SKILL.md`](profiles/calendar/SKILL.md) · [`operator/SKILL.md`](profiles/operator/SKILL.md) |
| Review a contract | [`calendar/profile.json`](profiles/calendar/profile.json) · [`operator/profile.json`](profiles/operator/profile.json) |
| Read the reasoning | [`calendar/PROFILE.md`](profiles/calendar/PROFILE.md) · [`operator/PROFILE.md`](profiles/operator/PROFILE.md) |
| Inspect the cases | [`calendar/fixtures/`](profiles/calendar/fixtures/) · [`operator/fixtures/`](profiles/operator/fixtures/) |
| Implement one | [`guides/build-a-server.md`](guides/build-a-server.md) |
| Wrap an existing server | [`guides/wrap-a-server.md`](guides/wrap-a-server.md) |
| Challenge the design | [`spec/`](spec/) · [`decisions/`](decisions/) · [`PRIOR-ART.md`](PRIOR-ART.md) |
| See the evidence | [`research/discovery/FINDINGS.md`](research/discovery/FINDINGS.md) |
| Contribute | [`CONTRIBUTING.md`](CONTRIBUTING.md) |

## Existing servers do not have to change

A **projection** presents a profile's verbs backed by an unmodified upstream. Someone writes the mapping once; it is reviewed, frozen, and behaviorally tested. A host can do this today without waiting for a vendor, and the publisher can adopt the same artifact later.

A projection passes the identical suites as a native implementation — `via: native` and `via: projected` record provenance, never grade. Coverage is declared honestly: every upstream tool in the mapped domain is `mapped`, `approximated` with a readable note, `raw_only`, or `unmapped`. **Silent loss is a specification violation.**

## What is real, and what is not

Real: two reviewable contracts with explicit Core, facet, and degradation boundaries; deterministic fixtures making the intended behavior concrete; a measured corpus; a local simulation showing native and projected backends producing the same comparable outcome from different traces.

Not real yet, stated plainly because the proposal is worth less if this part is vague:

- **No independent implementations.** Nobody has built two backends and run the same journey across both. That is the empirical crux and it is unanswered.
- **No runner, no passing claims.** The conformance model is specified; nothing has executed it. The website demonstration is a simulation, not evidence.
- **No capability map.** Two classes is not a catalogue, and names in the corpus do not carry function — a map is declared by authors, not derived from tool names ([F8](research/discovery/FINDINGS.md)).
- **No digests.** Canonicalization is decided (RFC 8785) but cross-language test vectors do not exist, so nothing can carry a real one. Immutability begins only at publication.

**What would change our mind:** two implementations reading one contract differently means it is ambiguous, which is a defect. A real backend that cannot express Core honestly means Core is too big. A smaller design that completes the same jobs wins. Prior art that already solves this is a successful outcome.

## Status and what comes next

Everything here is amendable. Maintainers accept changes in public with a short rationale; the most persuasive evidence is executable or observed.

A persuasive milestone needs a public runner for the fixtures, two genuinely different backends, the same agent journey working across both without vendor branching, and published implementer feedback. If that needs backend-specific reasoning, or the common contract turns out too lossy, this should change or stop.

MCP defines a route for work of this shape — the **SEP Extensions Track**. Recording it is not a claim that Class Profiles will take it or that it would be accepted; it is useful because it states the entry bar precisely:

| Requirement | Status |
|---|---|
| RFC 2119 normative language | Present in [`spec/`](spec/) |
| An associated working or interest group | **Absent** |
| A reference implementation in an official SDK, *before* review | **Absent** — the same gap as the implementation milestone |
| A specification of the extension's settings object | The card ([`spec/01 §6`](spec/01-concepts.md#card)); identifier `org.classprofiles/profiles` ([`decisions/0001`](decisions/0001-mcp-2026-07-28-alignment.md)) |

The two lists want the same artifact, so the work is not duplicated. The missing group is a **social** prerequisite, not a technical one, and no amount of specification work substitutes for it.

`org.classprofiles/profiles` is a reserved-by-convention reverse-DNS name under a domain this project controls, not an allocation by anyone.

## Relationship to Shiguchi

[Shiguchi](https://github.com/sylin-org/shiguchi) is a separate reference toolkit from which this was extracted. Class Profiles holds the contract; Shiguchi is one possible consumer. Keeping them apart lets other implementations evaluate the proposal on equal terms.

## License

[Apache-2.0](LICENSE), so implementers can copy, adapt, test, and challenge this, including in commercial work. [NOTICE](NOTICE) records provenance.
