skillmds 1.1.1 → 1.1.2
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/CHANGELOG.md +6 -0
- package/README.md +1 -1
- package/assets/skillmd-banner.jpg +0 -0
- package/bin/skillmd-mcp.mjs +771 -59
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `skillmds` are documented here. Versions follow [semver](https://semver.org).
|
|
4
4
|
|
|
5
|
+
## 1.1.2
|
|
6
|
+
|
|
7
|
+
- **MCP tool metadata.** Every tool now declares a `title`, `annotations` (all read-only except `skillmd_install`, none destructive), an `outputSchema`, and a description on every parameter; list-returning tools respond with `structuredContent: { items }`, `skillmd_lint` and `skillmd_install` return structured results, and refusals are flagged `isError`.
|
|
8
|
+
- **Server metadata.** `initialize` reports a title, description, website URL, icons and usage instructions.
|
|
9
|
+
- No behavior changes to what the tools do.
|
|
10
|
+
|
|
5
11
|
## 1.1.1
|
|
6
12
|
|
|
7
13
|
- Releases are now published through npm Trusted Publishing (OIDC from GitHub Actions) with provenance; no long-lived npm tokens exist for this package.
|
package/README.md
CHANGED
|
Binary file
|
package/bin/skillmd-mcp.mjs
CHANGED
|
@@ -46,7 +46,17 @@ async function api(path, init = {}) {
|
|
|
46
46
|
if (!res.ok) throw new Error(`SkillMD API ${res.status} on ${path}: ${await res.text().catch(() => "")}`);
|
|
47
47
|
return res.json();
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
// Tool results carry both a text rendering and structuredContent matching the
|
|
50
|
+
// tool's outputSchema. Arrays are wrapped as { items } so the structured payload
|
|
51
|
+
// is always an object, as the spec requires. Plain strings are messages only.
|
|
52
|
+
const text = (obj) => {
|
|
53
|
+
if (typeof obj === "string") return { content: [{ type: "text", text: obj }] };
|
|
54
|
+
const structured = Array.isArray(obj) ? { items: obj } : obj;
|
|
55
|
+
return { content: [{ type: "text", text: JSON.stringify(structured, null, 2) }], structuredContent: structured };
|
|
56
|
+
};
|
|
57
|
+
// A human-readable refusal/notice: text only, flagged as an error so clients do
|
|
58
|
+
// not expect structuredContent for it.
|
|
59
|
+
const notice = (msg) => ({ isError: true, content: [{ type: "text", text: msg }] });
|
|
50
60
|
|
|
51
61
|
// The public API returns site-oriented fields (ratings, counters, avatars,
|
|
52
62
|
// ranker internals) that are noise for an agent picking a skill. Strip them
|
|
@@ -67,76 +77,756 @@ const trimItems = (items) => (items ?? []).map((s) => Object.fromEntries(Object.
|
|
|
67
77
|
|
|
68
78
|
const TOOLS = [
|
|
69
79
|
{
|
|
70
|
-
name: "skillmd_search",
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
"name": "skillmd_search",
|
|
81
|
+
"title": "Search skills",
|
|
82
|
+
"description": "Search the SkillMD registry of Agent Skills (SKILL.md files) by task, name or keywords. Returns matching skills with their owner/name slug, description, category, safety verdict and install snippet, best match first.",
|
|
83
|
+
"inputSchema": {
|
|
84
|
+
"type": "object",
|
|
85
|
+
"properties": {
|
|
86
|
+
"query": {
|
|
87
|
+
"type": "string",
|
|
88
|
+
"description": "Natural-language query or keywords describing the task or skill"
|
|
89
|
+
},
|
|
90
|
+
"category": {
|
|
91
|
+
"type": "string",
|
|
92
|
+
"description": "Restrict to one category slug, e.g. coding, devops, data, security"
|
|
93
|
+
},
|
|
94
|
+
"verified_only": {
|
|
95
|
+
"type": "boolean",
|
|
96
|
+
"description": "Return only skills from verified publishers (default false)"
|
|
97
|
+
},
|
|
98
|
+
"type": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"enum": [
|
|
101
|
+
"single",
|
|
102
|
+
"pack"
|
|
103
|
+
],
|
|
104
|
+
"description": "Restrict to single-file skills or multi-file packs"
|
|
105
|
+
},
|
|
106
|
+
"min_rating": {
|
|
107
|
+
"type": "number",
|
|
108
|
+
"minimum": 0,
|
|
109
|
+
"maximum": 5,
|
|
110
|
+
"description": "Minimum average rating, 0 to 5"
|
|
111
|
+
},
|
|
112
|
+
"limit": {
|
|
113
|
+
"type": "integer",
|
|
114
|
+
"minimum": 1,
|
|
115
|
+
"maximum": 100,
|
|
116
|
+
"description": "Maximum number of results (default 20)"
|
|
117
|
+
}
|
|
81
118
|
},
|
|
82
|
-
required: [
|
|
119
|
+
"required": [
|
|
120
|
+
"query"
|
|
121
|
+
],
|
|
122
|
+
"additionalProperties": false
|
|
83
123
|
},
|
|
124
|
+
"outputSchema": {
|
|
125
|
+
"type": "object",
|
|
126
|
+
"properties": {
|
|
127
|
+
"items": {
|
|
128
|
+
"type": "array",
|
|
129
|
+
"items": {
|
|
130
|
+
"type": "object",
|
|
131
|
+
"description": "A skill as listed in search and leaderboard results.",
|
|
132
|
+
"properties": {
|
|
133
|
+
"slug": {
|
|
134
|
+
"type": "string",
|
|
135
|
+
"description": "owner/name identifier, e.g. anthropic/pdf"
|
|
136
|
+
},
|
|
137
|
+
"title": {
|
|
138
|
+
"type": "string",
|
|
139
|
+
"description": "Human-readable skill title"
|
|
140
|
+
},
|
|
141
|
+
"description": {
|
|
142
|
+
"type": "string",
|
|
143
|
+
"description": "What the skill does and when an agent should use it"
|
|
144
|
+
},
|
|
145
|
+
"category": {
|
|
146
|
+
"type": "string",
|
|
147
|
+
"description": "Category name"
|
|
148
|
+
},
|
|
149
|
+
"owner_handle": {
|
|
150
|
+
"type": "string",
|
|
151
|
+
"description": "Publisher handle"
|
|
152
|
+
},
|
|
153
|
+
"owner_name": {
|
|
154
|
+
"type": "string",
|
|
155
|
+
"description": "Publisher display name"
|
|
156
|
+
},
|
|
157
|
+
"license": {
|
|
158
|
+
"type": [
|
|
159
|
+
"string",
|
|
160
|
+
"null"
|
|
161
|
+
],
|
|
162
|
+
"description": "SPDX license id when declared"
|
|
163
|
+
},
|
|
164
|
+
"security_flags": {
|
|
165
|
+
"type": "array",
|
|
166
|
+
"items": {
|
|
167
|
+
"type": "string"
|
|
168
|
+
},
|
|
169
|
+
"description": "Capability flags: docs_only, network_calls, executes_scripts, reads_secrets, untrusted_install"
|
|
170
|
+
},
|
|
171
|
+
"ai_audit_verdict": {
|
|
172
|
+
"type": [
|
|
173
|
+
"string",
|
|
174
|
+
"null"
|
|
175
|
+
],
|
|
176
|
+
"description": "Safety review verdict: pass, caution, warning, fail or inconclusive"
|
|
177
|
+
},
|
|
178
|
+
"repo_stars": {
|
|
179
|
+
"type": [
|
|
180
|
+
"number",
|
|
181
|
+
"null"
|
|
182
|
+
],
|
|
183
|
+
"description": "GitHub stars of the source repository"
|
|
184
|
+
},
|
|
185
|
+
"install_snippet": {
|
|
186
|
+
"type": "string",
|
|
187
|
+
"description": "One-line install command"
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
"required": [
|
|
191
|
+
"slug"
|
|
192
|
+
],
|
|
193
|
+
"additionalProperties": true
|
|
194
|
+
},
|
|
195
|
+
"description": "Matching skills, best first"
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
"required": [
|
|
199
|
+
"items"
|
|
200
|
+
]
|
|
201
|
+
},
|
|
202
|
+
"annotations": {
|
|
203
|
+
"title": "Search skills",
|
|
204
|
+
"readOnlyHint": true,
|
|
205
|
+
"destructiveHint": false,
|
|
206
|
+
"idempotentHint": true,
|
|
207
|
+
"openWorldHint": false
|
|
208
|
+
}
|
|
84
209
|
},
|
|
85
210
|
{
|
|
86
|
-
name: "skillmd_get",
|
|
87
|
-
|
|
88
|
-
|
|
211
|
+
"name": "skillmd_get",
|
|
212
|
+
"title": "Get skill details",
|
|
213
|
+
"description": "Fetch one skill by owner/name slug, including its SKILL.md body, provenance (source repo and pinned commit), license, safety verdict and capability flags.",
|
|
214
|
+
"inputSchema": {
|
|
215
|
+
"type": "object",
|
|
216
|
+
"properties": {
|
|
217
|
+
"slug": {
|
|
218
|
+
"type": "string",
|
|
219
|
+
"pattern": "^[^/]+/[^/]+$",
|
|
220
|
+
"description": "Skill identifier as owner/name, e.g. anthropic/pdf"
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
"required": [
|
|
224
|
+
"slug"
|
|
225
|
+
],
|
|
226
|
+
"additionalProperties": false
|
|
227
|
+
},
|
|
228
|
+
"outputSchema": {
|
|
229
|
+
"type": "object",
|
|
230
|
+
"description": "Full skill record.",
|
|
231
|
+
"properties": {
|
|
232
|
+
"slug": {
|
|
233
|
+
"type": "string",
|
|
234
|
+
"description": "owner/name identifier, e.g. anthropic/pdf"
|
|
235
|
+
},
|
|
236
|
+
"title": {
|
|
237
|
+
"type": "string",
|
|
238
|
+
"description": "Human-readable skill title"
|
|
239
|
+
},
|
|
240
|
+
"description": {
|
|
241
|
+
"type": "string",
|
|
242
|
+
"description": "What the skill does and when an agent should use it"
|
|
243
|
+
},
|
|
244
|
+
"category": {
|
|
245
|
+
"type": "string",
|
|
246
|
+
"description": "Category name"
|
|
247
|
+
},
|
|
248
|
+
"owner_handle": {
|
|
249
|
+
"type": "string",
|
|
250
|
+
"description": "Publisher handle"
|
|
251
|
+
},
|
|
252
|
+
"owner_name": {
|
|
253
|
+
"type": "string",
|
|
254
|
+
"description": "Publisher display name"
|
|
255
|
+
},
|
|
256
|
+
"license": {
|
|
257
|
+
"type": [
|
|
258
|
+
"string",
|
|
259
|
+
"null"
|
|
260
|
+
],
|
|
261
|
+
"description": "SPDX license id when declared"
|
|
262
|
+
},
|
|
263
|
+
"security_flags": {
|
|
264
|
+
"type": "array",
|
|
265
|
+
"items": {
|
|
266
|
+
"type": "string"
|
|
267
|
+
},
|
|
268
|
+
"description": "Capability flags: docs_only, network_calls, executes_scripts, reads_secrets, untrusted_install"
|
|
269
|
+
},
|
|
270
|
+
"ai_audit_verdict": {
|
|
271
|
+
"type": [
|
|
272
|
+
"string",
|
|
273
|
+
"null"
|
|
274
|
+
],
|
|
275
|
+
"description": "Safety review verdict: pass, caution, warning, fail or inconclusive"
|
|
276
|
+
},
|
|
277
|
+
"repo_stars": {
|
|
278
|
+
"type": [
|
|
279
|
+
"number",
|
|
280
|
+
"null"
|
|
281
|
+
],
|
|
282
|
+
"description": "GitHub stars of the source repository"
|
|
283
|
+
},
|
|
284
|
+
"install_snippet": {
|
|
285
|
+
"type": "string",
|
|
286
|
+
"description": "One-line install command"
|
|
287
|
+
},
|
|
288
|
+
"type": {
|
|
289
|
+
"type": "string",
|
|
290
|
+
"enum": [
|
|
291
|
+
"single",
|
|
292
|
+
"pack"
|
|
293
|
+
],
|
|
294
|
+
"description": "single SKILL.md or a multi-file pack"
|
|
295
|
+
},
|
|
296
|
+
"body_md": {
|
|
297
|
+
"type": "string",
|
|
298
|
+
"description": "Markdown body of SKILL.md"
|
|
299
|
+
},
|
|
300
|
+
"raw_md": {
|
|
301
|
+
"type": [
|
|
302
|
+
"string",
|
|
303
|
+
"null"
|
|
304
|
+
],
|
|
305
|
+
"description": "Verbatim SKILL.md including frontmatter when stored"
|
|
306
|
+
},
|
|
307
|
+
"verified": {
|
|
308
|
+
"type": "boolean",
|
|
309
|
+
"description": "Published by a verified publisher"
|
|
310
|
+
},
|
|
311
|
+
"source_repo": {
|
|
312
|
+
"type": [
|
|
313
|
+
"string",
|
|
314
|
+
"null"
|
|
315
|
+
],
|
|
316
|
+
"description": "Upstream repository"
|
|
317
|
+
},
|
|
318
|
+
"commit_sha": {
|
|
319
|
+
"type": [
|
|
320
|
+
"string",
|
|
321
|
+
"null"
|
|
322
|
+
],
|
|
323
|
+
"description": "Pinned upstream commit"
|
|
324
|
+
},
|
|
325
|
+
"files": {
|
|
326
|
+
"type": "array",
|
|
327
|
+
"description": "Companion files for packs",
|
|
328
|
+
"items": {
|
|
329
|
+
"type": "object",
|
|
330
|
+
"additionalProperties": true
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
"tags": {
|
|
334
|
+
"type": "array",
|
|
335
|
+
"items": {
|
|
336
|
+
"type": "object",
|
|
337
|
+
"additionalProperties": true
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
"categories": {
|
|
341
|
+
"type": "array",
|
|
342
|
+
"items": {
|
|
343
|
+
"type": "object",
|
|
344
|
+
"additionalProperties": true
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
"required": [
|
|
349
|
+
"slug",
|
|
350
|
+
"title",
|
|
351
|
+
"description"
|
|
352
|
+
],
|
|
353
|
+
"additionalProperties": true
|
|
354
|
+
},
|
|
355
|
+
"annotations": {
|
|
356
|
+
"title": "Get skill details",
|
|
357
|
+
"readOnlyHint": true,
|
|
358
|
+
"destructiveHint": false,
|
|
359
|
+
"idempotentHint": true,
|
|
360
|
+
"openWorldHint": false
|
|
361
|
+
}
|
|
89
362
|
},
|
|
90
363
|
{
|
|
91
|
-
name: "skillmd_install",
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
inputSchema: {
|
|
95
|
-
type: "object",
|
|
96
|
-
properties: {
|
|
97
|
-
slug: {
|
|
98
|
-
|
|
364
|
+
"name": "skillmd_install",
|
|
365
|
+
"title": "Install skill",
|
|
366
|
+
"description": "Install a skill by owner/name slug: validates it, then writes SKILL.md (and companion files for packs, integrity-checked) into the agent's skills directory. Never executes scripts. The response reports the skill's capability flags (docs_only, network_calls, executes_scripts, reads_secrets) as information.",
|
|
367
|
+
"inputSchema": {
|
|
368
|
+
"type": "object",
|
|
369
|
+
"properties": {
|
|
370
|
+
"slug": {
|
|
371
|
+
"type": "string",
|
|
372
|
+
"pattern": "^[^/]+/[^/]+$",
|
|
373
|
+
"description": "Skill identifier as owner/name, e.g. anthropic/pdf"
|
|
374
|
+
},
|
|
375
|
+
"dest": {
|
|
376
|
+
"type": "string",
|
|
377
|
+
"description": "Skills directory to write into (default ~/.claude/skills)"
|
|
378
|
+
}
|
|
379
|
+
},
|
|
380
|
+
"required": [
|
|
381
|
+
"slug"
|
|
382
|
+
],
|
|
383
|
+
"additionalProperties": false
|
|
384
|
+
},
|
|
385
|
+
"outputSchema": {
|
|
386
|
+
"type": "object",
|
|
387
|
+
"properties": {
|
|
388
|
+
"installed": {
|
|
389
|
+
"type": "boolean",
|
|
390
|
+
"description": "Whether files were written"
|
|
391
|
+
},
|
|
392
|
+
"slug": {
|
|
393
|
+
"type": "string",
|
|
394
|
+
"description": "owner/name of the skill"
|
|
395
|
+
},
|
|
396
|
+
"dir": {
|
|
397
|
+
"type": "string",
|
|
398
|
+
"description": "Absolute directory the skill was written to"
|
|
399
|
+
},
|
|
400
|
+
"files_written": {
|
|
401
|
+
"type": "integer",
|
|
402
|
+
"description": "Number of files written"
|
|
403
|
+
},
|
|
404
|
+
"security_flags": {
|
|
405
|
+
"type": "array",
|
|
406
|
+
"items": {
|
|
407
|
+
"type": "string"
|
|
408
|
+
},
|
|
409
|
+
"description": "Capability flags reported for the skill"
|
|
410
|
+
},
|
|
411
|
+
"note": {
|
|
412
|
+
"type": "string",
|
|
413
|
+
"description": "Caveats, e.g. when only SKILL.md could be written"
|
|
414
|
+
}
|
|
99
415
|
},
|
|
100
|
-
required: [
|
|
416
|
+
"required": [
|
|
417
|
+
"installed",
|
|
418
|
+
"slug"
|
|
419
|
+
]
|
|
101
420
|
},
|
|
421
|
+
"annotations": {
|
|
422
|
+
"title": "Install skill",
|
|
423
|
+
"readOnlyHint": false,
|
|
424
|
+
"destructiveHint": false,
|
|
425
|
+
"idempotentHint": true,
|
|
426
|
+
"openWorldHint": false
|
|
427
|
+
}
|
|
102
428
|
},
|
|
103
429
|
{
|
|
104
|
-
name: "skillmd_trending",
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
430
|
+
"name": "skillmd_trending",
|
|
431
|
+
"title": "Trending skills",
|
|
432
|
+
"description": "Top skills on the SkillMD leaderboard, ranked by installs, saves and ratings, optionally within one category and time window.",
|
|
433
|
+
"inputSchema": {
|
|
434
|
+
"type": "object",
|
|
435
|
+
"properties": {
|
|
436
|
+
"range": {
|
|
437
|
+
"type": "string",
|
|
438
|
+
"enum": [
|
|
439
|
+
"30d",
|
|
440
|
+
"all"
|
|
441
|
+
],
|
|
442
|
+
"description": "Ranking window: last 30 days or all time (default all)"
|
|
443
|
+
},
|
|
444
|
+
"category": {
|
|
445
|
+
"type": "string",
|
|
446
|
+
"description": "Restrict to one category slug, e.g. coding, devops, data, security"
|
|
447
|
+
},
|
|
448
|
+
"limit": {
|
|
449
|
+
"type": "integer",
|
|
450
|
+
"minimum": 1,
|
|
451
|
+
"maximum": 100,
|
|
452
|
+
"description": "Maximum number of results (default 20)"
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
"additionalProperties": false
|
|
456
|
+
},
|
|
457
|
+
"outputSchema": {
|
|
458
|
+
"type": "object",
|
|
459
|
+
"properties": {
|
|
460
|
+
"items": {
|
|
461
|
+
"type": "array",
|
|
462
|
+
"items": {
|
|
463
|
+
"type": "object",
|
|
464
|
+
"description": "A skill as listed in search and leaderboard results.",
|
|
465
|
+
"properties": {
|
|
466
|
+
"slug": {
|
|
467
|
+
"type": "string",
|
|
468
|
+
"description": "owner/name identifier, e.g. anthropic/pdf"
|
|
469
|
+
},
|
|
470
|
+
"title": {
|
|
471
|
+
"type": "string",
|
|
472
|
+
"description": "Human-readable skill title"
|
|
473
|
+
},
|
|
474
|
+
"description": {
|
|
475
|
+
"type": "string",
|
|
476
|
+
"description": "What the skill does and when an agent should use it"
|
|
477
|
+
},
|
|
478
|
+
"category": {
|
|
479
|
+
"type": "string",
|
|
480
|
+
"description": "Category name"
|
|
481
|
+
},
|
|
482
|
+
"owner_handle": {
|
|
483
|
+
"type": "string",
|
|
484
|
+
"description": "Publisher handle"
|
|
485
|
+
},
|
|
486
|
+
"owner_name": {
|
|
487
|
+
"type": "string",
|
|
488
|
+
"description": "Publisher display name"
|
|
489
|
+
},
|
|
490
|
+
"license": {
|
|
491
|
+
"type": [
|
|
492
|
+
"string",
|
|
493
|
+
"null"
|
|
494
|
+
],
|
|
495
|
+
"description": "SPDX license id when declared"
|
|
496
|
+
},
|
|
497
|
+
"security_flags": {
|
|
498
|
+
"type": "array",
|
|
499
|
+
"items": {
|
|
500
|
+
"type": "string"
|
|
501
|
+
},
|
|
502
|
+
"description": "Capability flags: docs_only, network_calls, executes_scripts, reads_secrets, untrusted_install"
|
|
503
|
+
},
|
|
504
|
+
"ai_audit_verdict": {
|
|
505
|
+
"type": [
|
|
506
|
+
"string",
|
|
507
|
+
"null"
|
|
508
|
+
],
|
|
509
|
+
"description": "Safety review verdict: pass, caution, warning, fail or inconclusive"
|
|
510
|
+
},
|
|
511
|
+
"repo_stars": {
|
|
512
|
+
"type": [
|
|
513
|
+
"number",
|
|
514
|
+
"null"
|
|
515
|
+
],
|
|
516
|
+
"description": "GitHub stars of the source repository"
|
|
517
|
+
},
|
|
518
|
+
"install_snippet": {
|
|
519
|
+
"type": "string",
|
|
520
|
+
"description": "One-line install command"
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
"required": [
|
|
524
|
+
"slug"
|
|
525
|
+
],
|
|
526
|
+
"additionalProperties": true
|
|
527
|
+
},
|
|
528
|
+
"description": "Matching skills, best first"
|
|
529
|
+
}
|
|
112
530
|
},
|
|
531
|
+
"required": [
|
|
532
|
+
"items"
|
|
533
|
+
]
|
|
113
534
|
},
|
|
535
|
+
"annotations": {
|
|
536
|
+
"title": "Trending skills",
|
|
537
|
+
"readOnlyHint": true,
|
|
538
|
+
"destructiveHint": false,
|
|
539
|
+
"idempotentHint": true,
|
|
540
|
+
"openWorldHint": false
|
|
541
|
+
}
|
|
114
542
|
},
|
|
115
543
|
{
|
|
116
|
-
name: "skillmd_recommend",
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
544
|
+
"name": "skillmd_recommend",
|
|
545
|
+
"title": "Recommend skills",
|
|
546
|
+
"description": "Recommend skills. With based_on set to a skill's owner/name slug, returns the top skills in that skill's category (excluding itself); without it, returns what is trending over the last 30 days.",
|
|
547
|
+
"inputSchema": {
|
|
548
|
+
"type": "object",
|
|
549
|
+
"properties": {
|
|
550
|
+
"based_on": {
|
|
551
|
+
"type": "string",
|
|
552
|
+
"pattern": "^[^/]+/[^/]+$",
|
|
553
|
+
"description": "Skill slug (owner/name) to base recommendations on"
|
|
554
|
+
},
|
|
555
|
+
"limit": {
|
|
556
|
+
"type": "integer",
|
|
557
|
+
"minimum": 1,
|
|
558
|
+
"maximum": 100,
|
|
559
|
+
"description": "Maximum number of results (default 10)"
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
"additionalProperties": false
|
|
563
|
+
},
|
|
564
|
+
"outputSchema": {
|
|
565
|
+
"type": "object",
|
|
566
|
+
"properties": {
|
|
567
|
+
"items": {
|
|
568
|
+
"type": "array",
|
|
569
|
+
"items": {
|
|
570
|
+
"type": "object",
|
|
571
|
+
"description": "A skill as listed in search and leaderboard results.",
|
|
572
|
+
"properties": {
|
|
573
|
+
"slug": {
|
|
574
|
+
"type": "string",
|
|
575
|
+
"description": "owner/name identifier, e.g. anthropic/pdf"
|
|
576
|
+
},
|
|
577
|
+
"title": {
|
|
578
|
+
"type": "string",
|
|
579
|
+
"description": "Human-readable skill title"
|
|
580
|
+
},
|
|
581
|
+
"description": {
|
|
582
|
+
"type": "string",
|
|
583
|
+
"description": "What the skill does and when an agent should use it"
|
|
584
|
+
},
|
|
585
|
+
"category": {
|
|
586
|
+
"type": "string",
|
|
587
|
+
"description": "Category name"
|
|
588
|
+
},
|
|
589
|
+
"owner_handle": {
|
|
590
|
+
"type": "string",
|
|
591
|
+
"description": "Publisher handle"
|
|
592
|
+
},
|
|
593
|
+
"owner_name": {
|
|
594
|
+
"type": "string",
|
|
595
|
+
"description": "Publisher display name"
|
|
596
|
+
},
|
|
597
|
+
"license": {
|
|
598
|
+
"type": [
|
|
599
|
+
"string",
|
|
600
|
+
"null"
|
|
601
|
+
],
|
|
602
|
+
"description": "SPDX license id when declared"
|
|
603
|
+
},
|
|
604
|
+
"security_flags": {
|
|
605
|
+
"type": "array",
|
|
606
|
+
"items": {
|
|
607
|
+
"type": "string"
|
|
608
|
+
},
|
|
609
|
+
"description": "Capability flags: docs_only, network_calls, executes_scripts, reads_secrets, untrusted_install"
|
|
610
|
+
},
|
|
611
|
+
"ai_audit_verdict": {
|
|
612
|
+
"type": [
|
|
613
|
+
"string",
|
|
614
|
+
"null"
|
|
615
|
+
],
|
|
616
|
+
"description": "Safety review verdict: pass, caution, warning, fail or inconclusive"
|
|
617
|
+
},
|
|
618
|
+
"repo_stars": {
|
|
619
|
+
"type": [
|
|
620
|
+
"number",
|
|
621
|
+
"null"
|
|
622
|
+
],
|
|
623
|
+
"description": "GitHub stars of the source repository"
|
|
624
|
+
},
|
|
625
|
+
"install_snippet": {
|
|
626
|
+
"type": "string",
|
|
627
|
+
"description": "One-line install command"
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
"required": [
|
|
631
|
+
"slug"
|
|
632
|
+
],
|
|
633
|
+
"additionalProperties": true
|
|
634
|
+
},
|
|
635
|
+
"description": "Matching skills, best first"
|
|
636
|
+
}
|
|
637
|
+
},
|
|
638
|
+
"required": [
|
|
639
|
+
"items"
|
|
640
|
+
]
|
|
121
641
|
},
|
|
642
|
+
"annotations": {
|
|
643
|
+
"title": "Recommend skills",
|
|
644
|
+
"readOnlyHint": true,
|
|
645
|
+
"destructiveHint": false,
|
|
646
|
+
"idempotentHint": true,
|
|
647
|
+
"openWorldHint": false
|
|
648
|
+
}
|
|
122
649
|
},
|
|
123
650
|
{
|
|
124
|
-
name: "skillmd_list_saved",
|
|
125
|
-
|
|
126
|
-
|
|
651
|
+
"name": "skillmd_list_saved",
|
|
652
|
+
"title": "List saved skills",
|
|
653
|
+
"description": "List the signed-in user's saved skills. Requires the SKILLMD_TOKEN environment variable (a SkillMD personal access token).",
|
|
654
|
+
"inputSchema": {
|
|
655
|
+
"type": "object",
|
|
656
|
+
"properties": {},
|
|
657
|
+
"additionalProperties": false
|
|
658
|
+
},
|
|
659
|
+
"outputSchema": {
|
|
660
|
+
"type": "object",
|
|
661
|
+
"properties": {
|
|
662
|
+
"items": {
|
|
663
|
+
"type": "array",
|
|
664
|
+
"items": {
|
|
665
|
+
"type": "object",
|
|
666
|
+
"description": "A skill as listed in search and leaderboard results.",
|
|
667
|
+
"properties": {
|
|
668
|
+
"slug": {
|
|
669
|
+
"type": "string",
|
|
670
|
+
"description": "owner/name identifier, e.g. anthropic/pdf"
|
|
671
|
+
},
|
|
672
|
+
"title": {
|
|
673
|
+
"type": "string",
|
|
674
|
+
"description": "Human-readable skill title"
|
|
675
|
+
},
|
|
676
|
+
"description": {
|
|
677
|
+
"type": "string",
|
|
678
|
+
"description": "What the skill does and when an agent should use it"
|
|
679
|
+
},
|
|
680
|
+
"category": {
|
|
681
|
+
"type": "string",
|
|
682
|
+
"description": "Category name"
|
|
683
|
+
},
|
|
684
|
+
"owner_handle": {
|
|
685
|
+
"type": "string",
|
|
686
|
+
"description": "Publisher handle"
|
|
687
|
+
},
|
|
688
|
+
"owner_name": {
|
|
689
|
+
"type": "string",
|
|
690
|
+
"description": "Publisher display name"
|
|
691
|
+
},
|
|
692
|
+
"license": {
|
|
693
|
+
"type": [
|
|
694
|
+
"string",
|
|
695
|
+
"null"
|
|
696
|
+
],
|
|
697
|
+
"description": "SPDX license id when declared"
|
|
698
|
+
},
|
|
699
|
+
"security_flags": {
|
|
700
|
+
"type": "array",
|
|
701
|
+
"items": {
|
|
702
|
+
"type": "string"
|
|
703
|
+
},
|
|
704
|
+
"description": "Capability flags: docs_only, network_calls, executes_scripts, reads_secrets, untrusted_install"
|
|
705
|
+
},
|
|
706
|
+
"ai_audit_verdict": {
|
|
707
|
+
"type": [
|
|
708
|
+
"string",
|
|
709
|
+
"null"
|
|
710
|
+
],
|
|
711
|
+
"description": "Safety review verdict: pass, caution, warning, fail or inconclusive"
|
|
712
|
+
},
|
|
713
|
+
"repo_stars": {
|
|
714
|
+
"type": [
|
|
715
|
+
"number",
|
|
716
|
+
"null"
|
|
717
|
+
],
|
|
718
|
+
"description": "GitHub stars of the source repository"
|
|
719
|
+
},
|
|
720
|
+
"install_snippet": {
|
|
721
|
+
"type": "string",
|
|
722
|
+
"description": "One-line install command"
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
"required": [
|
|
726
|
+
"slug"
|
|
727
|
+
],
|
|
728
|
+
"additionalProperties": true
|
|
729
|
+
},
|
|
730
|
+
"description": "Matching skills, best first"
|
|
731
|
+
}
|
|
732
|
+
},
|
|
733
|
+
"required": [
|
|
734
|
+
"items"
|
|
735
|
+
]
|
|
736
|
+
},
|
|
737
|
+
"annotations": {
|
|
738
|
+
"title": "List saved skills",
|
|
739
|
+
"readOnlyHint": true,
|
|
740
|
+
"destructiveHint": false,
|
|
741
|
+
"idempotentHint": true,
|
|
742
|
+
"openWorldHint": false
|
|
743
|
+
}
|
|
127
744
|
},
|
|
128
745
|
{
|
|
129
|
-
name: "skillmd_lint",
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
inputSchema: {
|
|
133
|
-
type: "object",
|
|
134
|
-
properties: {
|
|
135
|
-
content: {
|
|
136
|
-
|
|
746
|
+
"name": "skillmd_lint",
|
|
747
|
+
"title": "Lint a SKILL.md",
|
|
748
|
+
"description": "Validate a SKILL.md against the SkillMD format and return diagnostics, capability flags and a 0-100 quality score. Pass raw SKILL.md content, or a registry slug (owner/name) to fetch and lint that skill.",
|
|
749
|
+
"inputSchema": {
|
|
750
|
+
"type": "object",
|
|
751
|
+
"properties": {
|
|
752
|
+
"content": {
|
|
753
|
+
"type": "string",
|
|
754
|
+
"description": "Raw SKILL.md text to validate (frontmatter plus body)"
|
|
755
|
+
},
|
|
756
|
+
"slug": {
|
|
757
|
+
"type": "string",
|
|
758
|
+
"pattern": "^[^/]+/[^/]+$",
|
|
759
|
+
"description": "Registry skill (owner/name) to fetch and validate instead of content"
|
|
760
|
+
}
|
|
137
761
|
},
|
|
762
|
+
"additionalProperties": false
|
|
138
763
|
},
|
|
139
|
-
|
|
764
|
+
"outputSchema": {
|
|
765
|
+
"type": "object",
|
|
766
|
+
"properties": {
|
|
767
|
+
"ok": {
|
|
768
|
+
"type": "boolean",
|
|
769
|
+
"description": "True when there are no error-level diagnostics"
|
|
770
|
+
},
|
|
771
|
+
"score": {
|
|
772
|
+
"type": "number",
|
|
773
|
+
"description": "Quality score 0-100"
|
|
774
|
+
},
|
|
775
|
+
"diagnostics": {
|
|
776
|
+
"type": "array",
|
|
777
|
+
"items": {
|
|
778
|
+
"type": "object",
|
|
779
|
+
"properties": {
|
|
780
|
+
"id": {
|
|
781
|
+
"type": "string",
|
|
782
|
+
"description": "Rule id, e.g. SK011"
|
|
783
|
+
},
|
|
784
|
+
"severity": {
|
|
785
|
+
"type": "string",
|
|
786
|
+
"enum": [
|
|
787
|
+
"error",
|
|
788
|
+
"warning",
|
|
789
|
+
"info"
|
|
790
|
+
]
|
|
791
|
+
},
|
|
792
|
+
"message": {
|
|
793
|
+
"type": "string"
|
|
794
|
+
},
|
|
795
|
+
"line": {
|
|
796
|
+
"type": [
|
|
797
|
+
"integer",
|
|
798
|
+
"null"
|
|
799
|
+
]
|
|
800
|
+
}
|
|
801
|
+
},
|
|
802
|
+
"required": [
|
|
803
|
+
"id",
|
|
804
|
+
"severity",
|
|
805
|
+
"message"
|
|
806
|
+
],
|
|
807
|
+
"additionalProperties": true
|
|
808
|
+
}
|
|
809
|
+
},
|
|
810
|
+
"security": {
|
|
811
|
+
"type": "object",
|
|
812
|
+
"description": "Scanner findings and capability flags",
|
|
813
|
+
"additionalProperties": true
|
|
814
|
+
}
|
|
815
|
+
},
|
|
816
|
+
"required": [
|
|
817
|
+
"ok",
|
|
818
|
+
"score",
|
|
819
|
+
"diagnostics"
|
|
820
|
+
]
|
|
821
|
+
},
|
|
822
|
+
"annotations": {
|
|
823
|
+
"title": "Lint a SKILL.md",
|
|
824
|
+
"readOnlyHint": true,
|
|
825
|
+
"destructiveHint": false,
|
|
826
|
+
"idempotentHint": true,
|
|
827
|
+
"openWorldHint": false
|
|
828
|
+
}
|
|
829
|
+
}
|
|
140
830
|
];
|
|
141
831
|
|
|
142
832
|
async function handleCall(name, args) {
|
|
@@ -174,12 +864,12 @@ async function handleCall(name, args) {
|
|
|
174
864
|
return text(trimItems(r.items));
|
|
175
865
|
}
|
|
176
866
|
case "skillmd_list_saved": {
|
|
177
|
-
if (!TOKEN) return
|
|
867
|
+
if (!TOKEN) return notice("Set SKILLMD_TOKEN (a SkillMD personal access token) to list your saved skills.");
|
|
178
868
|
const r = await api(`/api/favorites`);
|
|
179
869
|
return text(r.items ?? []);
|
|
180
870
|
}
|
|
181
871
|
case "skillmd_lint": {
|
|
182
|
-
if (!lint) return
|
|
872
|
+
if (!lint) return notice("Validation engine unavailable — reinstall the skillmds package (npm i -g skillmds), or run `npm ci && npm run build` in a source checkout.");
|
|
183
873
|
let raw = args.content;
|
|
184
874
|
let slug;
|
|
185
875
|
let verified = false;
|
|
@@ -190,18 +880,18 @@ async function handleCall(name, args) {
|
|
|
190
880
|
slug = slugName;
|
|
191
881
|
verified = !!skill.verified;
|
|
192
882
|
}
|
|
193
|
-
if (!raw) return
|
|
883
|
+
if (!raw) return notice("Provide `content` (raw SKILL.md) or `slug` (owner/name).");
|
|
194
884
|
const result = lint(raw, { ...(slug ? { slug } : {}), verified });
|
|
195
885
|
return text({ ok: result.ok, score: result.score, diagnostics: result.diagnostics, security: result.security });
|
|
196
886
|
}
|
|
197
887
|
case "skillmd_install": {
|
|
198
|
-
if (!skillMdFor) return
|
|
888
|
+
if (!skillMdFor) return notice("skillmds is not fully installed — reinstall it (npm i -g skillmds) and try again.");
|
|
199
889
|
const [owner, slugName] = String(args.slug).split("/");
|
|
200
890
|
// Defense in depth: slugName becomes a directory name below — refuse
|
|
201
891
|
// anything outside the registry's slugify alphabet (path separators,
|
|
202
892
|
// "..", etc.) before touching the network or filesystem.
|
|
203
893
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(slugName ?? "")) {
|
|
204
|
-
return
|
|
894
|
+
return notice(`Refused: invalid skill name "${slugName}" — expected a lowercase slug.`);
|
|
205
895
|
}
|
|
206
896
|
const skill = await api(`/api/skills/${owner}/${slugName}`);
|
|
207
897
|
const flags = skill.security_flags ?? [];
|
|
@@ -212,7 +902,7 @@ async function handleCall(name, args) {
|
|
|
212
902
|
const result = lint(raw, { slug: slugName });
|
|
213
903
|
if (!result.ok) {
|
|
214
904
|
const errors = result.diagnostics.filter((d) => d.severity === "error");
|
|
215
|
-
return
|
|
905
|
+
return notice(`Refused: ${args.slug} failed validation (${errors.map((d) => `${d.id}: ${d.message}`).join("; ")}). Not installed.`);
|
|
216
906
|
}
|
|
217
907
|
}
|
|
218
908
|
const baseDir = args.dest ? resolve(args.dest) : join(homedir(), ".claude", "skills");
|
|
@@ -265,7 +955,7 @@ async function handleCall(name, args) {
|
|
|
265
955
|
written = resolved.length || 1;
|
|
266
956
|
if (!resolved.some((f) => f.path === "SKILL.md")) await writeSafe("SKILL.md", raw);
|
|
267
957
|
} catch (e) {
|
|
268
|
-
if (e && e.integrity) return
|
|
958
|
+
if (e && e.integrity) return notice(`Refused: ${args.slug} failed integrity verification — ${e.message}. Not installed.`);
|
|
269
959
|
await writeSafe("SKILL.md", raw);
|
|
270
960
|
note = ` NOTE: pack assets could not be fetched — only SKILL.md was written. For the full pack run: npx skillmds add ${args.slug}`;
|
|
271
961
|
}
|
|
@@ -273,7 +963,11 @@ async function handleCall(name, args) {
|
|
|
273
963
|
await writeSafe("SKILL.md", raw);
|
|
274
964
|
}
|
|
275
965
|
api(`/api/skills/${owner}/${slugName}/install`, { method: "POST", body: JSON.stringify({ via: "mcp" }) }).catch(() => {});
|
|
276
|
-
|
|
966
|
+
const summary = { installed: true, slug: args.slug, dir, files_written: written, security_flags: flags, ...(note ? { note: note.trim() } : {}) };
|
|
967
|
+
return {
|
|
968
|
+
content: [{ type: "text", text: `Installed ${args.slug} → ${dir} (${written} file${written === 1 ? "" : "s"}; security: ${flags.join(", ") || "unscanned"})${note}` }],
|
|
969
|
+
structuredContent: summary,
|
|
970
|
+
};
|
|
277
971
|
}
|
|
278
972
|
default:
|
|
279
973
|
throw new Error(`Unknown tool: ${name}`);
|
|
@@ -281,7 +975,25 @@ async function handleCall(name, args) {
|
|
|
281
975
|
}
|
|
282
976
|
|
|
283
977
|
async function startMcpServer() {
|
|
284
|
-
const server = new Server(
|
|
978
|
+
const server = new Server(
|
|
979
|
+
{
|
|
980
|
+
name: "skillmd",
|
|
981
|
+
version: VERSION,
|
|
982
|
+
title: "SkillMD",
|
|
983
|
+
description:
|
|
984
|
+
"The open registry of Agent Skills: search, inspect, lint and install 25,000+ linted, security-reviewed SKILL.md files for Claude Code, Cursor, Codex and 60+ other agents.",
|
|
985
|
+
websiteUrl: "https://skillmd.com",
|
|
986
|
+
icons: [
|
|
987
|
+
{ src: "https://skillmd.com/favicon.png", mimeType: "image/png", sizes: ["512x512"] },
|
|
988
|
+
{ src: "https://skillmd.com/favicon.svg", mimeType: "image/svg+xml", sizes: ["any"] },
|
|
989
|
+
],
|
|
990
|
+
},
|
|
991
|
+
{
|
|
992
|
+
capabilities: { tools: {} },
|
|
993
|
+
instructions:
|
|
994
|
+
"SkillMD is a registry of Agent Skills (SKILL.md files). Use skillmd_search to find skills for a task, skillmd_get to inspect one (safety verdict, capability flags, provenance), skillmd_install to write it into the agent's skills directory, and skillmd_lint to validate your own SKILL.md. skillmd_trending and skillmd_recommend surface popular and related skills. Only skillmd_install writes files; it never executes scripts.",
|
|
995
|
+
},
|
|
996
|
+
);
|
|
285
997
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
286
998
|
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
287
999
|
try {
|
package/package.json
CHANGED