skill-library-mcp 1.3.5 → 2.0.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/.claude-plugin/hooks/hooks.json +16 -0
- package/.claude-plugin/hooks/run-hook.cmd +36 -0
- package/.claude-plugin/hooks/session-start +52 -0
- package/README.md +4 -4
- package/dist/index.js +19 -7
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
: << 'CMDBLOCK'
|
|
2
|
+
@echo off
|
|
3
|
+
REM Cross-platform polyglot wrapper for hook scripts.
|
|
4
|
+
REM On Windows: cmd.exe runs the batch portion, which finds and calls bash.
|
|
5
|
+
REM On Unix: the shell interprets this as a script (: is a no-op in bash).
|
|
6
|
+
|
|
7
|
+
if "%~1"=="" (
|
|
8
|
+
echo run-hook.cmd: missing script name >&2
|
|
9
|
+
exit /b 1
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
set "HOOK_DIR=%~dp0"
|
|
13
|
+
|
|
14
|
+
if exist "C:\Program Files\Git\bin\bash.exe" (
|
|
15
|
+
"C:\Program Files\Git\bin\bash.exe" "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
|
|
16
|
+
exit /b %ERRORLEVEL%
|
|
17
|
+
)
|
|
18
|
+
if exist "C:\Program Files (x86)\Git\bin\bash.exe" (
|
|
19
|
+
"C:\Program Files (x86)\Git\bin\bash.exe" "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
|
|
20
|
+
exit /b %ERRORLEVEL%
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
where bash >nul 2>nul
|
|
24
|
+
if %ERRORLEVEL% equ 0 (
|
|
25
|
+
bash "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
|
|
26
|
+
exit /b %ERRORLEVEL%
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
exit /b 0
|
|
30
|
+
CMDBLOCK
|
|
31
|
+
|
|
32
|
+
# Unix: run the named script directly
|
|
33
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
34
|
+
SCRIPT_NAME="$1"
|
|
35
|
+
shift
|
|
36
|
+
exec bash "${SCRIPT_DIR}/${SCRIPT_NAME}" "$@"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# SessionStart hook for skill-library plugin
|
|
3
|
+
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
escape_for_json() {
|
|
7
|
+
local s="$1"
|
|
8
|
+
s="${s//\\/\\\\}"
|
|
9
|
+
s="${s//\"/\\\"}"
|
|
10
|
+
s="${s//$'\n'/\\n}"
|
|
11
|
+
s="${s//$'\r'/\\r}"
|
|
12
|
+
s="${s//$'\t'/\\t}"
|
|
13
|
+
printf '%s' "$s"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
read -r -d '' CONTEXT << 'SKILLEOF' || true
|
|
17
|
+
You have access to a skill library with 15,000+ skills via MCP tools.
|
|
18
|
+
|
|
19
|
+
**IMPORTANT: Before responding to any task, check if a relevant skill exists.**
|
|
20
|
+
|
|
21
|
+
Use these MCP tools from the skill-library server:
|
|
22
|
+
- `search_skill({ query: "..." })` — Search for skills by keyword. Use natural language.
|
|
23
|
+
- `load_skill({ name: "...", include_resources: true })` — Load the full skill content.
|
|
24
|
+
- `list_categories()` — Browse all 13 skill categories.
|
|
25
|
+
|
|
26
|
+
**When to search:**
|
|
27
|
+
- Starting any new task (even simple ones — a skill may have best practices)
|
|
28
|
+
- Working with a specific framework, library, or tool
|
|
29
|
+
- Debugging, testing, deploying, or architecting
|
|
30
|
+
- Any domain you're not 100% certain about
|
|
31
|
+
|
|
32
|
+
**How to use:**
|
|
33
|
+
1. Search with a short query related to your task
|
|
34
|
+
2. If results look relevant, load the top skill
|
|
35
|
+
3. Follow the skill's guidance in your response
|
|
36
|
+
|
|
37
|
+
Don't skip this step. A 2-second search can prevent minutes of suboptimal work.
|
|
38
|
+
SKILLEOF
|
|
39
|
+
|
|
40
|
+
session_context="<IMPORTANT>\nYou have a skill library.\n\n$(escape_for_json "$CONTEXT")\n</IMPORTANT>"
|
|
41
|
+
|
|
42
|
+
cat <<EOF
|
|
43
|
+
{
|
|
44
|
+
"additional_context": "${session_context}",
|
|
45
|
+
"hookSpecificOutput": {
|
|
46
|
+
"hookEventName": "SessionStart",
|
|
47
|
+
"additionalContext": "${session_context}"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
EOF
|
|
51
|
+
|
|
52
|
+
exit 0
|
package/README.md
CHANGED
|
@@ -25,16 +25,16 @@ An MCP server that provides on-demand skill loading for AI coding assistants. In
|
|
|
25
25
|
Add the marketplace source, then install the plugin:
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
claude plugin marketplace add https://github.com/modbender/skill-library-mcp.git
|
|
29
|
-
claude plugin install skill-library
|
|
28
|
+
claude plugin marketplace add https://github.com/modbender/skill-library-mcp.git --scope user
|
|
29
|
+
claude plugin install skill-library --scope user
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
The MCP server starts automatically when Claude Code launches. No manual configuration needed.
|
|
33
33
|
|
|
34
|
-
### Claude Code (
|
|
34
|
+
### Claude Code (MCP Server)
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
claude mcp add skill-library -- npx -y skill-library-mcp
|
|
37
|
+
claude mcp add skill-library --scope user -- npx -y skill-library-mcp
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
### MCP Server (Other Tools)
|
package/dist/index.js
CHANGED
|
@@ -201,26 +201,38 @@ function searchSkills(index, query, limit = 20) {
|
|
|
201
201
|
for (const entry of index.entries) {
|
|
202
202
|
let score = 0;
|
|
203
203
|
let matchedTokens = 0;
|
|
204
|
+
const nameLower = entry.frontmatter.name.toLowerCase();
|
|
205
|
+
const descLower = entry.frontmatter.description.toLowerCase();
|
|
204
206
|
for (const qt of queryTokens) {
|
|
205
207
|
const idfWeight = index.idfScores.get(qt) ?? defaultIdf;
|
|
206
208
|
let bestTokenScore = 0;
|
|
207
209
|
for (const st of entry.searchTokens) {
|
|
208
210
|
if (st === qt) {
|
|
209
211
|
bestTokenScore = Math.max(bestTokenScore, idfWeight);
|
|
210
|
-
} else if (qt.length >=
|
|
211
|
-
|
|
212
|
+
} else if (qt.length >= 3 && st.length >= 3) {
|
|
213
|
+
if (st.includes(qt)) {
|
|
214
|
+
const overlap = qt.length / st.length;
|
|
215
|
+
bestTokenScore = Math.max(bestTokenScore, idfWeight * overlap * 0.5);
|
|
216
|
+
} else if (qt.includes(st)) {
|
|
217
|
+
const overlap = st.length / qt.length;
|
|
218
|
+
bestTokenScore = Math.max(bestTokenScore, idfWeight * overlap * 0.5);
|
|
219
|
+
}
|
|
212
220
|
}
|
|
213
221
|
}
|
|
214
222
|
if (bestTokenScore > 0) matchedTokens++;
|
|
215
223
|
score += bestTokenScore;
|
|
216
224
|
}
|
|
217
|
-
if (
|
|
218
|
-
score +=
|
|
225
|
+
if (nameLower.includes(queryLower)) {
|
|
226
|
+
score += 3;
|
|
219
227
|
}
|
|
220
|
-
|
|
221
|
-
score += 1;
|
|
228
|
+
for (const qt of queryTokens) {
|
|
229
|
+
if (nameLower.includes(qt)) score += 1;
|
|
230
|
+
}
|
|
231
|
+
if (descLower.includes(queryLower)) {
|
|
232
|
+
score += 1.5;
|
|
222
233
|
}
|
|
223
|
-
|
|
234
|
+
const coverage = matchedTokens / queryTokens.length;
|
|
235
|
+
score *= 1 + coverage;
|
|
224
236
|
if (score >= 0.5) {
|
|
225
237
|
results.push({
|
|
226
238
|
name: entry.frontmatter.name,
|