The resource surface
What this server offers to be picked, and what a picker chooses by.
Factory::resources() declares the list and
Factory::skillReferences() the one template behind it;
Sdk\ResourceHandler and
Sdk\SkillReferenceHandler answer
a read. Everything offered is a file this package ships, so reading one reaches
no installation and no network.
The tool surface is the other thing a client is offered,
and it has a page per tool because a tool has a schema and a recorded answer.
This is one page, because what a resource obliges is the same for every entry
and the entries themselves are enumerated live under typo3://guides.
Picked, not called#
A resource is picked by the host application or by the user, where a tool is called by the model in the middle of a task. That is the protocol's own distinction, and it decides everything else about this surface.
A tool explains itself in the answer it returns. A resource has its list entry
and nothing else, so description, annotations.priority and size are
what the choice is made on rather than decoration —
R-ANS-022.
The model's route into the same prose while it works is a tool:
typo3_rule_lookup searches the documents, and typo3_task_guide names the
workflow that owns the task it recognized.
The four shapes#
- ``typo3://guides`` — the index: the purpose, coverage and routing this client is offered, plus every document and skill with its URI, and each skill's references. The one to read first, and the one that enumerates the rest.
- ``typo3://guides/{documentId}`` — one document from
knowledge/documents/, which is also the corpustypo3_rule_lookupsearches. Mostly the core's own process. - ``typo3://skill/{skillId}/SKILL.md`` — one published task workflow from
skills/. Mostly extension, sitepackage and project work.bin/typo3-dev-companion installwrites the same file into the client's own skills directory, and this is the route for a client that never ran it. Published means the skill's own front matter does not declare it a draft: one that does is a directory inskills/and is offered nowhere. - ``typo3://skill/{skillId}/references/{file}`` — what a workflow hands over at a step. A resource template rather than one list entry each, because these are followed from the body that names them, and a checklist offered beside its own workflow is an entry nobody can choose between.
Two families rather than one, because the documents alone serve one audience. Most of that corpus is the core's own process, and most of the workflows are the work outside it, so offering both is what leaves each of the three audiences of R-AUD-001 something to pick.
Which of them an entry holds for is read off knowledge/server-scope.json and
nowhere else. Every document and every published skill is named by a covered
topic, and that topic's scope is what the description and the priority are
derived from. ScopeTest holds it in both directions, so a skill no topic
names fails the suite rather than reaching an extension author as core-only.
TYPO3_DEV_COMPANION_EXCLUDE_TOOLS reaches the index and not the list.
Coverage::offered() drops a topic nothing left can answer, so the index a
client reads matches the tools it has; the resources stay. Excluding a tool
takes away a call, not a document.
The skill URI#
A skill is a directory, and what is picked has to be the whole of what was
picked. The body is short routing, and every one of them opens by sending the
reader to references/base.md. Served at typo3://skill/{id}/SKILL.md, the
relative links that prose already carries resolve by ordinary URI rules onto the
URIs the template answers. Nothing is rewritten and nothing is assembled: the
published bytes go over the wire as they were written.
Dropping the file name is the simplification not to make. Those links would resolve one segment higher, onto URIs nothing serves, and the body would still read complete — the first reader to follow one is how anybody finds out.
references/base.md is a file in no skill in this checkout.
skills/base.md is the single copy, written into
each published directory by Installer and served here from that same file
(D-SKL-001).
So the resource is the file a client would have had if it had run the install.
What a picker reads#
- ``description`` — what the entry is and who its answers oblige. A document's comes from the covered topic; a skill's from its own front matter, in front of which stands the sentence saying it is a workflow to follow rather than a page to read. Neither is written a second time, so neither can drift from what it describes.
- ``annotations.priority`` — the ordering, and nothing else. The index sits
above everything it lists, what holds wherever the caller is working above
what stops at the core, and the references below all of them, because one is
read at the step that sends the reader to it. The numbers in
Factoryare a scale a picker sorts by, and the distance between two of them carries no meaning. - ``size`` — the bytes the handler really serves, so a client knows what
reading one costs. For the index that is the encoded JSON rather than a file
on disk, and
ResourceSurfaceTestasserts every declared size against what a read returns.
Two fields the spec has stay absent, and the first is where the confusion is:
- ``annotations.audience`` is the protocol's
userandassistant, the SDK'sRoleenum. It is never the three audiences ofR-AUD-001, which are not values it takes. Everything here is for both roles, so the field says nothing and is left off, andResourceSurfaceTestfails on a resource that sets it. - ``annotations.lastModified`` is in the spec revision the SDK speaks and is
carried by no
Mcp\Schema\Annotationsat the mcp/sdk version incomposer.lock, which hasaudienceandpriorityalone. It is recorded as unavailable rather than faked through_meta.
What is generated#
bin/cli tools:index writes the tool reference because each page restates a
description and two schemas that a class declares. The installed skill catalog
at The installed task skills is generated for the same reason: it is
where a person compares and reads the published workflows before installing.
bin/cli documentation:prepare copies the same Markdown the installer
publishes into the site source and adds one embedding page per skill.
There is no document-resource catalog in the manual. Those entries are already
enumerated where they cannot go stale: the typo3://guides index is built
from the same functions, and knowledge/server-scope.json names every
document with the scope it is offered under. A generated table would be a third
copy, and its size column would change on every edit to a knowledge document.
What is written here is the half no generator produces: what a resource is, why the skill URI carries the file name, and why two fields of the spec are empty. That changes when the shape changes, which is a commit somebody writes prose for in any case.
What holds it#
ResourceSurfaceTest— that every resource says what it is, declares the size a read really costs, sorts where its audience puts it, claims no audience the protocol does not mean, and that every link a skill writes resolves onto a URI this server answers.ScopeTest::everyKnowledgeDocumentIsAnnouncedByTheScopeandScopeTest::everyPublishedSkillIsAnnouncedByTheScope— that the coverage names each entry, which is where its description and its priority come from.StdioServerTest::theResourceListCarriesWhatAPickerChoosesByandStdioServerTest::aTaskWorkflowIsServedWithWhatItSendsItsReaderTo— the list and both families as they go over the wire, including the reference a body sends its reader to.