skillmds 0.1.0 → 1.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/README.md ADDED
@@ -0,0 +1,128 @@
1
+ <p align="center">
2
+ <img src="https://skillmd.com/skillmd-banner.jpg" alt="SkillMD" width="640">
3
+ </p>
4
+
5
+ # skillmds
6
+
7
+ [![npm version](https://img.shields.io/npm/v/skillmds.svg)](https://www.npmjs.com/package/skillmds)
8
+ [![npm downloads](https://img.shields.io/npm/dm/skillmds.svg)](https://www.npmjs.com/package/skillmds)
9
+ [![license](https://img.shields.io/npm/l/skillmds.svg)](#license)
10
+
11
+ > SkillMD for agents — the official **MCP server** *and* the **`skillmd` CLI** for **[SkillMD](https://skillmd.com)**, the open, verified registry of Agent Skills.
12
+
13
+ This one package ships two tools:
14
+
15
+ - **`skillmds`** — an MCP server so any MCP-capable agent (Claude Code, Claude Desktop, Cursor, …) can search, fetch, validate, and install `SKILL.md` skills with no copy-paste.
16
+ - **`skillmd`** — a CLI that lints and security-scans skills before installing or publishing them. *The registry that lints.*
17
+
18
+ ---
19
+
20
+ ## CLI quick start
21
+
22
+ ```bash
23
+ npm i -g skillmds # installs the `skillmd` command (and `skillmds`)
24
+
25
+ skillmd lint ./my-skill # validate against the spec + quality score
26
+ skillmd lint . --format sarif # SARIF for GitHub Code Scanning
27
+ skillmd scan . --deny executes_scripts
28
+ skillmd search pdf --verified
29
+ skillmd add anthropic/pdf -a claude-code -g # lints before installing
30
+ skillmd init my-skill
31
+ skillmd login && skillmd publish ./my-skill # refuses to publish on lint errors
32
+ ```
33
+
34
+ Without a global install, run a one-off with `npx -p skillmds skillmd lint .`.
35
+ Commands: `lint`/`check`, `scan`, `rules`, `init`, `search`, `add`, `list`, `remove`, `update`, `publish`, `login`. All support `--json`.
36
+
37
+ ---
38
+
39
+ ## MCP server
40
+
41
+ ## Install
42
+
43
+ **Claude Code** (one line):
44
+
45
+ ```bash
46
+ claude mcp add skillmds -- npx -y skillmds
47
+ ```
48
+
49
+ **Claude Desktop / Cursor / any MCP client** — add to your MCP config:
50
+
51
+ ```jsonc
52
+ {
53
+ "mcpServers": {
54
+ "skillmds": {
55
+ "command": "npx",
56
+ "args": ["-y", "skillmds"]
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ That's it. Restart your client and the SkillMD tools are available.
63
+
64
+ ---
65
+
66
+ ## What you can do
67
+
68
+ Once connected, just ask your agent in plain language:
69
+
70
+ - *"Find a skill for optimizing Dockerfiles."*
71
+ - *"Install the anthropic/pdf skill."*
72
+ - *"What are the top-rated data skills right now?"*
73
+
74
+ The agent picks the right tool, fetches the skill from SkillMD, and writes it into your skills directory.
75
+
76
+ ## Tools
77
+
78
+ | Tool | Auth | What it does |
79
+ | --- | --- | --- |
80
+ | `skillmd_search` | – | Search skills by name, description, or task (filter by category, type, rating, verified). |
81
+ | `skillmd_get` | – | Fetch one skill by `owner/name`, with its `SKILL.md`, provenance, license, and security flags. |
82
+ | `skillmd_install` | – | Write a skill's `SKILL.md` into your agent's skills dir. **Never executes scripts.** |
83
+ | `skillmd_trending` | – | Top skills on the leaderboard (`30d` or `all`, optional category). |
84
+ | `skillmd_recommend` | – | Skills similar to one you give, or trending if none. |
85
+ | `skillmd_list_saved` | token | Your saved skills (requires `SKILLMD_TOKEN`). |
86
+ | `skillmd_lint` | – | Validate a SKILL.md against the spec; returns diagnostics, security flags, and a quality score (0-100). Pass `content` or a `slug`. |
87
+
88
+ By default, `skillmd_install` writes to `~/.claude/skills/<name>/SKILL.md`. Pass a `dest` to target another directory.
89
+
90
+ ## Configuration
91
+
92
+ Both are optional environment variables:
93
+
94
+ | Variable | Default | Purpose |
95
+ | --- | --- | --- |
96
+ | `SKILLMD_API` | `https://skillmd-api.vinoor.workers.dev` | Override the API base URL. |
97
+ | `SKILLMD_TOKEN` | – | SkillMD personal access token; enables `skillmd_list_saved` and personalized recommendations. |
98
+
99
+ Example with a token:
100
+
101
+ ```jsonc
102
+ {
103
+ "mcpServers": {
104
+ "skillmds": {
105
+ "command": "npx",
106
+ "args": ["-y", "skillmds"],
107
+ "env": { "SKILLMD_TOKEN": "skillmd_pat_…" }
108
+ }
109
+ }
110
+ }
111
+ ```
112
+
113
+ ## Safety
114
+
115
+ SkillMD shows security flags (executes scripts, network calls, reads secrets, or docs-only) parsed from every skill's files, and **this server never runs a skill's scripts** — `skillmd_install` only writes the `SKILL.md` to disk. Review a skill before relying on it, especially from unverified authors.
116
+
117
+ ## Requirements
118
+
119
+ - Node.js **18+**
120
+
121
+ ## Links
122
+
123
+ - 🌐 Registry: **[skillmd.com](https://skillmd.com)**
124
+ - 🧩 What is an Agent Skill? See the [FAQ](https://skillmd.com/#faq)
125
+
126
+ ## License
127
+
128
+ MIT
@@ -14,6 +14,14 @@ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprot
14
14
  import { mkdir, writeFile } from "node:fs/promises";
15
15
  import { homedir } from "node:os";
16
16
  import { join, resolve } from "node:path";
17
+ // Shared validation engine, bundled into ./vendor at publish time (npm run build).
18
+ // Falls back gracefully if the vendor build is absent (e.g. running from source).
19
+ let lint = null;
20
+ try {
21
+ ({ lint } = await import("../vendor/index.js"));
22
+ } catch {
23
+ /* skillmd_lint will report that validation is unavailable */
24
+ }
17
25
 
18
26
  const API = process.env.SKILLMD_API || "https://skillmd-api.vinoor.workers.dev";
19
27
  const TOKEN = process.env.SKILLMD_TOKEN || "";
@@ -86,6 +94,18 @@ const TOOLS = [
86
94
  description: "List the signed-in user's saved skills. Requires SKILLMD_TOKEN to be set.",
87
95
  inputSchema: { type: "object", properties: {} },
88
96
  },
97
+ {
98
+ name: "skillmd_lint",
99
+ description:
100
+ "Validate a SKILL.md against the SkillMD spec and return diagnostics, security flags, and a quality score (0-100). Pass raw SKILL.md content, or a registry slug (owner/name) to fetch and lint.",
101
+ inputSchema: {
102
+ type: "object",
103
+ properties: {
104
+ content: { type: "string", description: "Raw SKILL.md content to validate" },
105
+ slug: { type: "string", description: "Registry slug owner/name to fetch and validate" },
106
+ },
107
+ },
108
+ },
89
109
  ];
90
110
 
91
111
  function reconstructSkillMd(skill) {
@@ -134,6 +154,20 @@ async function handleCall(name, args) {
134
154
  const r = await api(`/api/favorites`);
135
155
  return text(r.items ?? []);
136
156
  }
157
+ case "skillmd_lint": {
158
+ if (!lint) return text("Validation engine unavailable — run `npm run build` in the skillmds package.");
159
+ let raw = args.content;
160
+ let slug;
161
+ if (!raw && args.slug) {
162
+ const [owner, slugName] = String(args.slug).split("/");
163
+ const skill = await api(`/api/skills/${owner}/${slugName}`);
164
+ raw = reconstructSkillMd(skill);
165
+ slug = slugName;
166
+ }
167
+ if (!raw) return text("Provide `content` (raw SKILL.md) or `slug` (owner/name).");
168
+ const result = lint(raw, slug ? { slug } : {});
169
+ return text({ ok: result.ok, score: result.score, diagnostics: result.diagnostics, security: result.security });
170
+ }
137
171
  case "skillmd_install": {
138
172
  const [owner, slugName] = String(args.slug).split("/");
139
173
  const skill = await api(`/api/skills/${owner}/${slugName}`);
@@ -153,7 +187,7 @@ async function handleCall(name, args) {
153
187
  }
154
188
  }
155
189
 
156
- const server = new Server({ name: "skillmd", version: "0.1.0" }, { capabilities: { tools: {} } });
190
+ const server = new Server({ name: "skillmd", version: "1.0.0" }, { capabilities: { tools: {} } });
157
191
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
158
192
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
159
193
  try {
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ // The `skillmd` CLI, shipped inside the `skillmds` package.
3
+ import("../dist/cli.js");