Authoring skills
A skill is the unit of capability the Data Studio (part of the Trust Infrastructure Platform) governs and serves: one slug, one MCP tool name, an input
schema, an output schema, and a lifecycle from draft to published. This page takes an author key from “I have a
key” to “my skill is published”. Authoring happens over MCP only; the Data Studio’s web workbench is for
governance, not authoring.
Read Getting started with the Data Studio first. Everything there applies to an author key, which can also consume, with one difference in how you connect (§2).
§1 Who this is for
You hold an author-tier key whose role grants capability:skill-write. Without that capability the write tools do
not register for your key (§4). If you only call skills, the Consumer reference is the companion
instead.
§2 Connect an author key
Connect as Getting started §2 describes, with one change: leave out lane=consumer. The consumer lane accepts
read-only keys only and refuses a key that can write, with HTTP 403 key_family_not_accepted.
claude mcp add --transport http --scope user tip-author \
"https://api.dev.trustinfrastructure.com/api/mcp/real-estate?surface=lean" \
--header "Authorization: Bearer $TIP_API_KEY"
The lean surface keeps the write tools your roles grant. Use the host that matches your key’s prefix (Getting started §1). Then check that the four write tools are listed:
tip-skill-create-from-bundletip-skill-updatetip-skill-commenttip-skill-get-bundle
If they are missing, see §4. tip-key-introspect shows your key’s family, roles and write capabilities.
§3 The four write tools
Each tool works only inside the ecosystem your key belongs to. A slug in another ecosystem is not found.
tip-skill-create-from-bundle: create a skill
Creates a skill from a tip-skill-bundle-v1 JSON artifact (§5).
// tools/call tip-skill-create-from-bundle
{
"bundle": {
"schemaVersion": "tip-skill-bundle-v1",
"slug": "your-skill-slug",
"manifest": { /* see §5 */ },
"promptMd": "...",
"tools": [],
"prefetch": null
},
"editComment": "First draft"
}
- Required bundle fields:
schemaVersion("tip-skill-bundle-v1"),slug,manifest,promptMdandtools.prefetchis optional; passnullwhen you have no pre-checks. - The new skill lands as
draft, visible to consumers only once you publish it (§6). - Idempotent on an active slug. If a draft or published skill already has the slug, the call returns that skill
with
alreadyExisted: trueand changes nothing. Usetip-skill-updateto edit it. - An archived slug can be reclaimed. Creating it again supersedes the archived skill, which is kept for audit, and
returns
reclaimedArchivedSlug: true. The new bundle must carry a version different from the archived one.
tip-skill-update: edit a skill
A partial update by slug: send only the parts of update you want to change.
// tools/call tip-skill-update
{
"slug": "your-skill-slug",
"update": {
"manifest": { "description": "Use when … (a sharper description after the first trials)" },
"intent_phrases": ["what is the zoning for this address", "look up the bylaw for this property"]
},
"editComment": "Tighten the description; add intent phrases"
}
updatetakesmanifest,promptMd,prefetch,tools,intent_phrasesandstatus. Insidemanifest, an unknown key is refused;inputs.schemaandoutputs.schemaupdate the skill’s schemas.- Idempotent. The same payload twice changes nothing the second time: the answer carries
noop: trueand the version stays. - Versioned. Each real change increments the edit version and is recorded in the skill’s history, with your key as
its author. The answer names
fieldsChanged. - Setting
statusis how a skill is published or archived (§6).
tip-skill-comment: add an audit comment
Adds a governance comment without changing the skill: why it was published, what it was tested against, why it was superseded. Comments are append-only and carry the key that wrote them.
// tools/call tip-skill-comment
{
"slug": "your-skill-slug",
"comment": "Tested against Toronto, Ottawa and London city halls: 3 of 3 returned the zoning designation."
}
comment must be a non-empty string.
tip-skill-get-bundle: read the bundle back
The inverse of create: returns the skill’s tip-skill-bundle-v1 artifact, with its status, edit version and
publication time.
// tools/call tip-skill-get-bundle
{ "slug": "your-skill-slug" }
// include drafts:
{ "slug": "your-skill-slug", "version": 0 }
By default it returns the latest published version. version: 0 widens it to the latest row in any state, which needs
capability:skill-write. “Not found” means the slug is not in your ecosystem, or it has no published version and you
left out version: 0.
§4 The capability gate
The four write tools register only when your key’s role grants capability:skill-write. Tier alone is not enough:
registration is role-driven. If the tools are missing from your tool list:
- your role does not grant
capability:skill-write; or - your key is a
consumerkey.
Either way, ask your Data Studio contact for a role that grants it, or for an author key.
§5 The bundle
A tip-skill-bundle-v1 is the JSON artifact you author. An example for a lookup skill scoped to Ontario:
{
"schemaVersion": "tip-skill-bundle-v1",
"slug": "ontario-zoning-bylaw-lookup",
"manifest": {
"name": "Ontario zoning bylaw lookup",
"description": "Use when you need the current zoning designation or bylaw text for an Ontario property by civic address. Returns the bylaw section, the designation code and the municipality's source URL.",
"category": "data_retrieval",
"subtype": null,
"version": "1.0.0",
"intent_phrases": [
"what is the zoning for this address",
"look up the bylaw for this property",
"fetch the zoning designation"
],
"scopes": ["read:property"],
"tags": [
"geography:CA-ON",
"domain:property",
"archetype:query"
]
},
"promptMd": "## Use when\n\nThe caller has a confirmed Ontario civic address and needs the zoning bylaw...\n\n## Inputs\n\n- `address`: the full civic address...\n",
"tools": [],
"prefetch": null
}
The manifest fields:
name: a human-readable label. Required.slug: kebab-case, unique in your ecosystem. Required.description: by convention “Use when …” followed by at least three concrete triggers. Required.category: one ofdata_access,data_retrieval,domain_computation,orchestrated_packageorgeneral_tooling. (systemexists but is internal and cannot be authored here.) Required, and checked on create.subtype:metafor skills that work on other skills (builders, optimizers), otherwisenull.inputs.schema/outputs.schema: JSON Schema for what the skill takes and returns. Needed for most categories; the output schema is optional fordomain_computation. Input property names must be valid tool-argument names: 1 to 64 letters, digits,_,.or-, so never a leading$.version: semver.intent_phrases: plain-language triggers that discovery matches on.tags: canonical<axis>:<value>strings (below).prefetch:{ "checks": [...] }ornull: checks run before the skill.tools: tool declarations inside the skill. Most skills use[].
Tags
Tags decide who can see a skill (Consumer reference §2), so they are checked on every write. Each is <axis>:<value>:
| Axis | Values | Example |
|---|---|---|
geography: | ISO 3166-1 alpha-2, or 3166-2 with a lower-case place suffix | CA, CA-ON, CA-ON-toronto, US-WA-whatcom |
domain: | a slug | property, finance |
archetype: | a slug | query, pipeline, transactional |
jurisdiction: | like geography:, for where a source belongs | CA-BC |
mcp_visibility: | consumer or admin (set for you; see below) | |
capability:, app: | closed sets of values |
An unknown axis, or a value outside a closed set, is refused with a reason for each tag, and nothing is written. The
mcp_visibility: tag is stamped from the skill’s visibility on every write, so you do not set it yourself: a new skill
is consumer-visible.
§6 Publishing
draft ──tip-skill-update {status: "published"}──▶ published ──{status: "archived"}──▶ archived
└─ first publish of a county- or city-level skill ─▶ in_review ─ approved by the ecosystem admin ─▶ published
- Publish by setting
status.tip-skill-updatewithupdate: { status: "published" }publishes the skill. Writestatusonly; the published flag is derived from it. - Publishing is checked. Before the status changes, the skill’s manifest must pass the schemas the Data Studio’s consumers validate against (including the tool-argument naming rule in §5), and an orchestrated skill’s steps must not hand caller input to a fixed column. A failure is refused with every error named, and the skill stays a draft.
- The first publish of a county-, city- or municipality-level skill goes to review. It lands as
in_review, and the ecosystem’s admin approves it into the catalog. Later publishes of the same skill are direct. - A published skill must keep passing. An edit to a published skill’s schemas is refused if the skill would no longer pass the check it was published under.
- Archive by setting
status: "archived". The skill leaves the catalog and is kept for audit.
Before you publish
There is no automatic scoring. Check your skill against the bar for its category:
| Category | Before publishing |
|---|---|
data_access | Its data source has passed validation. |
data_retrieval, general_tooling | One call works; then at least three inputs that differ in shape, not three copies of the easy case, with at least 80% passing. |
domain_computation | At least three edge cases, each giving the expected answer every time. |
orchestrated_package | Every skill it calls is published; one call works; at least three places pass. |
Record what you tested with tip-skill-comment.
§7 Ownership
- Any author key in your ecosystem can edit any skill in your ecosystem. Authoring is collaborative by default.
- Ownership is attribution. The key that created a skill is recorded once, at creation, and cannot be changed by an update. Each edit is recorded with the key that made it.
- Ecosystems stay apart. A key writes only inside the ecosystem it was issued for, whatever its capabilities.
§8 Check that the publish landed
After tip-skill-update { status: "published" } succeeds:
tip-skill-get-bundle { slug }returns the skill withstatus: "published". If it reports no published version, the skill went toin_review(§6) or the status was not set.discover-skillswith aqueryfrom your intent phrases finds it, if your key’s roles reach its tags.- Call it once with
tip-invoke-skill, to prove it runs, not only that it is listed.
The tool list is refreshed on every write, so a new skill shows at once for keys that can see it.
§9 Common errors
1. A tag is refused
Symptom. Create or update is refused with Invalid tags, and the details list each failing tag with its axis,
value and reason (an unknown axis, or a value outside a closed set).
Fix. Correct the tag. A typo in a capability: value matters most: it silently changes which tools register, which
is why it is refused at write time.
2. The write tools are missing
Symptom. Your tool list has the discovery tools but no tip-skill-* tools, or a call to one is “tool not found”.
Fix. Your role does not grant capability:skill-write (§4). Ask your Data Studio contact.
3. A publish is refused
Symptom. Cannot publish: manifest fails consumer-schema validation, followed by the list of errors.
Fix. Each error names the field. The usual ones are a missing description or input schema, or an input property
name with a leading $. Fix them with tip-skill-update and publish again.
4. 401 or 403 on connect
A 401 means the key does not match the host (Getting started §1). A 403 key_family_not_accepted means you connected
with lane=consumer: leave it out for an author key (§2).
See also
- Getting started with the Data Studio: connecting, discovery, prices and the error codes.
- Consumer reference: the three gates that decide who sees your published skill.