@skillsmith/mcp-server 0.5.0 → 0.5.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 +13 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/__tests__/LocalIndexer.empty-dir.test.d.ts +21 -0
- package/dist/src/__tests__/LocalIndexer.empty-dir.test.d.ts.map +1 -0
- package/dist/src/__tests__/LocalIndexer.empty-dir.test.js +38 -0
- package/dist/src/__tests__/LocalIndexer.empty-dir.test.js.map +1 -0
- package/dist/src/__tests__/get-skill.test.js +5 -0
- package/dist/src/__tests__/get-skill.test.js.map +1 -1
- package/dist/src/__tests__/search-installable.test.d.ts +11 -0
- package/dist/src/__tests__/search-installable.test.d.ts.map +1 -0
- package/dist/src/__tests__/search-installable.test.js +149 -0
- package/dist/src/__tests__/search-installable.test.js.map +1 -0
- package/dist/src/cli-flags.d.ts +20 -0
- package/dist/src/cli-flags.d.ts.map +1 -0
- package/dist/src/cli-flags.js +36 -0
- package/dist/src/cli-flags.js.map +1 -0
- package/dist/src/index.js +97 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/tools/LocalSkillSearch.d.ts.map +1 -1
- package/dist/src/tools/LocalSkillSearch.js +3 -0
- package/dist/src/tools/LocalSkillSearch.js.map +1 -1
- package/dist/src/tools/compare.d.ts +4 -4
- package/dist/src/tools/compare.js +4 -4
- package/dist/src/tools/compare.types.js +3 -3
- package/dist/src/tools/compare.types.js.map +1 -1
- package/dist/src/tools/get-skill.d.ts +6 -6
- package/dist/src/tools/get-skill.d.ts.map +1 -1
- package/dist/src/tools/get-skill.js +22 -9
- package/dist/src/tools/get-skill.js.map +1 -1
- package/dist/src/tools/install.d.ts.map +1 -1
- package/dist/src/tools/install.js +6 -1
- package/dist/src/tools/install.js.map +1 -1
- package/dist/src/tools/install.test.js +65 -0
- package/dist/src/tools/install.test.js.map +1 -1
- package/dist/src/tools/install.tool.js +1 -1
- package/dist/src/tools/install.tool.js.map +1 -1
- package/dist/src/tools/recommend.types.js +2 -2
- package/dist/src/tools/recommend.types.js.map +1 -1
- package/dist/src/tools/search.d.ts +6 -0
- package/dist/src/tools/search.d.ts.map +1 -1
- package/dist/src/tools/search.formatter.d.ts.map +1 -1
- package/dist/src/tools/search.formatter.js +4 -0
- package/dist/src/tools/search.formatter.js.map +1 -1
- package/dist/src/tools/search.js +41 -6
- package/dist/src/tools/search.js.map +1 -1
- package/dist/src/tools/suggest.d.ts +2 -2
- package/dist/src/tools/suggest.js +2 -2
- package/dist/src/tools/uninstall.d.ts.map +1 -1
- package/dist/src/tools/uninstall.js +1 -1
- package/dist/src/tools/uninstall.js.map +1 -1
- package/dist/src/tools/validate.types.js +1 -1
- package/dist/src/tools/validate.types.js.map +1 -1
- package/dist/src/webhooks/stripe-webhook-endpoint.d.ts +18 -1
- package/dist/src/webhooks/stripe-webhook-endpoint.d.ts.map +1 -1
- package/dist/src/webhooks/stripe-webhook-endpoint.js.map +1 -1
- package/dist/tests/cli-flags.test.d.ts +2 -0
- package/dist/tests/cli-flags.test.d.ts.map +1 -0
- package/dist/tests/cli-flags.test.js +33 -0
- package/dist/tests/cli-flags.test.js.map +1 -0
- package/dist/tests/install-assets.test.d.ts +16 -0
- package/dist/tests/install-assets.test.d.ts.map +1 -0
- package/dist/tests/install-assets.test.js +72 -0
- package/dist/tests/install-assets.test.js.map +1 -0
- package/dist/tests/startup-probe.test.d.ts +17 -0
- package/dist/tests/startup-probe.test.d.ts.map +1 -0
- package/dist/tests/startup-probe.test.js +209 -0
- package/dist/tests/startup-probe.test.js.map +1 -0
- package/dist/tests/tool-descriptions.test.d.ts +16 -0
- package/dist/tests/tool-descriptions.test.d.ts.map +1 -0
- package/dist/tests/tool-descriptions.test.js +63 -0
- package/dist/tests/tool-descriptions.test.js.map +1 -0
- package/package.json +3 -11
- package/server.json +2 -2
- package/src/assets/skills/skillsmith/SKILL.md +109 -80
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-5009: MCP server startup capability probe tests.
|
|
3
|
+
*
|
|
4
|
+
* Covers the structured `[skillsmith] embeddings: …` stderr log that runs once
|
|
5
|
+
* at server boot to make transformers-availability observable in production.
|
|
6
|
+
*
|
|
7
|
+
* Two tiers:
|
|
8
|
+
* 1. Unit tests — exercise probe behavior directly by stubbing
|
|
9
|
+
* EmbeddingService.checkAvailability / getTransformersLoadError before
|
|
10
|
+
* importing the mcp-server module under test. Cheap and deterministic.
|
|
11
|
+
* 2. Integration test — spawn the real built `dist/src/index.js` binary
|
|
12
|
+
* with SKILLSMITH_USE_MOCK_EMBEDDINGS=true and assert the stderr line
|
|
13
|
+
* appears (and stdout stays clean per MCP stdio protocol). Gated by a
|
|
14
|
+
* `beforeAll` that builds dist if absent (plan-review H9).
|
|
15
|
+
*/
|
|
16
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
17
|
+
import { existsSync } from 'node:fs';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest';
|
|
21
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
+
const __dirname = path.dirname(__filename);
|
|
23
|
+
const REPO_ROOT = path.resolve(__dirname, '..', '..', '..');
|
|
24
|
+
const DIST_ENTRY = path.join(REPO_ROOT, 'packages', 'mcp-server', 'dist', 'src', 'index.js');
|
|
25
|
+
/**
|
|
26
|
+
* Mirrors the probe in packages/mcp-server/src/index.ts. Kept in sync via the
|
|
27
|
+
* integration test below — if this drifts, the integration assertions will
|
|
28
|
+
* catch it.
|
|
29
|
+
*/
|
|
30
|
+
async function runProbe(deps, log, timeoutMs = 2000) {
|
|
31
|
+
const TIMEOUT_SENTINEL = Symbol('probe-timeout');
|
|
32
|
+
let timeoutHandle;
|
|
33
|
+
try {
|
|
34
|
+
const result = await Promise.race([
|
|
35
|
+
deps.checkAvailability(),
|
|
36
|
+
new Promise((resolve) => {
|
|
37
|
+
timeoutHandle = setTimeout(() => resolve(TIMEOUT_SENTINEL), timeoutMs);
|
|
38
|
+
}),
|
|
39
|
+
]);
|
|
40
|
+
if (result === TIMEOUT_SENTINEL) {
|
|
41
|
+
log('[skillsmith] embeddings: mock (transformers unavailable: probe-timeout after 2s; install @huggingface/transformers or set SKILLSMITH_USE_MOCK_EMBEDDINGS=true to silence)');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (result === true)
|
|
45
|
+
return;
|
|
46
|
+
const loadErr = deps.getTransformersLoadError();
|
|
47
|
+
const reason = loadErr?.message ?? 'module-load-failed';
|
|
48
|
+
log(`[skillsmith] embeddings: mock (transformers unavailable: ${reason}; install @huggingface/transformers or set SKILLSMITH_USE_MOCK_EMBEDDINGS=true to silence)`);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
52
|
+
log(`[skillsmith] embeddings: probe-failed (${msg}; install @huggingface/transformers or set SKILLSMITH_USE_MOCK_EMBEDDINGS=true to silence)`);
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
if (timeoutHandle !== undefined)
|
|
56
|
+
clearTimeout(timeoutHandle);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
describe('SMI-5009 startup probe — unit', () => {
|
|
60
|
+
afterEach(() => {
|
|
61
|
+
vi.useRealTimers();
|
|
62
|
+
});
|
|
63
|
+
it('is silent when real embeddings are available', async () => {
|
|
64
|
+
const logs = [];
|
|
65
|
+
await runProbe({
|
|
66
|
+
checkAvailability: () => Promise.resolve(true),
|
|
67
|
+
getTransformersLoadError: () => null,
|
|
68
|
+
}, (m) => logs.push(m));
|
|
69
|
+
expect(logs).toEqual([]);
|
|
70
|
+
});
|
|
71
|
+
it('logs structured mock-fallback warning with reason when checkAvailability returns false', async () => {
|
|
72
|
+
const logs = [];
|
|
73
|
+
const err = new Error('ENOENT: cannot find module @huggingface/transformers');
|
|
74
|
+
await runProbe({
|
|
75
|
+
checkAvailability: () => Promise.resolve(false),
|
|
76
|
+
getTransformersLoadError: () => err,
|
|
77
|
+
}, (m) => logs.push(m));
|
|
78
|
+
expect(logs).toHaveLength(1);
|
|
79
|
+
expect(logs[0]).toMatch(/\[skillsmith\] embeddings: mock \(transformers unavailable: ENOENT: cannot find module @huggingface\/transformers/);
|
|
80
|
+
// Remediation hint MUST be present per plan-review D3.
|
|
81
|
+
expect(logs[0]).toContain('install @huggingface/transformers');
|
|
82
|
+
expect(logs[0]).toContain('SKILLSMITH_USE_MOCK_EMBEDDINGS=true');
|
|
83
|
+
});
|
|
84
|
+
it('falls back to "module-load-failed" when no load error is recorded', async () => {
|
|
85
|
+
const logs = [];
|
|
86
|
+
await runProbe({
|
|
87
|
+
checkAvailability: () => Promise.resolve(false),
|
|
88
|
+
getTransformersLoadError: () => null,
|
|
89
|
+
}, (m) => logs.push(m));
|
|
90
|
+
expect(logs).toHaveLength(1);
|
|
91
|
+
expect(logs[0]).toContain('transformers unavailable: module-load-failed');
|
|
92
|
+
});
|
|
93
|
+
it('emits probe-timeout line and returns within ~2s when checkAvailability hangs forever', async () => {
|
|
94
|
+
const logs = [];
|
|
95
|
+
const start = Date.now();
|
|
96
|
+
await runProbe({
|
|
97
|
+
// Hangs forever — only the timeout sentinel should resolve.
|
|
98
|
+
checkAvailability: () => new Promise(() => undefined),
|
|
99
|
+
getTransformersLoadError: () => null,
|
|
100
|
+
}, (m) => logs.push(m), 100 // shrink timeout for the test so suite stays fast
|
|
101
|
+
);
|
|
102
|
+
const elapsed = Date.now() - start;
|
|
103
|
+
expect(logs).toHaveLength(1);
|
|
104
|
+
expect(logs[0]).toMatch(/embeddings: mock \(transformers unavailable: probe-timeout/);
|
|
105
|
+
// Must complete within a small multiple of the timeout — proves the
|
|
106
|
+
// hard-bound holds even when checkAvailability never resolves.
|
|
107
|
+
expect(elapsed).toBeLessThan(2000);
|
|
108
|
+
});
|
|
109
|
+
it('catches a thrown error and logs probe-failed without rethrowing', async () => {
|
|
110
|
+
const logs = [];
|
|
111
|
+
await expect(runProbe({
|
|
112
|
+
checkAvailability: () => Promise.reject(new Error('boom')),
|
|
113
|
+
getTransformersLoadError: () => null,
|
|
114
|
+
}, (m) => logs.push(m))).resolves.toBeUndefined();
|
|
115
|
+
expect(logs).toHaveLength(1);
|
|
116
|
+
expect(logs[0]).toMatch(/embeddings: probe-failed \(boom/);
|
|
117
|
+
expect(logs[0]).toContain('install @huggingface/transformers');
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
// Integration test — spawn the real built binary and assert the stderr line.
|
|
122
|
+
// Gated by a beforeAll dist build per plan-review H9 (H9: spawn-based tests
|
|
123
|
+
// can quietly run against a stale dist; force a fresh build).
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
describe('SMI-5009 startup probe — integration (spawn)', () => {
|
|
126
|
+
beforeAll(() => {
|
|
127
|
+
// H9 review finding: spawn-based tests can quietly run against a stale
|
|
128
|
+
// dist. Build mcp-server explicitly if dist is missing, and fail loudly
|
|
129
|
+
// if it still isn't present afterwards.
|
|
130
|
+
if (!existsSync(DIST_ENTRY)) {
|
|
131
|
+
const build = spawnSync('npm', ['run', 'build', '--workspace=@skillsmith/mcp-server'], {
|
|
132
|
+
stdio: 'inherit',
|
|
133
|
+
cwd: REPO_ROOT,
|
|
134
|
+
});
|
|
135
|
+
if (build.status !== 0) {
|
|
136
|
+
throw new Error('mcp-server build failed in beforeAll');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (!existsSync(DIST_ENTRY)) {
|
|
140
|
+
throw new Error(`Expected ${DIST_ENTRY} to exist after build`);
|
|
141
|
+
}
|
|
142
|
+
}, 120_000);
|
|
143
|
+
it('starts the server, never pollutes stdout with [skillsmith] embeddings:, and emits the probe line on stderr when the mock fallback is engaged', async () => {
|
|
144
|
+
// Two acceptable outcomes when running against an environment where
|
|
145
|
+
// `@huggingface/transformers` is installed (the common case in CI):
|
|
146
|
+
//
|
|
147
|
+
// (a) probe runs, real embeddings available → SILENT (no embeddings: line)
|
|
148
|
+
// (b) probe runs with mock fallback → "[skillsmith] embeddings: mock …"
|
|
149
|
+
//
|
|
150
|
+
// The assertion is: stdout MUST NEVER contain `[skillsmith] embeddings:`
|
|
151
|
+
// (R2 / MCP stdio protocol invariant), and the server must reach the
|
|
152
|
+
// "Skillsmith MCP server running" stderr line within 10s (proving the
|
|
153
|
+
// probe did not block boot — R1).
|
|
154
|
+
const proc = spawn('node', [DIST_ENTRY], {
|
|
155
|
+
env: {
|
|
156
|
+
...process.env,
|
|
157
|
+
SKILLSMITH_SKIP_SKILL_INSTALL: '1',
|
|
158
|
+
SKILLSMITH_AUTO_UPDATE_CHECK: 'false',
|
|
159
|
+
},
|
|
160
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
161
|
+
});
|
|
162
|
+
const stderrChunks = [];
|
|
163
|
+
const stdoutChunks = [];
|
|
164
|
+
proc.stderr.on('data', (d) => stderrChunks.push(d.toString()));
|
|
165
|
+
proc.stdout.on('data', (d) => stdoutChunks.push(d.toString()));
|
|
166
|
+
try {
|
|
167
|
+
await new Promise((resolve, reject) => {
|
|
168
|
+
const timeout = setTimeout(() => {
|
|
169
|
+
reject(new Error(`server boot timeout — stderr so far:\n${stderrChunks.join('')}\nstdout so far:\n${stdoutChunks.join('')}`));
|
|
170
|
+
}, 10_000);
|
|
171
|
+
proc.stderr.on('data', (d) => {
|
|
172
|
+
if (d.toString().includes('Skillsmith MCP server running')) {
|
|
173
|
+
clearTimeout(timeout);
|
|
174
|
+
resolve();
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
proc.on('error', (err) => {
|
|
178
|
+
clearTimeout(timeout);
|
|
179
|
+
reject(err);
|
|
180
|
+
});
|
|
181
|
+
proc.on('exit', (code) => {
|
|
182
|
+
if (code !== null && code !== 0) {
|
|
183
|
+
clearTimeout(timeout);
|
|
184
|
+
reject(new Error(`mcp-server exited ${code} before reporting "running"; stderr:\n${stderrChunks.join('')}`));
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
proc.kill('SIGTERM');
|
|
191
|
+
}
|
|
192
|
+
const stderr = stderrChunks.join('');
|
|
193
|
+
const stdout = stdoutChunks.join('');
|
|
194
|
+
// Server reached the "running" line — proves the probe did not block
|
|
195
|
+
// boot (R1, 2s timeout enforced).
|
|
196
|
+
expect(stderr).toMatch(/Skillsmith MCP server running/);
|
|
197
|
+
// CRITICAL (R2): probe MUST NOT pollute stdout — would corrupt the MCP
|
|
198
|
+
// stdio protocol frame.
|
|
199
|
+
expect(stdout).not.toMatch(/\[skillsmith\] embeddings:/);
|
|
200
|
+
// If the probe DID log on stderr, it must use the structured shape
|
|
201
|
+
// (mock / probe-failed). On hosts where transformers is installed,
|
|
202
|
+
// the probe is silent — that path is also valid.
|
|
203
|
+
if (stderr.includes('[skillsmith] embeddings:')) {
|
|
204
|
+
expect(stderr).toMatch(/\[skillsmith\] embeddings: (mock|probe-failed)/);
|
|
205
|
+
expect(stderr).toContain('install @huggingface/transformers');
|
|
206
|
+
}
|
|
207
|
+
}, 30_000);
|
|
208
|
+
});
|
|
209
|
+
//# sourceMappingURL=startup-probe.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup-probe.test.js","sourceRoot":"","sources":["../../tests/startup-probe.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAEvE,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACjD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;AAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;AAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,CAAA;AAiB5F;;;;GAIG;AACH,KAAK,UAAU,QAAQ,CACrB,IAAe,EACf,GAA0B,EAC1B,SAAS,GAAG,IAAI;IAEhB,MAAM,gBAAgB,GAAkB,MAAM,CAAC,eAAe,CAAC,CAAA;IAC/D,IAAI,aAAyC,CAAA;IAE7C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAoC;YACnE,IAAI,CAAC,iBAAiB,EAAE;YACxB,IAAI,OAAO,CAA0B,CAAC,OAAO,EAAE,EAAE;gBAC/C,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,SAAS,CAAC,CAAA;YACxE,CAAC,CAAC;SACH,CAAC,CAAA;QAEF,IAAI,MAAM,KAAK,gBAAgB,EAAE,CAAC;YAChC,GAAG,CACD,2KAA2K,CAC5K,CAAA;YACD,OAAM;QACR,CAAC;QAED,IAAI,MAAM,KAAK,IAAI;YAAE,OAAM;QAE3B,MAAM,OAAO,GAAG,IAAI,CAAC,wBAAwB,EAAE,CAAA;QAC/C,MAAM,MAAM,GAAG,OAAO,EAAE,OAAO,IAAI,oBAAoB,CAAA;QACvD,GAAG,CACD,4DAA4D,MAAM,4FAA4F,CAC/J,CAAA;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC5D,GAAG,CACD,0CAA0C,GAAG,4FAA4F,CAC1I,CAAA;IACH,CAAC;YAAS,CAAC;QACT,IAAI,aAAa,KAAK,SAAS;YAAE,YAAY,CAAC,aAAa,CAAC,CAAA;IAC9D,CAAC;AACH,CAAC;AAED,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;IAC7C,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,aAAa,EAAE,CAAA;IACpB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,IAAI,GAAa,EAAE,CAAA;QACzB,MAAM,QAAQ,CACZ;YACE,iBAAiB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;YAC9C,wBAAwB,EAAE,GAAG,EAAE,CAAC,IAAI;SACrC,EACD,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CACpB,CAAA;QACD,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC1B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wFAAwF,EAAE,KAAK,IAAI,EAAE;QACtG,MAAM,IAAI,GAAa,EAAE,CAAA;QACzB,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAA;QAC7E,MAAM,QAAQ,CACZ;YACE,iBAAiB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;YAC/C,wBAAwB,EAAE,GAAG,EAAE,CAAC,GAAG;SACpC,EACD,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CACpB,CAAA;QACD,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAC5B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CACrB,mHAAmH,CACpH,CAAA;QACD,uDAAuD;QACvD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,mCAAmC,CAAC,CAAA;QAC9D,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,qCAAqC,CAAC,CAAA;IAClE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,IAAI,GAAa,EAAE,CAAA;QACzB,MAAM,QAAQ,CACZ;YACE,iBAAiB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;YAC/C,wBAAwB,EAAE,GAAG,EAAE,CAAC,IAAI;SACrC,EACD,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CACpB,CAAA;QACD,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAC5B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,8CAA8C,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sFAAsF,EAAE,KAAK,IAAI,EAAE;QACpG,MAAM,IAAI,GAAa,EAAE,CAAA;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACxB,MAAM,QAAQ,CACZ;YACE,4DAA4D;YAC5D,iBAAiB,EAAE,GAAG,EAAE,CAAC,IAAI,OAAO,CAAU,GAAG,EAAE,CAAC,SAAS,CAAC;YAC9D,wBAAwB,EAAE,GAAG,EAAE,CAAC,IAAI;SACrC,EACD,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EACnB,GAAG,CAAC,kDAAkD;SACvD,CAAA;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAA;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAC5B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,4DAA4D,CAAC,CAAA;QACrF,oEAAoE;QACpE,+DAA+D;QAC/D,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;IACpC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,IAAI,GAAa,EAAE,CAAA;QACzB,MAAM,MAAM,CACV,QAAQ,CACN;YACE,iBAAiB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC;YAC1D,wBAAwB,EAAE,GAAG,EAAE,CAAC,IAAI;SACrC,EACD,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CACpB,CACF,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAA;QAC1B,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAC5B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAA;QAC1D,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,mCAAmC,CAAC,CAAA;IAChE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,8EAA8E;AAC9E,6EAA6E;AAC7E,4EAA4E;AAC5E,8DAA8D;AAC9D,8EAA8E;AAE9E,QAAQ,CAAC,8CAA8C,EAAE,GAAG,EAAE;IAC5D,SAAS,CAAC,GAAG,EAAE;QACb,uEAAuE;QACvE,wEAAwE;QACxE,wCAAwC;QACxC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,oCAAoC,CAAC,EAAE;gBACrF,KAAK,EAAE,SAAS;gBAChB,GAAG,EAAE,SAAS;aACf,CAAC,CAAA;YACF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAA;YACzD,CAAC;QACH,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,YAAY,UAAU,uBAAuB,CAAC,CAAA;QAChE,CAAC;IACH,CAAC,EAAE,OAAO,CAAC,CAAA;IAEX,EAAE,CAAC,8IAA8I,EAAE,KAAK,IAAI,EAAE;QAC5J,oEAAoE;QACpE,oEAAoE;QACpE,EAAE;QACF,6EAA6E;QAC7E,0EAA0E;QAC1E,EAAE;QACF,yEAAyE;QACzE,qEAAqE;QACrE,sEAAsE;QACtE,kCAAkC;QAClC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,EAAE;YACvC,GAAG,EAAE;gBACH,GAAG,OAAO,CAAC,GAAG;gBACd,6BAA6B,EAAE,GAAG;gBAClC,4BAA4B,EAAE,OAAO;aACtC;YACD,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;SAClC,CAAC,CAAA;QAEF,MAAM,YAAY,GAAa,EAAE,CAAA;QACjC,MAAM,YAAY,GAAa,EAAE,CAAA;QACjC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;QACtE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;QAEtE,IAAI,CAAC;YACH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC1C,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;oBAC9B,MAAM,CACJ,IAAI,KAAK,CACP,yCAAyC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,qBAAqB,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAC3G,CACF,CAAA;gBACH,CAAC,EAAE,MAAM,CAAC,CAAA;gBACV,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE;oBACnC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC,EAAE,CAAC;wBAC3D,YAAY,CAAC,OAAO,CAAC,CAAA;wBACrB,OAAO,EAAE,CAAA;oBACX,CAAC;gBACH,CAAC,CAAC,CAAA;gBACF,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;oBACvB,YAAY,CAAC,OAAO,CAAC,CAAA;oBACrB,MAAM,CAAC,GAAG,CAAC,CAAA;gBACb,CAAC,CAAC,CAAA;gBACF,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;oBACvB,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;wBAChC,YAAY,CAAC,OAAO,CAAC,CAAA;wBACrB,MAAM,CACJ,IAAI,KAAK,CACP,qBAAqB,IAAI,yCAAyC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAC1F,CACF,CAAA;oBACH,CAAC;gBACH,CAAC,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;QACJ,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACtB,CAAC;QAED,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACpC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAEpC,qEAAqE;QACrE,kCAAkC;QAClC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAA;QAEvD,uEAAuE;QACvE,wBAAwB;QACxB,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAA;QAExD,mEAAmE;QACnE,mEAAmE;QACnE,iDAAiD;QACjD,IAAI,MAAM,CAAC,QAAQ,CAAC,0BAA0B,CAAC,EAAE,CAAC;YAChD,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,gDAAgD,CAAC,CAAA;YACxE,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,mCAAmC,CAAC,CAAA;QAC/D,CAAC;IACH,CAAC,EAAE,MAAM,CAAC,CAAA;AACZ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-4790 Wave 1 Step 1.5: Snapshot tests for MCP tool descriptions
|
|
3
|
+
*
|
|
4
|
+
* Each user-facing tool description must:
|
|
5
|
+
* 1. Lead with the canonical bracketed prefix `[Skillsmith — <Stage> stage]`
|
|
6
|
+
* (per the lifecycle taxonomy in docs/internal/implementation/_taxonomy.md)
|
|
7
|
+
* 2. Name "Skillsmith" prominently for product-name anchoring
|
|
8
|
+
* 3. Stay within the ≤1024-char target (no MCP-spec hard cap; aligns with
|
|
9
|
+
* Anthropic SKILL.md frontmatter convention)
|
|
10
|
+
*
|
|
11
|
+
* If you change a description intentionally, update the snapshot
|
|
12
|
+
* (`vitest -u`). If a snapshot mismatch surprises you, the description
|
|
13
|
+
* regressed — the prefix or anchor was lost.
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=tool-descriptions.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-descriptions.test.d.ts","sourceRoot":"","sources":["../../tests/tool-descriptions.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-4790 Wave 1 Step 1.5: Snapshot tests for MCP tool descriptions
|
|
3
|
+
*
|
|
4
|
+
* Each user-facing tool description must:
|
|
5
|
+
* 1. Lead with the canonical bracketed prefix `[Skillsmith — <Stage> stage]`
|
|
6
|
+
* (per the lifecycle taxonomy in docs/internal/implementation/_taxonomy.md)
|
|
7
|
+
* 2. Name "Skillsmith" prominently for product-name anchoring
|
|
8
|
+
* 3. Stay within the ≤1024-char target (no MCP-spec hard cap; aligns with
|
|
9
|
+
* Anthropic SKILL.md frontmatter convention)
|
|
10
|
+
*
|
|
11
|
+
* If you change a description intentionally, update the snapshot
|
|
12
|
+
* (`vitest -u`). If a snapshot mismatch surprises you, the description
|
|
13
|
+
* regressed — the prefix or anchor was lost.
|
|
14
|
+
*/
|
|
15
|
+
import { describe, it, expect } from 'vitest';
|
|
16
|
+
import { searchToolSchema } from '../src/tools/search.js';
|
|
17
|
+
import { getSkillToolSchema } from '../src/tools/get-skill.js';
|
|
18
|
+
import { recommendToolSchema } from '../src/tools/recommend.types.js';
|
|
19
|
+
import { compareToolSchema } from '../src/tools/compare.types.js';
|
|
20
|
+
import { installTool } from '../src/tools/install.tool.js';
|
|
21
|
+
import { uninstallTool } from '../src/tools/uninstall.js';
|
|
22
|
+
import { validateToolSchema } from '../src/tools/validate.types.js';
|
|
23
|
+
// Tool → expected lifecycle stage (must match docs/internal/implementation/_taxonomy.md)
|
|
24
|
+
const TOOL_STAGE_MAPPING = [
|
|
25
|
+
{ tool: searchToolSchema, name: 'search', stage: 'Discover' },
|
|
26
|
+
{ tool: getSkillToolSchema, name: 'get_skill', stage: 'Evaluate' },
|
|
27
|
+
{ tool: recommendToolSchema, name: 'skill_recommend', stage: 'Discover' },
|
|
28
|
+
{ tool: compareToolSchema, name: 'skill_compare', stage: 'Evaluate' },
|
|
29
|
+
{ tool: installTool, name: 'install_skill', stage: 'Install' },
|
|
30
|
+
{ tool: uninstallTool, name: 'uninstall_skill', stage: 'Retire' },
|
|
31
|
+
{ tool: validateToolSchema, name: 'skill_validate', stage: 'Install' },
|
|
32
|
+
];
|
|
33
|
+
describe('SMI-4790: MCP tool descriptions', () => {
|
|
34
|
+
describe('canonical prefix', () => {
|
|
35
|
+
it.each(TOOL_STAGE_MAPPING)('$name: leads with [Skillsmith — $stage stage]', ({ tool, stage }) => {
|
|
36
|
+
const expectedPrefix = `[Skillsmith — ${stage} stage]`;
|
|
37
|
+
expect(tool.description).toMatch(new RegExp(`^${expectedPrefix.replace(/[\\[\]—]/g, '\\$&')}`));
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe('product-name anchor', () => {
|
|
41
|
+
it.each(TOOL_STAGE_MAPPING)('$name: contains "Skillsmith" at least twice', ({ tool }) => {
|
|
42
|
+
const matches = tool.description.match(/Skillsmith/g);
|
|
43
|
+
expect(matches?.length ?? 0).toBeGreaterThanOrEqual(2);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe('length budget', () => {
|
|
47
|
+
it.each(TOOL_STAGE_MAPPING)('$name: description under 1024 characters', ({ tool }) => {
|
|
48
|
+
expect(tool.description.length).toBeLessThanOrEqual(1024);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('snapshot', () => {
|
|
52
|
+
it('all 7 descriptions match snapshot', () => {
|
|
53
|
+
const snapshot = TOOL_STAGE_MAPPING.map(({ name, stage, tool }) => ({
|
|
54
|
+
name,
|
|
55
|
+
stage,
|
|
56
|
+
description: tool.description,
|
|
57
|
+
length: tool.description.length,
|
|
58
|
+
}));
|
|
59
|
+
expect(snapshot).toMatchSnapshot();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=tool-descriptions.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-descriptions.test.js","sourceRoot":"","sources":["../../tests/tool-descriptions.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAA;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAEnE,yFAAyF;AACzF,MAAM,kBAAkB,GAAG;IACzB,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE;IAC7D,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE;IAClE,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,UAAU,EAAE;IACzE,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,EAAE;IACrE,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,SAAS,EAAE;IAC9D,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,QAAQ,EAAE;IACjE,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,SAAS,EAAE;CAC9D,CAAA;AAEV,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CACzB,+CAA+C,EAC/C,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;YAClB,MAAM,cAAc,GAAG,iBAAiB,KAAK,SAAS,CAAA;YACtD,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,CAC9B,IAAI,MAAM,CAAC,IAAI,cAAc,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,CAAC,CAC9D,CAAA;QACH,CAAC,CACF,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACnC,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,6CAA6C,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;YACtF,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;YACrD,MAAM,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAA;QACxD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,0CAA0C,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;YACnF,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAA;QAC3D,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;QACxB,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;YAC3C,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;gBAClE,IAAI;gBACJ,KAAK;gBACL,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;aAChC,CAAC,CAAC,CAAA;YACH,MAAM,CAAC,QAAQ,CAAC,CAAC,eAAe,EAAE,CAAA;QACpC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skillsmith/mcp-server",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"mcpName": "io.github.smith-horn/skillsmith",
|
|
5
5
|
"description": "MCP server for Skillsmith skill discovery",
|
|
6
6
|
"type": "module",
|
|
@@ -34,23 +34,15 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
37
|
-
"@skillsmith/core": "^0.
|
|
37
|
+
"@skillsmith/core": "^0.7.2",
|
|
38
38
|
"esbuild": "0.27.2",
|
|
39
39
|
"ulid": "3.0.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"tsx": "4.21.0",
|
|
43
|
-
"vitest": "4.1.
|
|
43
|
+
"vitest": "4.1.6",
|
|
44
44
|
"zod": "3.25.76"
|
|
45
45
|
},
|
|
46
|
-
"peerDependencies": {
|
|
47
|
-
"@skillsmith/enterprise": "*"
|
|
48
|
-
},
|
|
49
|
-
"peerDependenciesMeta": {
|
|
50
|
-
"@skillsmith/enterprise": {
|
|
51
|
-
"optional": true
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
46
|
"files": [
|
|
55
47
|
"dist",
|
|
56
48
|
"src/assets",
|
package/server.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"url": "https://github.com/smith-horn/skillsmith",
|
|
9
9
|
"source": "github"
|
|
10
10
|
},
|
|
11
|
-
"version": "0.5.
|
|
11
|
+
"version": "0.5.2",
|
|
12
12
|
"_meta": {
|
|
13
13
|
"io.skillsmith/categories": ["developer-tools", "ai-agents", "skill-management"],
|
|
14
14
|
"io.skillsmith/keywords": [
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
{
|
|
24
24
|
"registryType": "npm",
|
|
25
25
|
"identifier": "@skillsmith/mcp-server",
|
|
26
|
-
"version": "0.5.
|
|
26
|
+
"version": "0.5.2",
|
|
27
27
|
"transport": {
|
|
28
28
|
"type": "stdio"
|
|
29
29
|
},
|
|
@@ -1,24 +1,71 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "Skillsmith"
|
|
3
|
-
description: "
|
|
3
|
+
description: "Skillsmith is the canonical lifecycle manager for agent skills (SKILL.md format) across any MCP-capable agent runtime — Claude Code, Cursor, Copilot, Codex, Windsurf. Discover, evaluate, install, use, maintain, author, govern, retire skills. Triggers: 'use Skillsmith', 'ask Skillsmith', 'search Skillsmith', 'find a Skillsmith skill', 'install with Skillsmith', 'Skillsmith trust tier', 'Skillsmith audit', 'create a skill with Skillsmith', 'publish to Skillsmith', 'Skillsmith quota', 'pin a Skillsmith skill', 'compare Skillsmith skills'. Routes natural-language requests to Skillsmith MCP tools and CLI commands."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Skillsmith
|
|
7
7
|
|
|
8
|
-
Skillsmith is your skill
|
|
8
|
+
Skillsmith is your master skill for the full lifecycle of agent skills — across every MCP-capable agent runtime. Use Skillsmith to discover, evaluate, install, use, maintain, author, govern, and retire SKILL.md-format skills without leaving your editor.
|
|
9
|
+
|
|
10
|
+
## Lifecycle Stages
|
|
11
|
+
|
|
12
|
+
Every Skillsmith operation maps to one of 8 lifecycle stages. Use the stage name when you want to be explicit ("use Skillsmith to **discover** testing skills"); natural prompts work too.
|
|
13
|
+
|
|
14
|
+
| # | Stage | What it covers | Primary surface |
|
|
15
|
+
|---|---|---|---|
|
|
16
|
+
| 1 | **Discover** | Find skills by query, recommendation, or filter | MCP `search`, `skill_recommend` |
|
|
17
|
+
| 2 | **Evaluate** | Compare candidates, read trust badges, view diffs | MCP `get_skill`, `skill_compare`, `skill_diff` |
|
|
18
|
+
| 3 | **Install** | Add a skill to the runtime's skills directory | MCP `install_skill`; CLI `install` |
|
|
19
|
+
| 4 | **Use** | Invoke the installed skill at the runtime layer | runtime-native (e.g. Claude Code skill match) |
|
|
20
|
+
| 5 | **Maintain** | Update, pin, audit collisions, configure modes | CLI `update`/`pin`/`unpin`/`audit collisions`; MCP `skill_updates`, `skill_outdated` |
|
|
21
|
+
| 6 | **Author** | Init, validate, transform, publish a new skill | CLI `author init/validate/publish/subagent/transform/mcp-init` |
|
|
22
|
+
| 7 | **Govern** | Audit logs, RBAC, SIEM, compliance (Team+) | MCP `audit_export`, `audit_query`, `siem_export` |
|
|
23
|
+
| 8 | **Retire** | Uninstall, deprecate | MCP `uninstall_skill`; CLI `remove` |
|
|
9
24
|
|
|
10
25
|
## Quick Reference: MCP Tools
|
|
11
26
|
|
|
12
|
-
| Tool | Use
|
|
13
|
-
|
|
14
|
-
| `search` | Finding skills by keyword
|
|
15
|
-
| `
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
27
|
+
| Tool | Stage | Use when | Example prompt |
|
|
28
|
+
|---|---|---|---|
|
|
29
|
+
| `search` | Discover | Finding skills by keyword/category/trust tier | "Use Skillsmith to search for testing skills" |
|
|
30
|
+
| `skill_recommend` | Discover | Contextual recommendations | "Ask Skillsmith to recommend skills for my React project" |
|
|
31
|
+
| `get_skill` | Evaluate | Full details for a known skill | "Use Skillsmith to show details for community/jest-helper" |
|
|
32
|
+
| `skill_compare` | Evaluate | Side-by-side comparison | "Use Skillsmith to compare jest-helper and vitest-helper" |
|
|
33
|
+
| `skill_diff` | Evaluate | Diff two installed versions | "Use Skillsmith to diff jest-helper versions" |
|
|
34
|
+
| `install_skill` | Install | Add a skill to your runtime | "Use Skillsmith to install jest-helper" |
|
|
35
|
+
| `skill_validate` | Install | Pre-install validation of SKILL.md | "Use Skillsmith to validate ./my-skill" |
|
|
36
|
+
| `skill_updates` | Maintain | Check for available updates | "Ask Skillsmith for updates to my installed skills" |
|
|
37
|
+
| `skill_outdated` | Maintain | List skills behind latest | "Use Skillsmith to show outdated skills" |
|
|
38
|
+
| `skill_inventory_audit` | Maintain | Namespace-collision audit (Team+) | "Use Skillsmith to audit my skills inventory" |
|
|
39
|
+
| `audit_export` / `audit_query` / `siem_export` | Govern | Compliance + SIEM (Enterprise) | "Use Skillsmith to export audit logs for last 30 days" |
|
|
40
|
+
| `uninstall_skill` | Retire | Remove an installed skill | "Use Skillsmith to uninstall jest-helper" |
|
|
41
|
+
|
|
42
|
+
**Triggering tip**: prefix natural-language prompts with `Use Skillsmith to ...` or `Ask Skillsmith for ...`. The product-name anchor binds tool selection reliably across MCP-capable runtimes.
|
|
43
|
+
|
|
44
|
+
## Routing CLI-only Operations
|
|
45
|
+
|
|
46
|
+
Some lifecycle operations live in the CLI and have no MCP equivalent (yet). When the user asks for these, surface the exact terminal command:
|
|
47
|
+
|
|
48
|
+
| Operation | CLI command |
|
|
49
|
+
|---|---|
|
|
50
|
+
| Pin a skill to a version | `skillsmith pin <skill> <version>` |
|
|
51
|
+
| Unpin a skill | `skillsmith unpin <skill>` |
|
|
52
|
+
| Update all installed skills | `skillsmith update --all` |
|
|
53
|
+
| Audit advisories (Team+) | `skillsmith audit advisories` |
|
|
54
|
+
| Audit collisions | `skillsmith audit collisions` |
|
|
55
|
+
| Configure audit mode | `skillsmith config set audit_mode <preventative\|power_user\|governance\|off>` |
|
|
56
|
+
| Author a new skill | `skillsmith author init <name>` |
|
|
57
|
+
| Publish a skill | `skillsmith author publish` |
|
|
58
|
+
| Login | `skillsmith login` |
|
|
59
|
+
|
|
60
|
+
Always show the command verbatim with a one-line note: "Run this in your terminal."
|
|
61
|
+
|
|
62
|
+
## Cross-Runtime Behavior
|
|
63
|
+
|
|
64
|
+
Skillsmith's MCP server works in **any MCP-capable agent runtime**:
|
|
65
|
+
|
|
66
|
+
- **Claude Code** — default runtime. Skills install to `~/.claude/skills/`.
|
|
67
|
+
- **Cursor / Copilot / Windsurf** — set `SKILLSMITH_CLIENT=<runtime>` in your MCP server env config to install to the runtime-equivalent path. See [Getting Started](https://skillsmith.app/docs/getting-started).
|
|
68
|
+
- **Custom MCP routers** — universal MCP tool calls work; skill-file install paths configurable via `SKILLSMITH_CLIENT`.
|
|
22
69
|
|
|
23
70
|
## Trust Tiers
|
|
24
71
|
|
|
@@ -26,122 +73,104 @@ Skills are categorized by verification level:
|
|
|
26
73
|
|
|
27
74
|
| Tier | Badge | Meaning | When to Trust |
|
|
28
75
|
|------|-------|---------|---------------|
|
|
29
|
-
| **
|
|
30
|
-
| **
|
|
31
|
-
| **Community** | Yellow |
|
|
32
|
-
| **
|
|
33
|
-
|
|
34
|
-
For detailed criteria, see [TRUST_TIERS.md](docs/TRUST_TIERS.md).
|
|
76
|
+
| **Verified** | Green checkmark | Official Skillsmith / Anthropic | Always safe |
|
|
77
|
+
| **Curated** | Blue badge | Vendor-org publisher, ≥0.80 quality | Generally safe |
|
|
78
|
+
| **Community** | Yellow | Security scan + required metadata | Review before install |
|
|
79
|
+
| **Experimental** | Orange | Beta / new | Use cautiously |
|
|
80
|
+
| **Unknown** | Red warning | No verification | Only if you trust the author |
|
|
35
81
|
|
|
36
|
-
|
|
82
|
+
For criteria detail, see https://skillsmith.app/docs/trust-tiers.
|
|
37
83
|
|
|
38
|
-
|
|
84
|
+
## Pricing & Quotas
|
|
39
85
|
|
|
40
|
-
| Tier | API
|
|
41
|
-
|
|
86
|
+
| Tier | API calls/month | Price |
|
|
87
|
+
|---|---|---|
|
|
42
88
|
| **Community** | 1,000 | Free |
|
|
43
89
|
| **Individual** | 10,000 | $9.99/mo |
|
|
44
90
|
| **Team** | 100,000 | $25/user/mo |
|
|
45
91
|
| **Enterprise** | Unlimited | $55/user/mo |
|
|
46
92
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
For details, see [QUOTAS.md](docs/QUOTAS.md).
|
|
93
|
+
Usage warnings at 80% and 90%. Upgrade at https://skillsmith.app/upgrade.
|
|
50
94
|
|
|
51
95
|
## Security Model
|
|
52
96
|
|
|
53
|
-
Skillsmith
|
|
54
|
-
|
|
55
|
-
### What Skillsmith Validates
|
|
97
|
+
Skillsmith is the security boundary between untrusted skill sources and your runtime.
|
|
56
98
|
|
|
57
|
-
|
|
99
|
+
**What Skillsmith validates before install**:
|
|
58
100
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
101
|
+
- SKILL.md frontmatter and required fields
|
|
102
|
+
- Security scan: jailbreak patterns, suspicious URLs, sensitive file access
|
|
103
|
+
- Typosquatting check against known skills
|
|
104
|
+
- Blocklist of known-malicious skills
|
|
63
105
|
|
|
64
|
-
|
|
106
|
+
**What Skillsmith cannot prevent**:
|
|
65
107
|
|
|
66
|
-
- Novel attack patterns not in
|
|
108
|
+
- Novel attack patterns not in detection database
|
|
67
109
|
- Social engineering in legitimate-looking instructions
|
|
68
110
|
- Runtime behavior (skills execute with your permissions)
|
|
69
111
|
|
|
70
|
-
**Recommendation**:
|
|
71
|
-
|
|
72
|
-
For the complete security model, see [SECURITY.md](docs/SECURITY.md).
|
|
112
|
+
**Recommendation**: review skill content before installation, especially for unverified skills.
|
|
73
113
|
|
|
74
114
|
## Creating Skills
|
|
75
115
|
|
|
76
|
-
|
|
116
|
+
Skill authoring lives in the CLI:
|
|
77
117
|
|
|
78
118
|
```
|
|
79
|
-
|
|
80
|
-
|
|
119
|
+
skillsmith author init my-new-skill
|
|
120
|
+
skillsmith author validate
|
|
121
|
+
skillsmith author publish
|
|
81
122
|
```
|
|
82
123
|
|
|
83
|
-
|
|
84
|
-
- YAML frontmatter (name ≤64 chars, description ≤1024 chars)
|
|
85
|
-
- Progressive disclosure structure (4 levels)
|
|
86
|
-
- Directory organization
|
|
87
|
-
- Validation checklist
|
|
124
|
+
For an end-to-end walkthrough, see https://skillsmith.app/docs/tutorials/author.
|
|
88
125
|
|
|
89
|
-
|
|
126
|
+
The companion **skill-builder** skill guides you through frontmatter, progressive disclosure structure, and directory organization. Install it with `skillsmith install skill-builder` (it's not bundled by default).
|
|
90
127
|
|
|
91
|
-
|
|
92
|
-
# Find all testing skills
|
|
93
|
-
"Search for testing skills"
|
|
94
|
-
|
|
95
|
-
# Find verified skills only
|
|
96
|
-
"Find verified skills for git workflows"
|
|
128
|
+
## Common Workflows
|
|
97
129
|
|
|
98
|
-
|
|
99
|
-
"Search for devops skills with score above 80"
|
|
130
|
+
### Discover then install
|
|
100
131
|
|
|
101
|
-
|
|
102
|
-
"
|
|
132
|
+
```
|
|
133
|
+
"Use Skillsmith to recommend skills for my Next.js project"
|
|
134
|
+
"Use Skillsmith to install community/next-helper"
|
|
103
135
|
```
|
|
104
136
|
|
|
105
|
-
|
|
137
|
+
### Evaluate before installing
|
|
106
138
|
|
|
107
|
-
### Install a Skill
|
|
108
139
|
```
|
|
109
|
-
"
|
|
140
|
+
"Use Skillsmith to compare jest-helper and vitest-helper"
|
|
141
|
+
"Use Skillsmith to show details for community/vitest-helper"
|
|
142
|
+
"Use Skillsmith to install community/vitest-helper"
|
|
110
143
|
```
|
|
111
|
-
Skillsmith downloads the skill, runs security scan, and installs to ~/.claude/skills/.
|
|
112
144
|
|
|
113
|
-
###
|
|
114
|
-
```
|
|
115
|
-
"What skills do I have installed?"
|
|
116
|
-
```
|
|
145
|
+
### Maintain installed skills
|
|
117
146
|
|
|
118
|
-
### Remove a Skill
|
|
119
147
|
```
|
|
120
|
-
"
|
|
148
|
+
"Ask Skillsmith for updates to my installed skills"
|
|
149
|
+
# Then run in terminal:
|
|
150
|
+
skillsmith update --all
|
|
121
151
|
```
|
|
122
152
|
|
|
123
|
-
###
|
|
153
|
+
### Audit before sharing your skill folder
|
|
154
|
+
|
|
124
155
|
```
|
|
125
|
-
"
|
|
156
|
+
"Use Skillsmith to audit my skills inventory"
|
|
157
|
+
# Or in terminal:
|
|
158
|
+
skillsmith audit collisions
|
|
126
159
|
```
|
|
127
|
-
Skillsmith analyzes your project context and suggests relevant skills.
|
|
128
160
|
|
|
129
161
|
## License
|
|
130
162
|
|
|
131
163
|
Skillsmith uses **Elastic License 2.0**:
|
|
132
|
-
- You can self-host for internal use
|
|
133
|
-
- You can modify for your own use
|
|
134
|
-
- You cannot offer Skillsmith as a managed service to others
|
|
135
|
-
- You cannot circumvent license key functionality
|
|
136
|
-
|
|
137
|
-
## Related Documentation
|
|
138
164
|
|
|
139
|
-
-
|
|
140
|
-
-
|
|
141
|
-
-
|
|
165
|
+
- Self-host for internal use ✓
|
|
166
|
+
- Modify for your own use ✓
|
|
167
|
+
- Offer Skillsmith as a managed service to others ✗
|
|
168
|
+
- Circumvent license key functionality ✗
|
|
142
169
|
|
|
143
170
|
## Getting Help
|
|
144
171
|
|
|
145
|
-
- Docs:
|
|
172
|
+
- Docs: https://skillsmith.app/docs
|
|
173
|
+
- Tutorials (lifecycle walkthroughs): https://skillsmith.app/docs/tutorials
|
|
174
|
+
- CLI: `skillsmith --help`
|
|
146
175
|
- Issues: https://github.com/smith-horn/skillsmith/issues
|
|
147
176
|
- Email: support@skillsmith.app
|