@olaservo/skill-jack-mcp 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -12
- package/dist/index.d.ts +3 -2
- package/dist/index.js +66 -27
- package/dist/skill-tool.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Skill Jack MCP
|
|
2
2
|
|
|
3
|
-
An MCP server that jacks [Agent Skills](https://agentskills.
|
|
3
|
+
An MCP server that jacks [Agent Skills](https://agentskills.io) directly into your LLM's brain.
|
|
4
|
+
|
|
5
|
+
> **Recommended:** For best results, use an [MCP client](https://modelcontextprotocol.io/clients) that supports server instructions. This allows the LLM to see available skills in its system prompt, enabling automatic skill discovery and activation. Without this support, the model will still be able to call these tools, but you might need to provide more explicit instructions on what skills are available and the intended activation patterns.
|
|
4
6
|
|
|
5
7
|
## Features
|
|
6
8
|
|
|
@@ -33,17 +35,22 @@ npm run build
|
|
|
33
35
|
|
|
34
36
|
## Usage
|
|
35
37
|
|
|
36
|
-
Configure
|
|
38
|
+
Configure one or more skills directories containing your Agent Skills:
|
|
37
39
|
|
|
38
40
|
```bash
|
|
39
|
-
#
|
|
41
|
+
# Single directory
|
|
40
42
|
skill-jack-mcp /path/to/skills
|
|
41
43
|
|
|
42
|
-
#
|
|
44
|
+
# Multiple directories (separate args or comma-separated)
|
|
45
|
+
skill-jack-mcp /path/to/skills /path/to/more/skills
|
|
46
|
+
skill-jack-mcp /path/to/skills,/path/to/more/skills
|
|
47
|
+
|
|
48
|
+
# Using environment variable (comma-separated for multiple)
|
|
43
49
|
SKILLS_DIR=/path/to/skills skill-jack-mcp
|
|
50
|
+
SKILLS_DIR=/path/to/skills,/path/to/more/skills skill-jack-mcp
|
|
44
51
|
```
|
|
45
52
|
|
|
46
|
-
|
|
53
|
+
Each directory is scanned along with its `.claude/skills/` and `skills/` subdirectories for skills. Duplicate skill names are handled by keeping the first occurrence.
|
|
47
54
|
|
|
48
55
|
**Windows note**: Use forward slashes in paths when using with MCP Inspector:
|
|
49
56
|
```bash
|
|
@@ -52,16 +59,16 @@ skill-jack-mcp "C:/Users/you/skills"
|
|
|
52
59
|
|
|
53
60
|
## How It Works
|
|
54
61
|
|
|
55
|
-
The server implements the [Agent Skills](https://agentskills.
|
|
62
|
+
The server implements the [Agent Skills](https://agentskills.io) progressive disclosure pattern:
|
|
56
63
|
|
|
57
|
-
1. **At startup**: Discovers skills from configured
|
|
64
|
+
1. **At startup**: Discovers skills from configured directories
|
|
58
65
|
2. **On connection**: Server instructions (with skill metadata) are sent in the initialize response
|
|
59
66
|
3. **On tool call**: Agent calls `skill` tool to load full SKILL.md content
|
|
60
67
|
|
|
61
68
|
```
|
|
62
69
|
┌─────────────────────────────────────────────────────────┐
|
|
63
70
|
│ Server starts │
|
|
64
|
-
│ • Discovers skills from configured
|
|
71
|
+
│ • Discovers skills from configured directories │
|
|
65
72
|
│ • Generates instructions with skill metadata │
|
|
66
73
|
│ ↓ │
|
|
67
74
|
│ MCP Client connects │
|
|
@@ -96,7 +103,7 @@ Read files within a skill's directory (`scripts/`, `references/`, `assets/`, `sn
|
|
|
96
103
|
|
|
97
104
|
This follows the Agent Skills spec's progressive disclosure pattern - resources are loaded only when needed.
|
|
98
105
|
|
|
99
|
-
**
|
|
106
|
+
**Read a single file:**
|
|
100
107
|
```json
|
|
101
108
|
{
|
|
102
109
|
"skill": "mcp-server-ts",
|
|
@@ -104,7 +111,14 @@ This follows the Agent Skills spec's progressive disclosure pattern - resources
|
|
|
104
111
|
}
|
|
105
112
|
```
|
|
106
113
|
|
|
107
|
-
**
|
|
114
|
+
**Read all files in a directory:**
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"skill": "algorithmic-art",
|
|
118
|
+
"path": "templates"
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
Returns all files in the directory as multiple content items.
|
|
108
122
|
|
|
109
123
|
**List available files** (pass empty path):
|
|
110
124
|
```json
|
|
@@ -194,7 +208,7 @@ These are loaded into the model's system prompt by [clients](https://modelcontex
|
|
|
194
208
|
|
|
195
209
|
## Skill Discovery
|
|
196
210
|
|
|
197
|
-
Skills are discovered at startup from the configured
|
|
211
|
+
Skills are discovered at startup from the configured directories. For each directory, the server checks:
|
|
198
212
|
- The directory itself for skill subdirectories
|
|
199
213
|
- `.claude/skills/` subdirectory
|
|
200
214
|
- `skills/` subdirectory
|
|
@@ -213,6 +227,6 @@ npx @modelcontextprotocol/inspector@latest node dist/index.js /path/to/skills
|
|
|
213
227
|
|
|
214
228
|
## Related
|
|
215
229
|
|
|
216
|
-
- [Agent Skills Specification](https://agentskills.
|
|
230
|
+
- [Agent Skills Specification](https://agentskills.io)
|
|
217
231
|
- [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
|
|
218
232
|
- [Example MCP Clients](https://modelcontextprotocol.io/clients)
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* Provides global skills with tools for progressive disclosure.
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
|
-
* skill-jack-mcp /path/to/skills
|
|
10
|
-
* SKILLS_DIR=/path/to/skills skill-jack-mcp
|
|
9
|
+
* skill-jack-mcp /path/to/skills [/path2 ...] # One or more directories
|
|
10
|
+
* SKILLS_DIR=/path/to/skills skill-jack-mcp # Single directory via env
|
|
11
|
+
* SKILLS_DIR=/path1,/path2 skill-jack-mcp # Multiple (comma-separated)
|
|
11
12
|
*/
|
|
12
13
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* Provides global skills with tools for progressive disclosure.
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
|
-
* skill-jack-mcp /path/to/skills
|
|
10
|
-
* SKILLS_DIR=/path/to/skills skill-jack-mcp
|
|
9
|
+
* skill-jack-mcp /path/to/skills [/path2 ...] # One or more directories
|
|
10
|
+
* SKILLS_DIR=/path/to/skills skill-jack-mcp # Single directory via env
|
|
11
|
+
* SKILLS_DIR=/path1,/path2 skill-jack-mcp # Multiple (comma-separated)
|
|
11
12
|
*/
|
|
12
13
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
13
14
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -22,20 +23,40 @@ import { createSubscriptionManager, registerSubscriptionHandlers, } from "./subs
|
|
|
22
23
|
*/
|
|
23
24
|
const SKILL_SUBDIRS = [".claude/skills", "skills"];
|
|
24
25
|
/**
|
|
25
|
-
*
|
|
26
|
+
* Separator for multiple paths in SKILLS_DIR environment variable.
|
|
27
|
+
* Comma works cross-platform (not valid in file paths on any OS).
|
|
26
28
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
const PATH_LIST_SEPARATOR = ",";
|
|
30
|
+
/**
|
|
31
|
+
* Get the skills directories from command line args and/or environment.
|
|
32
|
+
* Returns deduplicated, resolved paths.
|
|
33
|
+
*/
|
|
34
|
+
function getSkillsDirs() {
|
|
35
|
+
const dirs = [];
|
|
36
|
+
// Collect all non-flag command-line arguments (comma-separated supported)
|
|
29
37
|
const args = process.argv.slice(2);
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
for (const arg of args) {
|
|
39
|
+
if (!arg.startsWith("-")) {
|
|
40
|
+
const paths = arg
|
|
41
|
+
.split(PATH_LIST_SEPARATOR)
|
|
42
|
+
.map((p) => p.trim())
|
|
43
|
+
.filter((p) => p.length > 0)
|
|
44
|
+
.map((p) => path.resolve(p));
|
|
45
|
+
dirs.push(...paths);
|
|
46
|
+
}
|
|
32
47
|
}
|
|
33
|
-
//
|
|
48
|
+
// Also check environment variable (comma-separated supported)
|
|
34
49
|
const envDir = process.env.SKILLS_DIR;
|
|
35
50
|
if (envDir) {
|
|
36
|
-
|
|
51
|
+
const envPaths = envDir
|
|
52
|
+
.split(PATH_LIST_SEPARATOR)
|
|
53
|
+
.map((p) => p.trim())
|
|
54
|
+
.filter((p) => p.length > 0)
|
|
55
|
+
.map((p) => path.resolve(p));
|
|
56
|
+
dirs.push(...envPaths);
|
|
37
57
|
}
|
|
38
|
-
|
|
58
|
+
// Deduplicate by resolved path
|
|
59
|
+
return [...new Set(dirs)];
|
|
39
60
|
}
|
|
40
61
|
/**
|
|
41
62
|
* Shared state for skill management.
|
|
@@ -46,20 +67,37 @@ const skillState = {
|
|
|
46
67
|
instructions: "",
|
|
47
68
|
};
|
|
48
69
|
/**
|
|
49
|
-
* Discover skills from configured
|
|
50
|
-
*
|
|
70
|
+
* Discover skills from multiple configured directories.
|
|
71
|
+
* Each directory is checked along with its standard subdirectories.
|
|
72
|
+
* Handles duplicate skill names by keeping first occurrence.
|
|
51
73
|
*/
|
|
52
|
-
function
|
|
74
|
+
function discoverSkillsFromDirs(skillsDirs) {
|
|
53
75
|
const allSkills = [];
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
76
|
+
const seenNames = new Map(); // name -> source directory
|
|
77
|
+
for (const skillsDir of skillsDirs) {
|
|
78
|
+
if (!fs.existsSync(skillsDir)) {
|
|
79
|
+
console.error(`Warning: Skills directory not found: ${skillsDir}`);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
console.error(`Scanning skills directory: ${skillsDir}`);
|
|
83
|
+
// Check if the directory itself contains skills
|
|
84
|
+
const dirSkills = discoverSkills(skillsDir);
|
|
85
|
+
// Also check standard subdirectories
|
|
86
|
+
for (const subdir of SKILL_SUBDIRS) {
|
|
87
|
+
const subPath = path.join(skillsDir, subdir);
|
|
88
|
+
if (fs.existsSync(subPath)) {
|
|
89
|
+
dirSkills.push(...discoverSkills(subPath));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Add skills, checking for duplicates
|
|
93
|
+
for (const skill of dirSkills) {
|
|
94
|
+
if (seenNames.has(skill.name)) {
|
|
95
|
+
console.error(`Warning: Duplicate skill "${skill.name}" found in ${path.dirname(skill.path)} ` +
|
|
96
|
+
`(already loaded from ${seenNames.get(skill.name)})`);
|
|
97
|
+
continue; // Skip duplicate
|
|
98
|
+
}
|
|
99
|
+
seenNames.set(skill.name, path.dirname(skill.path));
|
|
100
|
+
allSkills.push(skill);
|
|
63
101
|
}
|
|
64
102
|
}
|
|
65
103
|
return allSkills;
|
|
@@ -69,16 +107,17 @@ function discoverSkillsFromDir(skillsDir) {
|
|
|
69
107
|
*/
|
|
70
108
|
const subscriptionManager = createSubscriptionManager();
|
|
71
109
|
async function main() {
|
|
72
|
-
const
|
|
73
|
-
if (
|
|
110
|
+
const skillsDirs = getSkillsDirs();
|
|
111
|
+
if (skillsDirs.length === 0) {
|
|
74
112
|
console.error("No skills directory configured.");
|
|
75
|
-
console.error("Usage: skill-jack-mcp /path/to/skills");
|
|
113
|
+
console.error("Usage: skill-jack-mcp /path/to/skills [/path/to/more/skills ...]");
|
|
76
114
|
console.error(" or: SKILLS_DIR=/path/to/skills skill-jack-mcp");
|
|
115
|
+
console.error(" or: SKILLS_DIR=/path1,/path2 skill-jack-mcp");
|
|
77
116
|
process.exit(1);
|
|
78
117
|
}
|
|
79
|
-
console.error(`Skills
|
|
118
|
+
console.error(`Skills directories: ${skillsDirs.join(", ")}`);
|
|
80
119
|
// Discover skills at startup
|
|
81
|
-
const skills =
|
|
120
|
+
const skills = discoverSkillsFromDirs(skillsDirs);
|
|
82
121
|
skillState.skillMap = createSkillMap(skills);
|
|
83
122
|
skillState.instructions = generateInstructions(skills);
|
|
84
123
|
console.error(`Discovered ${skills.length} skill(s)`);
|
package/dist/skill-tool.js
CHANGED
|
@@ -87,7 +87,7 @@ const SkillResourceSchema = z.object({
|
|
|
87
87
|
skill: z.string().describe("Skill name"),
|
|
88
88
|
path: z
|
|
89
89
|
.string()
|
|
90
|
-
.describe("Relative path
|
|
90
|
+
.describe("Relative path to file or directory. Examples: 'snippets/tool.ts' (single file), 'templates' (all files in directory), '' (list available files)."),
|
|
91
91
|
});
|
|
92
92
|
// Security constants (exported for reuse in skill-resources.ts)
|
|
93
93
|
export const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB max file size
|