@olaservo/skill-jack-mcp 0.1.1 → 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 +12 -7
- package/dist/index.d.ts +3 -2
- package/dist/index.js +66 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,17 +35,22 @@ npm run build
|
|
|
35
35
|
|
|
36
36
|
## Usage
|
|
37
37
|
|
|
38
|
-
Configure
|
|
38
|
+
Configure one or more skills directories containing your Agent Skills:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
#
|
|
41
|
+
# Single directory
|
|
42
42
|
skill-jack-mcp /path/to/skills
|
|
43
43
|
|
|
44
|
-
#
|
|
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)
|
|
45
49
|
SKILLS_DIR=/path/to/skills skill-jack-mcp
|
|
50
|
+
SKILLS_DIR=/path/to/skills,/path/to/more/skills skill-jack-mcp
|
|
46
51
|
```
|
|
47
52
|
|
|
48
|
-
|
|
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.
|
|
49
54
|
|
|
50
55
|
**Windows note**: Use forward slashes in paths when using with MCP Inspector:
|
|
51
56
|
```bash
|
|
@@ -56,14 +61,14 @@ skill-jack-mcp "C:/Users/you/skills"
|
|
|
56
61
|
|
|
57
62
|
The server implements the [Agent Skills](https://agentskills.io) progressive disclosure pattern:
|
|
58
63
|
|
|
59
|
-
1. **At startup**: Discovers skills from configured
|
|
64
|
+
1. **At startup**: Discovers skills from configured directories
|
|
60
65
|
2. **On connection**: Server instructions (with skill metadata) are sent in the initialize response
|
|
61
66
|
3. **On tool call**: Agent calls `skill` tool to load full SKILL.md content
|
|
62
67
|
|
|
63
68
|
```
|
|
64
69
|
┌─────────────────────────────────────────────────────────┐
|
|
65
70
|
│ Server starts │
|
|
66
|
-
│ • Discovers skills from configured
|
|
71
|
+
│ • Discovers skills from configured directories │
|
|
67
72
|
│ • Generates instructions with skill metadata │
|
|
68
73
|
│ ↓ │
|
|
69
74
|
│ MCP Client connects │
|
|
@@ -203,7 +208,7 @@ These are loaded into the model's system prompt by [clients](https://modelcontex
|
|
|
203
208
|
|
|
204
209
|
## Skill Discovery
|
|
205
210
|
|
|
206
|
-
Skills are discovered at startup from the configured
|
|
211
|
+
Skills are discovered at startup from the configured directories. For each directory, the server checks:
|
|
207
212
|
- The directory itself for skill subdirectories
|
|
208
213
|
- `.claude/skills/` subdirectory
|
|
209
214
|
- `skills/` subdirectory
|
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)`);
|