Skillgesture is a local MCP server for organizing and providing skills to AI agents. Skills are stored in a central repository, organized as group → skill → subskill, and loaded in full only when an agent requests them.
- central repository in ~/.skillgesture;
- skill content stored as Markdown;
- catalog, associations, and sessions persisted as JSON;
- global skills or skills associated with exact paths;
- simultaneous loading of multiple folders;
- lightweight index without Markdown content;
- on-demand reading;
- creation and modification of groups, skills, and subskills;
- enabling and disabling nodes;
- durable, independent sessions for multiple agents;
- atomic writes and a shared cross-process lock.
- Node.js 24 or later
- npm 12 or later
npm installTo make the skillgesture command globally available during development:
npm linknpm startThe server uses the MCP stdio transport. Diagnostic messages are written to stderr, while stdout is reserved for the MCP protocol.
Example MCP client configuration:
{
"mcpServers": {
"skillgesture": {
"command": "node",
"args": ["/absolute/path/to/skillgesture/src/index.js"]
}
}
}To use a different storage directory:
SKILLGESTURE_HOME=/alternative/path npm startManages sessions, the catalog, and associations. The available actions are:
- session.open
- session.configure
- session.list
- group.upsert
- skill.upsert
- subskill.upsert
- node.setEnabled
- association.set
Returns the lightweight tree of skills applicable to a session. It includes metadata and provenance, but not Markdown content.
Reads the Markdown of a single active skill or subskill on demand. If the skill contains imported supporting files, the first read also returns their resources index. Passing one of those paths as resourcePath reads only that resource without loading the entire bundle into the context.
Each agent creates a session once:
{
"action": "session.open",
"data": {
"label": "coding-agent",
"folders": [
"/Users/example/projects/api",
"/Users/example/projects/shared"
]
}
}The response contains a UUID:
{
"ok": true,
"session": {
"sessionId": "6de1fdba-aec8-4dc7-b03c-1e21e1ae58ac"
},
"resumed": false
}The agent must retain and reuse this sessionId.
After restarting the server:
{
"action": "session.open",
"data": {
"sessionId": "6de1fdba-aec8-4dc7-b03c-1e21e1ae58ac"
}
}An unknown ID does not implicitly create a new session.
{
"action": "session.configure",
"data": {
"sessionId": "6de1fdba-aec8-4dc7-b03c-1e21e1ae58ac",
"mode": "add",
"folders": ["/Users/example/projects/another-project"]
}
}mode can be replace, add, or remove.
{
"sessionId": "6de1fdba-aec8-4dc7-b03c-1e21e1ae58ac",
"includeDisabled": false
}{
"sessionId": "6de1fdba-aec8-4dc7-b03c-1e21e1ae58ac",
"groupId": "coding",
"skillId": "nodejs",
"subskillId": "testing"
}subskillId is optional.
To read a resource listed in the previous response:
{
"sessionId": "6de1fdba-aec8-4dc7-b03c-1e21e1ae58ac",
"groupId": "coding",
"skillId": "nodejs",
"resourcePath": "references/testing.md"
}Text resources are returned as UTF-8; binary resources are returned as Base64.
{
"action": "group.upsert",
"data": {
"id": "coding",
"name": "Coding",
"description": "Development skills"
}
}{
"action": "skill.upsert",
"data": {
"groupId": "coding",
"id": "git",
"name": "Git",
"description": "Version control management",
"global": true,
"markdown": "# Git\n\nSkill instructions."
}
}{
"action": "skill.upsert",
"data": {
"groupId": "coding",
"id": "nodejs",
"name": "Node.js",
"global": false,
"markdown": "# Node.js\n\nSkill instructions."
}
}{
"action": "subskill.upsert",
"data": {
"groupId": "coding",
"skillId": "nodejs",
"id": "testing",
"name": "Node testing",
"markdown": "# Node testing\n\nUse node:test."
}
}Subskills inherit the scope of their parent skill.
{
"action": "association.set",
"data": {
"folder": "/Users/example/projects/api",
"skills": [
{
"groupId": "coding",
"skillId": "nodejs"
}
]
}
}association.set replaces the folder's entire set of skills. An empty array removes the association.
Associations are based on the exact canonical path:
- an association with /projects/apidoes not automatically apply to/projects/api/packages/web;
- folders must exist when they are loaded or associated;
- a session can contain multiple folders and receives the deduplicated union of their skills.
{
"action": "node.setEnabled",
"data": {
"ref": {
"groupId": "coding",
"skillId": "nodejs"
},
"enabled": false
}
}Disabling a group disables all its descendant skills. Disabling a skill also makes its subskills unreadable. skill_tree can show disabled nodes when called with includeDisabled: true.
Multiple MCP processes can use the same repository. Sessions are stored separately, and mutations are serialized through a cross-process lock.
Update operations accept expectedVersion; association.set accepts expectedRevision. If another agent has already changed the data, Skillgesture returns VERSION_CONFLICT instead of silently overwriting the change.
~/.skillgesture/
├── catalog.json
├── associations.json
├── sessions/
│ └── <session-id>.json
└── skills/
└── <group-id>/
└── <skill-id>/
├── versions/
│ └── <version>/
│ ├── SKILL.md
│ └── resources/
└── subskills/
└── <subskill-id>/
└── versions/
└── <version>/
├── SKILL.md
└── resources/
Markdown versions are immutable. The catalog points to the active version, preventing reads from observing partially updated content.
npm testTests use temporary directories and do not modify ~/.skillgesture.
ISC