Skip to main content

Agents and skills

Internal developers only

The Capture MCP SDK is currently only available to Capture's internal developers. We are working hard on the cybersecurity part, so that we can also offer it to everyone who builds on top of Capture.

Your app can tell Captain how to use its tools, not only what they are. You do this by shipping two folders next to your code:

  • Agents: *.agent.md files, each one a persona with a system prompt. Captain builds one specialist per agent.
  • Skills: <name>/SKILL.md folders, written in the open Agent Skills format, that an agent can load when it needs them.

They travel with your tools in the registration heartbeat. This is also what makes the difference between Captain and a general AI tool that only sees a list of tools: Captain has the guidance.

If your app registers no agents, Captain serves it one default agent over all its tools. Any app that may register tools may also register agents and skills, on the same heartbeat and with the same machine client.

Point the SDK at your folders​

settings = CaptureMcpSettings(
...,
agents_dir="my_app:agents", # or "my_app.agents", or a plain directory
skills_dir="my_app:skills",
)

Both settings are resolved through importlib.resources. The value names package data, not a path on your build machine. A wheel that is installed finds its prompts without a checkout, and a file that exists in development but is missing from the image fails loudly instead of quietly.

A definition that the SDK refuses is left out and logged once. The MCP server checks again and returns what it refused, which the SDK also logs once. A mistake in an agent or a skill never takes your tools offline.


An agent​

An *.agent.md file is frontmatter plus a body. The body becomes the system prompt.

---
name: uns-explorer # must match the file name, Agent Skills naming rules
description: Browses and reads the Unified Namespace of a site.
tools: uns_browse uns_read # registered names, a subset of your tools; omit the key to bind them all
skills: uns-authoring # skills of this app the agent may load
model: captain-medium # one of Captain's seven tiers; never a raw model id
permissions: app-901:uns:view # optional; the agent is hidden from users who lack them
---

You are the UNS explorer for this site. …
KeyWhat it does
nameThe name of the agent. Lowercase letters and digits in hyphen-separated segments, at most 64 characters. It must match the file name: greeter.agent.md holds the agent greeter.
descriptionWhat the agent is for, at most 1024 characters. It is what the router uses to decide when to hand a question to this agent, so it is part of the review of your app.
toolsThe tools the agent can use, by the name they are registered under, separated by spaces or commas. Bind a subset for least privilege. Leave the key out to bind every tool of your app. A tool you do not register is an error.
skillsThe skills of your app that the agent advertises in its prompt.
modelOptional. One of the tiers of Captain: captain-small, captain-medium, captain-rag-expert, captain-data-expert, captain-tool-expert, captain-reasoning-expert or captain-vision. Never a raw model id. Leave it out and the agent runs on captain-tool-expert. An operator can still move a tier, so treat it as the default of your agent.
permissionsOptional. The permissions a user needs to be offered the agent. See below.
  • The body is the system prompt, at most 64 KiB. Captain adds its own answer style, scope and visualization guidance after it. You cannot supply or remove those.
  • Frontmatter values are one line. A block value such as description: > or a list spread over several lines is refused, instead of guessed at: a guess would become a system prompt. Keys that this version does not know are ignored, so a file written for a newer SDK still builds.
Use the registered tool name

An agent binds a tool by the name it is registered under, {prefix}_{tool}. The prefix is platform_app_name (PlatformAppName in .NET) when you set it and the service name otherwise. With the prefix uns, a tool browse is uns_browse. A bare name is an error: the MCP server compares an agent with the registered names on the same heartbeat, and refuses an agent that binds one.

Permissions here include the app key

Unlike the permission on a tool, the permissions of an agent or a skill are written fully qualified, as {app}:{resource}:{action}, for example app-901:uns:view. An agent may legitimately require the permission of another app, so there is no app part to fill in for you. For your own app, the first part is the app key that Capture assigned to it (see GET /api/apps/me). An entry whose first part is not your app key is treated as the permission of another app: the SDK does not declare it, and it hides the agent from every user until that app declares it. A malformed entry is an error.

An agent with permissions is only offered to a user who holds all of them in the company the question is asked in, and who may use at least one of the tools of the agent. The SDK declares the entries that belong to your app on the permission manifest of your app, as it does for the permission on a tool, so an administrator has something to put in a role. This is not a security boundary. The MCP server checks every tool call again with the token of the caller. The permissions keep an agent out of the way of a user who cannot use it.


A skill​

A skill is a folder skills/<name>/SKILL.md, with an optional references/ folder one level deep.

---
name: uns-authoring
description: How to lay out a Unified Namespace for a site: the naming conventions and the level at which a tag belongs.
allowed-tools: uns_write
permissions: app-901:uns:manage
---

# Authoring a Unified Namespace

1. Model the physical plant first: enterprise, site, area, line, cell.
2. Name every level in `lower-kebab-case`.
3. Read `references/naming.md` before you propose a rename.
4. Only once the layout is agreed, write with `uns_write`, one node at a time.
skills/uns-authoring/SKILL.md
skills/uns-authoring/references/naming.md
  • description is all an agent sees of the skill until it loads it, at most 1024 characters. The body is the procedure, at most 64 KiB, delivered only when the skill is loaded.
  • allowed-tools lists your registered tools. They become available to an agent only once the skill is loaded, and only for that turn. So a capability that an agent should not carry into every conversation arrives with the procedure that explains it. A tool named here does not need to be bound by any agent. Leave the key out and the skill unlocks nothing, the opposite of the tools of an agent.
  • Loading never reveals a tool the caller does not hold. The permissions of the caller are applied first, and a skill can only stop withholding what was already allowed.
  • permissions works as it does on an agent: all of them, fully qualified, judged in the company the question is asked in.
  • references/ holds plain text files one level deep, each at most 64 KiB, that the agent reads on demand. Long material belongs there instead of in the body. A skill has at most 16 references, and its body and references together are at most 512 KiB.
  • scripts/ and assets/ are an error. Executable behaviour on this platform is a tool of your app, which is permission-checked and observable. It is not a file in a skill.
  • Any agent of your app can load any skill of your app. The skills key of an agent only names the ones its prompt advertises. A skill can only name your own tools and skills.

Check them​

capture-mcp validate runs the same rules the MCP server applies when you register. It exits with a non-zero code on an error and with zero when it only found warnings, so it drops straight into a CI step:

capture-mcp validate --app my_app.main:app # settings and tool names come from the app
capture-mcp validate --agents-dir ./agents --tool uns_browse --tool uns_read # registered names

--app imports the module from the working directory, so run it from the root of your project.

app.start() runs the same check before it connects to anything. It raises capture_mcp_sdk.definitions.DefinitionValidationError on an error, so a typo in a prompt cannot reach a running system. Warnings, for example a tool that no agent binds and no skill unlocks, are logged and do not stop the start.

A tool that no agent binds and no skill unlocks is a warning in both languages: Captain can never call it through an agent.


An example to start from​

Both SDKs come with a working example: examples/uns_sample_app/ in Python, with one agent, one skill and a reference file, and McpSdkSample in .NET, with end-to-end tests of the registration loop.