How agents load skills

The two MCP tools an employee's AI client uses to find a skill and read it, and what comes back

An employee’s AI client reaches skills through the same MCP endpoint it already uses for tools. Workforce serves two built-in tools for it, list_skills and retrieve_skill, alongside search_tools and request_tool_access on https://ah-api.merge.dev/mcp. Both are served only once Merge has enabled skill retrieval for your org, so on an org without it the endpoint advertises the tool access tools and nothing else.

There is nothing to install and nothing to sync. A skill published a moment ago is retrievable on the next call, and a client already connected to the endpoint has both tools without reconnecting. The Workforce desktop client writes the MCP configuration that points a client at this endpoint, but it does not copy skills to the machine: retrieval is always a call.

The retrieval pattern

Skills load in two or three steps, so a client spends context only on what it needs.

  1. list_skills returns the skills available to the employee making the call, as slug, name, description, and referenced Connectors. No instruction bodies.
  2. retrieve_skill with a slug returns that skill’s full SKILL.md plus the list of files bundled with it.
  3. retrieve_skill with a slug and a path returns one bundled file, if the instructions call for it.

Most work stops at step two. Step three is what keeps a long reference document out of every retrieval that does not need it.

list_skills

Lists the skills this employee can use. The set is resolved per person, not per org:

  • Skills published to the whole organization
  • Skills published to a Group the employee belongs to
  • The employee’s own personal skills
  • Merge-provided skills you have enabled

Two employees in the same org can therefore get different results from the same call, which is the point of Group and personal reach. Change someone’s Groups in your identity provider and their library changes with them. See Who a skill reaches.

ParameterRequiredDescription
keywordNoFilters to skills whose name or description contains this text

The keyword filter matches name and description only. Skill bodies are not searched, which is why a skill’s description has to carry the words people use for the task. See Writing a skill.

{
"skills": [
{
"slug": "expense-report-review",
"name": "Expense report review",
"description": "Review a submitted expense report against the T&E policy and either approve it or send it back with the line items that need receipts.",
"referenced_connectors": ["expensify", "slack"]
}
]
}

Unpublished skills, drafts, submissions awaiting review, Merge-provided skills you have not enabled, and skills scoped to a Group or a person the caller is not do not appear.

retrieve_skill resolves against the same set, so a slug the caller cannot reach returns not found rather than a permission error. A guessed slug tells a client nothing about what exists.

retrieve_skill

Returns a skill’s instructions, or one of its bundled files.

ParameterRequiredDescription
skillYesThe skill’s slug, from list_skills
pathNoA bundled file path, taken from the manifest returned by the pathless call

Called with a slug alone, you get the instructions and the manifest:

{
"skill": {
"slug": "expense-report-review",
"name": "Expense report review",
"version": 3,
"skill_md": "# Expense report review\n\n## Steps\n\n1. Pull the report with `expensify__get_report`...",
"manifest": ["SKILL.md", "references/te-policy.md", "examples/rejection-message.md"],
"referenced_connectors": ["expensify", "slack"]
}
}

version is the published version number the client read, which makes “which instructions produced this run” answerable later.

Called with a path from that manifest, you get the one file:

{
"skill": {
"slug": "expense-report-review",
"version": 3,
"path": "references/te-policy.md",
"encoding": "utf-8",
"content": "# Travel and expense policy\n\nMeals are reimbursable up to $75 per day..."
}
}

Text files come back as UTF-8 in content. Binary files come back base64-encoded, with encoding saying which, so the caller knows how to decode.

A path that is not in the skill’s manifest returns not found. A client cannot read outside a skill’s bundle, and cannot reach another skill’s files through a path.

What clients get, and what they do not

retrieve_skill always serves the currently published version. Drafts and in-review revisions are invisible to agents, so an employee working on a revision never affects a colleague mid-task. If a skill is unpublished while someone is working, the next retrieval returns not found rather than stale content.

A skill grants nothing. Instructions that name a tool the employee cannot use still fail at the tool layer, with the same error a direct request would produce. If a skill consistently fails for one Group, the fix is in their Tool Pack or Connector access, not in the skill.

Retrieval is audited

Every retrieve_skill call writes a SKILL_RETRIEVED event to the Audit trail, attributed to the employee whose client made the call. Read next to Tool call logs, that gives you the sequence: which skill an agent loaded, and which calls it made afterward.

Each skill also carries a retrieval count in its detail drawer, which is the fastest way to see which of your procedures employees actually use and which ones nobody has ever loaded. It counts skill loads, not bundled-file fetches, so an agent reading three reference files is one retrieval.

Next

Go back to Skills for how the library fits together.