@skillsmith/mcp-server 0.1.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.
Files changed (306) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/src/__tests__/get-skill.test.d.ts +6 -0
  3. package/dist/src/__tests__/get-skill.test.d.ts.map +1 -0
  4. package/dist/src/__tests__/get-skill.test.js +88 -0
  5. package/dist/src/__tests__/get-skill.test.js.map +1 -0
  6. package/dist/src/__tests__/middleware/errorFormatter.test.d.ts +7 -0
  7. package/dist/src/__tests__/middleware/errorFormatter.test.d.ts.map +1 -0
  8. package/dist/src/__tests__/middleware/errorFormatter.test.js +304 -0
  9. package/dist/src/__tests__/middleware/errorFormatter.test.js.map +1 -0
  10. package/dist/src/__tests__/middleware/license.test.d.ts +7 -0
  11. package/dist/src/__tests__/middleware/license.test.d.ts.map +1 -0
  12. package/dist/src/__tests__/middleware/license.test.js +500 -0
  13. package/dist/src/__tests__/middleware/license.test.js.map +1 -0
  14. package/dist/src/__tests__/search.test.d.ts +6 -0
  15. package/dist/src/__tests__/search.test.d.ts.map +1 -0
  16. package/dist/src/__tests__/search.test.js +86 -0
  17. package/dist/src/__tests__/search.test.js.map +1 -0
  18. package/dist/src/__tests__/test-utils.d.ts +19 -0
  19. package/dist/src/__tests__/test-utils.d.ts.map +1 -0
  20. package/dist/src/__tests__/test-utils.js +87 -0
  21. package/dist/src/__tests__/test-utils.js.map +1 -0
  22. package/dist/src/context/index.d.ts +19 -0
  23. package/dist/src/context/index.d.ts.map +1 -0
  24. package/dist/src/context/index.js +25 -0
  25. package/dist/src/context/index.js.map +1 -0
  26. package/dist/src/context/project-detector.d.ts +145 -0
  27. package/dist/src/context/project-detector.d.ts.map +1 -0
  28. package/dist/src/context/project-detector.js +321 -0
  29. package/dist/src/context/project-detector.js.map +1 -0
  30. package/dist/src/context.d.ts +100 -0
  31. package/dist/src/context.d.ts.map +1 -0
  32. package/dist/src/context.js +157 -0
  33. package/dist/src/context.js.map +1 -0
  34. package/dist/src/core-shim.d.ts +7 -0
  35. package/dist/src/core-shim.d.ts.map +1 -0
  36. package/dist/src/core-shim.js +9 -0
  37. package/dist/src/core-shim.js.map +1 -0
  38. package/dist/src/health/healthCheck.d.ts +88 -0
  39. package/dist/src/health/healthCheck.d.ts.map +1 -0
  40. package/dist/src/health/healthCheck.js +117 -0
  41. package/dist/src/health/healthCheck.js.map +1 -0
  42. package/dist/src/health/index.d.ts +21 -0
  43. package/dist/src/health/index.d.ts.map +1 -0
  44. package/dist/src/health/index.js +21 -0
  45. package/dist/src/health/index.js.map +1 -0
  46. package/dist/src/health/readinessCheck.d.ts +139 -0
  47. package/dist/src/health/readinessCheck.d.ts.map +1 -0
  48. package/dist/src/health/readinessCheck.js +266 -0
  49. package/dist/src/health/readinessCheck.js.map +1 -0
  50. package/dist/src/index.d.ts +8 -0
  51. package/dist/src/index.d.ts.map +1 -0
  52. package/dist/src/index.js +178 -0
  53. package/dist/src/index.js.map +1 -0
  54. package/dist/src/index.test.d.ts +2 -0
  55. package/dist/src/index.test.d.ts.map +1 -0
  56. package/dist/src/index.test.js +43 -0
  57. package/dist/src/index.test.js.map +1 -0
  58. package/dist/src/logger.d.ts +26 -0
  59. package/dist/src/logger.d.ts.map +1 -0
  60. package/dist/src/logger.js +179 -0
  61. package/dist/src/logger.js.map +1 -0
  62. package/dist/src/middleware/__tests__/csp.test.d.ts +2 -0
  63. package/dist/src/middleware/__tests__/csp.test.d.ts.map +1 -0
  64. package/dist/src/middleware/__tests__/csp.test.js +389 -0
  65. package/dist/src/middleware/__tests__/csp.test.js.map +1 -0
  66. package/dist/src/middleware/csp.d.ts +87 -0
  67. package/dist/src/middleware/csp.d.ts.map +1 -0
  68. package/dist/src/middleware/csp.js +273 -0
  69. package/dist/src/middleware/csp.js.map +1 -0
  70. package/dist/src/middleware/degradation.d.ts +99 -0
  71. package/dist/src/middleware/degradation.d.ts.map +1 -0
  72. package/dist/src/middleware/degradation.js +315 -0
  73. package/dist/src/middleware/degradation.js.map +1 -0
  74. package/dist/src/middleware/errorFormatter.d.ts +119 -0
  75. package/dist/src/middleware/errorFormatter.d.ts.map +1 -0
  76. package/dist/src/middleware/errorFormatter.js +294 -0
  77. package/dist/src/middleware/errorFormatter.js.map +1 -0
  78. package/dist/src/middleware/index.d.ts +10 -0
  79. package/dist/src/middleware/index.d.ts.map +1 -0
  80. package/dist/src/middleware/index.js +14 -0
  81. package/dist/src/middleware/index.js.map +1 -0
  82. package/dist/src/middleware/license.d.ts +161 -0
  83. package/dist/src/middleware/license.d.ts.map +1 -0
  84. package/dist/src/middleware/license.js +281 -0
  85. package/dist/src/middleware/license.js.map +1 -0
  86. package/dist/src/middleware/toolFeatureMapping.d.ts +36 -0
  87. package/dist/src/middleware/toolFeatureMapping.d.ts.map +1 -0
  88. package/dist/src/middleware/toolFeatureMapping.js +90 -0
  89. package/dist/src/middleware/toolFeatureMapping.js.map +1 -0
  90. package/dist/src/onboarding/first-run.d.ts +64 -0
  91. package/dist/src/onboarding/first-run.d.ts.map +1 -0
  92. package/dist/src/onboarding/first-run.js +77 -0
  93. package/dist/src/onboarding/first-run.js.map +1 -0
  94. package/dist/src/onboarding/index.d.ts +7 -0
  95. package/dist/src/onboarding/index.d.ts.map +1 -0
  96. package/dist/src/onboarding/index.js +7 -0
  97. package/dist/src/onboarding/index.js.map +1 -0
  98. package/dist/src/suggestions/index.d.ts +21 -0
  99. package/dist/src/suggestions/index.d.ts.map +1 -0
  100. package/dist/src/suggestions/index.js +20 -0
  101. package/dist/src/suggestions/index.js.map +1 -0
  102. package/dist/src/suggestions/suggestion-engine.d.ts +185 -0
  103. package/dist/src/suggestions/suggestion-engine.d.ts.map +1 -0
  104. package/dist/src/suggestions/suggestion-engine.js +352 -0
  105. package/dist/src/suggestions/suggestion-engine.js.map +1 -0
  106. package/dist/src/suggestions/types.d.ts +88 -0
  107. package/dist/src/suggestions/types.d.ts.map +1 -0
  108. package/dist/src/suggestions/types.js +21 -0
  109. package/dist/src/suggestions/types.js.map +1 -0
  110. package/dist/src/tools/analyze.d.ts +151 -0
  111. package/dist/src/tools/analyze.d.ts.map +1 -0
  112. package/dist/src/tools/analyze.js +205 -0
  113. package/dist/src/tools/analyze.js.map +1 -0
  114. package/dist/src/tools/compare.d.ts +149 -0
  115. package/dist/src/tools/compare.d.ts.map +1 -0
  116. package/dist/src/tools/compare.js +464 -0
  117. package/dist/src/tools/compare.js.map +1 -0
  118. package/dist/src/tools/get-skill.d.ts +116 -0
  119. package/dist/src/tools/get-skill.d.ts.map +1 -0
  120. package/dist/src/tools/get-skill.js +224 -0
  121. package/dist/src/tools/get-skill.js.map +1 -0
  122. package/dist/src/tools/index.d.ts +20 -0
  123. package/dist/src/tools/index.d.ts.map +1 -0
  124. package/dist/src/tools/index.js +20 -0
  125. package/dist/src/tools/index.js.map +1 -0
  126. package/dist/src/tools/install.d.ts +122 -0
  127. package/dist/src/tools/install.d.ts.map +1 -0
  128. package/dist/src/tools/install.js +314 -0
  129. package/dist/src/tools/install.js.map +1 -0
  130. package/dist/src/tools/recommend.d.ts +171 -0
  131. package/dist/src/tools/recommend.d.ts.map +1 -0
  132. package/dist/src/tools/recommend.js +325 -0
  133. package/dist/src/tools/recommend.js.map +1 -0
  134. package/dist/src/tools/search.d.ts +121 -0
  135. package/dist/src/tools/search.d.ts.map +1 -0
  136. package/dist/src/tools/search.js +249 -0
  137. package/dist/src/tools/search.js.map +1 -0
  138. package/dist/src/tools/suggest.d.ts +181 -0
  139. package/dist/src/tools/suggest.d.ts.map +1 -0
  140. package/dist/src/tools/suggest.js +342 -0
  141. package/dist/src/tools/suggest.js.map +1 -0
  142. package/dist/src/tools/uninstall.d.ts +123 -0
  143. package/dist/src/tools/uninstall.d.ts.map +1 -0
  144. package/dist/src/tools/uninstall.js +250 -0
  145. package/dist/src/tools/uninstall.js.map +1 -0
  146. package/dist/src/tools/validate.d.ts +122 -0
  147. package/dist/src/tools/validate.d.ts.map +1 -0
  148. package/dist/src/tools/validate.js +497 -0
  149. package/dist/src/tools/validate.js.map +1 -0
  150. package/dist/src/utils/installed-skills.d.ts +101 -0
  151. package/dist/src/utils/installed-skills.d.ts.map +1 -0
  152. package/dist/src/utils/installed-skills.js +220 -0
  153. package/dist/src/utils/installed-skills.js.map +1 -0
  154. package/dist/src/utils/validation.d.ts +76 -0
  155. package/dist/src/utils/validation.d.ts.map +1 -0
  156. package/dist/src/utils/validation.js +153 -0
  157. package/dist/src/utils/validation.js.map +1 -0
  158. package/dist/src/webhooks/index.d.ts +8 -0
  159. package/dist/src/webhooks/index.d.ts.map +1 -0
  160. package/dist/src/webhooks/index.js +9 -0
  161. package/dist/src/webhooks/index.js.map +1 -0
  162. package/dist/src/webhooks/webhook-endpoint.d.ts +149 -0
  163. package/dist/src/webhooks/webhook-endpoint.d.ts.map +1 -0
  164. package/dist/src/webhooks/webhook-endpoint.js +339 -0
  165. package/dist/src/webhooks/webhook-endpoint.js.map +1 -0
  166. package/dist/tests/compare.test.d.ts +6 -0
  167. package/dist/tests/compare.test.d.ts.map +1 -0
  168. package/dist/tests/compare.test.js +225 -0
  169. package/dist/tests/compare.test.js.map +1 -0
  170. package/dist/tests/context/project-detector.test.d.ts +6 -0
  171. package/dist/tests/context/project-detector.test.d.ts.map +1 -0
  172. package/dist/tests/context/project-detector.test.js +719 -0
  173. package/dist/tests/context/project-detector.test.js.map +1 -0
  174. package/dist/tests/e2e/compare.e2e.test.d.ts +10 -0
  175. package/dist/tests/e2e/compare.e2e.test.d.ts.map +1 -0
  176. package/dist/tests/e2e/compare.e2e.test.js +286 -0
  177. package/dist/tests/e2e/compare.e2e.test.js.map +1 -0
  178. package/dist/tests/e2e/install-flow.e2e.test.d.ts +10 -0
  179. package/dist/tests/e2e/install-flow.e2e.test.d.ts.map +1 -0
  180. package/dist/tests/e2e/install-flow.e2e.test.js +209 -0
  181. package/dist/tests/e2e/install-flow.e2e.test.js.map +1 -0
  182. package/dist/tests/e2e/recommend.e2e.test.d.ts +12 -0
  183. package/dist/tests/e2e/recommend.e2e.test.d.ts.map +1 -0
  184. package/dist/tests/e2e/recommend.e2e.test.js +347 -0
  185. package/dist/tests/e2e/recommend.e2e.test.js.map +1 -0
  186. package/dist/tests/e2e/skill-flow.e2e.test.d.ts +10 -0
  187. package/dist/tests/e2e/skill-flow.e2e.test.d.ts.map +1 -0
  188. package/dist/tests/e2e/skill-flow.e2e.test.js +280 -0
  189. package/dist/tests/e2e/skill-flow.e2e.test.js.map +1 -0
  190. package/dist/tests/e2e/suggest.e2e.test.d.ts +13 -0
  191. package/dist/tests/e2e/suggest.e2e.test.d.ts.map +1 -0
  192. package/dist/tests/e2e/suggest.e2e.test.js +347 -0
  193. package/dist/tests/e2e/suggest.e2e.test.js.map +1 -0
  194. package/dist/tests/e2e/utils/baseline-collector.d.ts +107 -0
  195. package/dist/tests/e2e/utils/baseline-collector.d.ts.map +1 -0
  196. package/dist/tests/e2e/utils/baseline-collector.js +211 -0
  197. package/dist/tests/e2e/utils/baseline-collector.js.map +1 -0
  198. package/dist/tests/e2e/utils/hardcoded-detector.d.ts +46 -0
  199. package/dist/tests/e2e/utils/hardcoded-detector.d.ts.map +1 -0
  200. package/dist/tests/e2e/utils/hardcoded-detector.js +255 -0
  201. package/dist/tests/e2e/utils/hardcoded-detector.js.map +1 -0
  202. package/dist/tests/e2e/utils/index.d.ts +7 -0
  203. package/dist/tests/e2e/utils/index.d.ts.map +1 -0
  204. package/dist/tests/e2e/utils/index.js +7 -0
  205. package/dist/tests/e2e/utils/index.js.map +1 -0
  206. package/dist/tests/e2e/utils/linear-reporter.d.ts +60 -0
  207. package/dist/tests/e2e/utils/linear-reporter.d.ts.map +1 -0
  208. package/dist/tests/e2e/utils/linear-reporter.js +232 -0
  209. package/dist/tests/e2e/utils/linear-reporter.js.map +1 -0
  210. package/dist/tests/health.test.d.ts +9 -0
  211. package/dist/tests/health.test.d.ts.map +1 -0
  212. package/dist/tests/health.test.js +308 -0
  213. package/dist/tests/health.test.js.map +1 -0
  214. package/dist/tests/integration/analyze.integration.test.d.ts +2 -0
  215. package/dist/tests/integration/analyze.integration.test.d.ts.map +1 -0
  216. package/dist/tests/integration/analyze.integration.test.js +244 -0
  217. package/dist/tests/integration/analyze.integration.test.js.map +1 -0
  218. package/dist/tests/integration/compare.integration.test.d.ts +2 -0
  219. package/dist/tests/integration/compare.integration.test.d.ts.map +1 -0
  220. package/dist/tests/integration/compare.integration.test.js +120 -0
  221. package/dist/tests/integration/compare.integration.test.js.map +1 -0
  222. package/dist/tests/integration/fixtures/test-skills.d.ts +62 -0
  223. package/dist/tests/integration/fixtures/test-skills.d.ts.map +1 -0
  224. package/dist/tests/integration/fixtures/test-skills.js +644 -0
  225. package/dist/tests/integration/fixtures/test-skills.js.map +1 -0
  226. package/dist/tests/integration/get-skill.integration.test.d.ts +6 -0
  227. package/dist/tests/integration/get-skill.integration.test.d.ts.map +1 -0
  228. package/dist/tests/integration/get-skill.integration.test.js +203 -0
  229. package/dist/tests/integration/get-skill.integration.test.js.map +1 -0
  230. package/dist/tests/integration/github-api.integration.test.d.ts +14 -0
  231. package/dist/tests/integration/github-api.integration.test.d.ts.map +1 -0
  232. package/dist/tests/integration/github-api.integration.test.js +190 -0
  233. package/dist/tests/integration/github-api.integration.test.js.map +1 -0
  234. package/dist/tests/integration/install.integration.test.d.ts +6 -0
  235. package/dist/tests/integration/install.integration.test.d.ts.map +1 -0
  236. package/dist/tests/integration/install.integration.test.js +282 -0
  237. package/dist/tests/integration/install.integration.test.js.map +1 -0
  238. package/dist/tests/integration/recommend.integration.test.d.ts +2 -0
  239. package/dist/tests/integration/recommend.integration.test.d.ts.map +1 -0
  240. package/dist/tests/integration/recommend.integration.test.js +215 -0
  241. package/dist/tests/integration/recommend.integration.test.js.map +1 -0
  242. package/dist/tests/integration/search.integration.test.d.ts +6 -0
  243. package/dist/tests/integration/search.integration.test.d.ts.map +1 -0
  244. package/dist/tests/integration/search.integration.test.js +229 -0
  245. package/dist/tests/integration/search.integration.test.js.map +1 -0
  246. package/dist/tests/integration/setup.d.ts +71 -0
  247. package/dist/tests/integration/setup.d.ts.map +1 -0
  248. package/dist/tests/integration/setup.js +124 -0
  249. package/dist/tests/integration/setup.js.map +1 -0
  250. package/dist/tests/integration/uninstall.integration.test.d.ts +6 -0
  251. package/dist/tests/integration/uninstall.integration.test.d.ts.map +1 -0
  252. package/dist/tests/integration/uninstall.integration.test.js +296 -0
  253. package/dist/tests/integration/uninstall.integration.test.js.map +1 -0
  254. package/dist/tests/integration/validate.integration.test.d.ts +2 -0
  255. package/dist/tests/integration/validate.integration.test.d.ts.map +1 -0
  256. package/dist/tests/integration/validate.integration.test.js +181 -0
  257. package/dist/tests/integration/validate.integration.test.js.map +1 -0
  258. package/dist/tests/onboarding/first-run.test.d.ts +7 -0
  259. package/dist/tests/onboarding/first-run.test.d.ts.map +1 -0
  260. package/dist/tests/onboarding/first-run.test.js +258 -0
  261. package/dist/tests/onboarding/first-run.test.js.map +1 -0
  262. package/dist/tests/performance/search-performance.test.d.ts +10 -0
  263. package/dist/tests/performance/search-performance.test.d.ts.map +1 -0
  264. package/dist/tests/performance/search-performance.test.js +218 -0
  265. package/dist/tests/performance/search-performance.test.js.map +1 -0
  266. package/dist/tests/recommend.test.d.ts +6 -0
  267. package/dist/tests/recommend.test.d.ts.map +1 -0
  268. package/dist/tests/recommend.test.js +208 -0
  269. package/dist/tests/recommend.test.js.map +1 -0
  270. package/dist/tests/suggestions/suggestion-engine.test.d.ts +6 -0
  271. package/dist/tests/suggestions/suggestion-engine.test.d.ts.map +1 -0
  272. package/dist/tests/suggestions/suggestion-engine.test.js +448 -0
  273. package/dist/tests/suggestions/suggestion-engine.test.js.map +1 -0
  274. package/dist/tests/test-utils.d.ts +74 -0
  275. package/dist/tests/test-utils.d.ts.map +1 -0
  276. package/dist/tests/test-utils.js +98 -0
  277. package/dist/tests/test-utils.js.map +1 -0
  278. package/dist/tests/tools.test.d.ts +5 -0
  279. package/dist/tests/tools.test.d.ts.map +1 -0
  280. package/dist/tests/tools.test.js +138 -0
  281. package/dist/tests/tools.test.js.map +1 -0
  282. package/dist/tests/unit/installed-skills.test.d.ts +6 -0
  283. package/dist/tests/unit/installed-skills.test.d.ts.map +1 -0
  284. package/dist/tests/unit/installed-skills.test.js +285 -0
  285. package/dist/tests/unit/installed-skills.test.js.map +1 -0
  286. package/dist/tests/unit/logger.test.d.ts +6 -0
  287. package/dist/tests/unit/logger.test.d.ts.map +1 -0
  288. package/dist/tests/unit/logger.test.js +281 -0
  289. package/dist/tests/unit/logger.test.js.map +1 -0
  290. package/dist/tests/validate.test.d.ts +5 -0
  291. package/dist/tests/validate.test.d.ts.map +1 -0
  292. package/dist/tests/validate.test.js +303 -0
  293. package/dist/tests/validate.test.js.map +1 -0
  294. package/dist/tests/webhooks/proxy-trust.security.test.d.ts +8 -0
  295. package/dist/tests/webhooks/proxy-trust.security.test.d.ts.map +1 -0
  296. package/dist/tests/webhooks/proxy-trust.security.test.js +145 -0
  297. package/dist/tests/webhooks/proxy-trust.security.test.js.map +1 -0
  298. package/dist/tests/webhooks/rate-limiter.security.test.d.ts +8 -0
  299. package/dist/tests/webhooks/rate-limiter.security.test.d.ts.map +1 -0
  300. package/dist/tests/webhooks/rate-limiter.security.test.js +122 -0
  301. package/dist/tests/webhooks/rate-limiter.security.test.js.map +1 -0
  302. package/dist/vitest.config.d.ts +6 -0
  303. package/dist/vitest.config.d.ts.map +1 -0
  304. package/dist/vitest.config.js +13 -0
  305. package/dist/vitest.config.js.map +1 -0
  306. package/package.json +63 -0
@@ -0,0 +1,325 @@
1
+ /**
2
+ * @fileoverview MCP Skill Recommend Tool for suggesting relevant skills
3
+ * @module @skillsmith/mcp-server/tools/recommend
4
+ * @see SMI-741: Add MCP Tool skill_recommend
5
+ * @see SMI-602: Integrate semantic matching with EmbeddingService
6
+ * @see SMI-604: Add trigger phrase overlap detection
7
+ *
8
+ * Provides skill recommendations based on:
9
+ * - Currently installed skills (semantic similarity)
10
+ * - Optional project context (semantic matching)
11
+ * - Codebase analysis (framework detection)
12
+ * - Overlap detection (avoid similar skills)
13
+ *
14
+ * @example
15
+ * // Basic recommendation
16
+ * const results = await executeRecommend({
17
+ * installed_skills: ['anthropic/commit'],
18
+ * limit: 5
19
+ * }, toolContext);
20
+ *
21
+ * @example
22
+ * // Recommendation with project context
23
+ * const results = await executeRecommend({
24
+ * installed_skills: ['anthropic/commit'],
25
+ * project_context: 'React frontend with Jest testing',
26
+ * limit: 10
27
+ * }, toolContext);
28
+ */
29
+ import { z } from 'zod';
30
+ import { SkillMatcher, OverlapDetector } from '@skillsmith/core';
31
+ import { getInstalledSkills } from '../utils/installed-skills.js';
32
+ /**
33
+ * Zod schema for recommend tool input validation
34
+ */
35
+ export const recommendInputSchema = z.object({
36
+ /** Currently installed skill IDs */
37
+ installed_skills: z.array(z.string()).min(0).default([]),
38
+ /** Optional project description for context-aware recommendations */
39
+ project_context: z.string().optional(),
40
+ /** Maximum recommendations to return (default 5) */
41
+ limit: z.number().min(1).max(50).default(5),
42
+ /** Enable overlap detection (default true) */
43
+ detect_overlap: z.boolean().default(true),
44
+ /** Minimum similarity threshold (0-1, default 0.3) */
45
+ min_similarity: z.number().min(0).max(1).default(0.3),
46
+ });
47
+ /**
48
+ * MCP tool schema definition for skill_recommend
49
+ */
50
+ export const recommendToolSchema = {
51
+ name: 'skill_recommend',
52
+ description: 'Recommend skills based on currently installed skills and optional project context. Uses semantic similarity to find relevant skills. Auto-detects installed skills from ~/.claude/skills/ if not provided.',
53
+ inputSchema: {
54
+ type: 'object',
55
+ properties: {
56
+ installed_skills: {
57
+ type: 'array',
58
+ items: { type: 'string' },
59
+ description: 'Currently installed skill IDs (e.g., ["anthropic/commit", "community/jest-helper"]). If empty, auto-detects from ~/.claude/skills/',
60
+ },
61
+ project_context: {
62
+ type: 'string',
63
+ description: 'Optional project description for context-aware recommendations (e.g., "React frontend with Jest testing")',
64
+ },
65
+ limit: {
66
+ type: 'number',
67
+ description: 'Maximum recommendations to return (default 5, max 50)',
68
+ minimum: 1,
69
+ maximum: 50,
70
+ default: 5,
71
+ },
72
+ detect_overlap: {
73
+ type: 'boolean',
74
+ description: 'Enable overlap detection to filter similar skills (default true)',
75
+ default: true,
76
+ },
77
+ min_similarity: {
78
+ type: 'number',
79
+ description: 'Minimum similarity threshold (0-1, default 0.3)',
80
+ minimum: 0,
81
+ maximum: 1,
82
+ default: 0.3,
83
+ },
84
+ },
85
+ required: [],
86
+ },
87
+ };
88
+ /**
89
+ * Map database trust tier to MCP trust tier
90
+ */
91
+ function mapTrustTierFromDb(dbTier) {
92
+ switch (dbTier) {
93
+ case 'verified':
94
+ return 'verified';
95
+ case 'community':
96
+ return 'community';
97
+ case 'experimental':
98
+ return 'standard';
99
+ case 'unknown':
100
+ default:
101
+ return 'unverified';
102
+ }
103
+ }
104
+ /**
105
+ * Transform a database skill to SkillData format for matching
106
+ */
107
+ function transformSkillToMatchData(skill) {
108
+ // Generate trigger phrases from name and first few tags
109
+ const triggerPhrases = [
110
+ skill.name,
111
+ `use ${skill.name}`,
112
+ `${skill.name} help`,
113
+ ...skill.tags.slice(0, 3).map((tag) => `${tag} ${skill.name}`),
114
+ ];
115
+ return {
116
+ id: skill.id,
117
+ name: skill.name,
118
+ description: skill.description || '',
119
+ triggerPhrases,
120
+ keywords: skill.tags,
121
+ qualityScore: Math.round((skill.qualityScore ?? 0.5) * 100),
122
+ trustTier: mapTrustTierFromDb(skill.trustTier),
123
+ };
124
+ }
125
+ /**
126
+ * Load skills from database via ToolContext
127
+ * Returns skills transformed to SkillData format for matching
128
+ */
129
+ async function loadSkillsFromDatabase(context, limit = 500) {
130
+ const result = context.skillRepository.findAll(limit, 0);
131
+ return result.items.map(transformSkillToMatchData);
132
+ }
133
+ /**
134
+ * Execute skill recommendation based on installed skills and context.
135
+ *
136
+ * Uses semantic similarity to find skills that complement the user's
137
+ * current installation. When project context is provided, it's used
138
+ * to improve recommendation relevance. Overlap detection prevents
139
+ * recommending skills that are too similar to installed ones.
140
+ *
141
+ * @param input - Recommendation parameters
142
+ * @returns Promise resolving to recommendation response
143
+ * @throws {SkillsmithError} When validation fails
144
+ *
145
+ * @example
146
+ * const response = await executeRecommend({
147
+ * installed_skills: ['anthropic/commit'],
148
+ * project_context: 'React TypeScript frontend',
149
+ * limit: 5
150
+ * }, toolContext);
151
+ * console.log(response.recommendations[0].reason);
152
+ */
153
+ export async function executeRecommend(input, context) {
154
+ const startTime = performance.now();
155
+ // Validate input with Zod
156
+ const validated = recommendInputSchema.parse(input);
157
+ let { installed_skills } = validated;
158
+ const { project_context, limit, detect_overlap, min_similarity } = validated;
159
+ // SMI-906: Auto-detect installed skills from ~/.claude/skills/ if not provided
160
+ const autoDetected = installed_skills.length === 0;
161
+ if (autoDetected) {
162
+ installed_skills = await getInstalledSkills();
163
+ }
164
+ // Load skills from database (limit to reasonable number for performance)
165
+ // Use 500 as default to balance coverage vs performance
166
+ const skillDatabase = await loadSkillsFromDatabase(context, 500);
167
+ // Initialize matcher with fallback mode for now (real embeddings in production)
168
+ const matcher = new SkillMatcher({
169
+ useFallback: true, // Use mock embeddings for consistent behavior
170
+ minSimilarity: min_similarity,
171
+ qualityWeight: 0.3,
172
+ });
173
+ // Get installed skill data
174
+ const installedSkillData = skillDatabase.filter((s) => installed_skills.some((id) => id.toLowerCase() === s.id.toLowerCase()));
175
+ // SMI-907: Extract installed skill names for name-based overlap detection
176
+ // This filters skills with semantically similar names (e.g., "docker" filters "docker-compose")
177
+ const installedNames = installed_skills.map((id) => {
178
+ // Extract the skill name from the ID (e.g., "community/docker" -> "docker")
179
+ const idName = id.split('/').pop()?.toLowerCase() || '';
180
+ // Also check if any installed skill data has a matching name
181
+ const skillData = installedSkillData.find((s) => s.id.toLowerCase() === id.toLowerCase());
182
+ return {
183
+ idName,
184
+ skillName: skillData?.name.toLowerCase() || idName,
185
+ };
186
+ });
187
+ // Filter out already installed skills AND semantically similar names from candidates
188
+ const candidates = skillDatabase.filter((s) => {
189
+ const skillName = s.name.toLowerCase();
190
+ const skillIdName = s.id.split('/').pop()?.toLowerCase() || '';
191
+ // Exclude if exact ID match (case-insensitive)
192
+ if (installed_skills.some((id) => id.toLowerCase() === s.id.toLowerCase())) {
193
+ return false;
194
+ }
195
+ // SMI-907: Exclude if name is contained in or contains installed skill name
196
+ // This prevents recommending "docker-compose" when "docker" is installed
197
+ for (const installed of installedNames) {
198
+ const { idName, skillName: installedSkillName } = installed;
199
+ if (!idName && !installedSkillName)
200
+ continue;
201
+ // Check name containment both ways
202
+ if ((installedSkillName && skillName.includes(installedSkillName)) ||
203
+ (installedSkillName && installedSkillName.includes(skillName)) ||
204
+ (idName && skillIdName.includes(idName)) ||
205
+ (idName && idName.includes(skillIdName))) {
206
+ return false;
207
+ }
208
+ }
209
+ return true;
210
+ });
211
+ let overlapFiltered = 0;
212
+ // Apply overlap detection if enabled and there are installed skills
213
+ let filteredCandidates = candidates;
214
+ if (detect_overlap && installedSkillData.length > 0) {
215
+ const overlapDetector = new OverlapDetector({
216
+ useFallback: true,
217
+ overlapThreshold: 0.6,
218
+ phraseThreshold: 0.75,
219
+ });
220
+ const filterResult = await overlapDetector.filterByOverlap(candidates, installedSkillData);
221
+ filteredCandidates = filterResult.accepted;
222
+ overlapFiltered = filterResult.rejected.length;
223
+ overlapDetector.close();
224
+ }
225
+ // Build query from installed skills and project context
226
+ let query = '';
227
+ if (installedSkillData.length > 0) {
228
+ query = installedSkillData
229
+ .map((s) => `${s.name} ${s.description} ${s.keywords?.join(' ') || ''}`)
230
+ .join(' ');
231
+ }
232
+ if (project_context) {
233
+ query = query ? `${query} ${project_context}` : project_context;
234
+ }
235
+ if (!query) {
236
+ query = 'general development productivity tools';
237
+ }
238
+ // Find similar skills using semantic matching
239
+ const matchResults = await matcher.findSimilarSkills(query, filteredCandidates, limit);
240
+ // Transform to response format
241
+ const recommendations = matchResults.map((result) => {
242
+ const skill = result.skill;
243
+ return {
244
+ skill_id: skill.id,
245
+ name: skill.name,
246
+ reason: result.matchReason,
247
+ similarity_score: result.similarityScore,
248
+ trust_tier: skill.trustTier,
249
+ quality_score: skill.qualityScore ?? 50,
250
+ };
251
+ });
252
+ const endTime = performance.now();
253
+ matcher.close();
254
+ return {
255
+ recommendations,
256
+ candidates_considered: candidates.length,
257
+ overlap_filtered: overlapFiltered,
258
+ context: {
259
+ installed_count: installed_skills.length,
260
+ has_project_context: !!project_context,
261
+ using_semantic_matching: true,
262
+ auto_detected: autoDetected,
263
+ },
264
+ timing: {
265
+ totalMs: Math.round(endTime - startTime),
266
+ },
267
+ };
268
+ }
269
+ /**
270
+ * Format recommendations for terminal display
271
+ */
272
+ export function formatRecommendations(response) {
273
+ const lines = [];
274
+ lines.push('\n=== Skill Recommendations ===\n');
275
+ if (response.recommendations.length === 0) {
276
+ lines.push('No recommendations found.');
277
+ lines.push('');
278
+ lines.push('Suggestions:');
279
+ lines.push(' - Try adding more installed skills for better matching');
280
+ lines.push(' - Provide a project context for more relevant results');
281
+ }
282
+ else {
283
+ lines.push(`Found ${response.recommendations.length} recommendation(s):\n`);
284
+ response.recommendations.forEach((rec, index) => {
285
+ const trustBadge = getTrustBadge(rec.trust_tier);
286
+ lines.push(`${index + 1}. ${rec.name} ${trustBadge}`);
287
+ lines.push(` Score: ${rec.quality_score}/100 | Relevance: ${Math.round(rec.similarity_score * 100)}%`);
288
+ lines.push(` ${rec.reason}`);
289
+ lines.push(` ID: ${rec.skill_id}`);
290
+ lines.push('');
291
+ });
292
+ }
293
+ lines.push('---');
294
+ lines.push(`Candidates considered: ${response.candidates_considered}`);
295
+ if (response.overlap_filtered > 0) {
296
+ lines.push(`Filtered for overlap: ${response.overlap_filtered}`);
297
+ }
298
+ if (response.context.auto_detected) {
299
+ lines.push(`Installed skills: ${response.context.installed_count} (auto-detected from ~/.claude/skills/)`);
300
+ }
301
+ else {
302
+ lines.push(`Installed skills: ${response.context.installed_count}`);
303
+ }
304
+ lines.push(`Semantic matching: ${response.context.using_semantic_matching ? 'enabled' : 'disabled'}`);
305
+ lines.push(`Completed in ${response.timing.totalMs}ms`);
306
+ return lines.join('\n');
307
+ }
308
+ /**
309
+ * Get trust badge for display
310
+ */
311
+ function getTrustBadge(tier) {
312
+ switch (tier) {
313
+ case 'verified':
314
+ return '[VERIFIED]';
315
+ case 'community':
316
+ return '[COMMUNITY]';
317
+ case 'standard':
318
+ return '[STANDARD]';
319
+ case 'unverified':
320
+ return '[UNVERIFIED]';
321
+ default:
322
+ return '[UNKNOWN]';
323
+ }
324
+ }
325
+ //# sourceMappingURL=recommend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recommend.js","sourceRoot":"","sources":["../../../src/tools/recommend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * @fileoverview MCP Search Tool for Claude Code skill discovery
3
+ * @module @skillsmith/mcp-server/tools/search
4
+ * @see {@link https://github.com/wrsmith108/skillsmith|Skillsmith Repository}
5
+ * @see SMI-789: Wire search tool to SearchService
6
+ *
7
+ * Provides skill search functionality with support for:
8
+ * - Full-text search across skill names, descriptions, and authors
9
+ * - Category filtering (development, testing, devops, etc.)
10
+ * - Trust tier filtering (verified, community, standard, unverified)
11
+ * - Minimum quality score filtering
12
+ *
13
+ * @example
14
+ * // Basic search with context
15
+ * const results = await executeSearch({ query: 'commit' }, context);
16
+ *
17
+ * @example
18
+ * // Search with filters
19
+ * const results = await executeSearch({
20
+ * query: 'test',
21
+ * category: 'testing',
22
+ * trust_tier: 'verified',
23
+ * min_score: 80
24
+ * }, context);
25
+ */
26
+ import { type MCPSearchResponse as SearchResponse } from '@skillsmith/core';
27
+ import type { ToolContext } from '../context.js';
28
+ /**
29
+ * Search tool schema for MCP
30
+ */
31
+ export declare const searchToolSchema: {
32
+ name: string;
33
+ description: string;
34
+ inputSchema: {
35
+ type: "object";
36
+ properties: {
37
+ query: {
38
+ type: string;
39
+ description: string;
40
+ };
41
+ category: {
42
+ type: string;
43
+ description: string;
44
+ enum: string[];
45
+ };
46
+ trust_tier: {
47
+ type: string;
48
+ description: string;
49
+ enum: string[];
50
+ };
51
+ min_score: {
52
+ type: string;
53
+ description: string;
54
+ minimum: number;
55
+ maximum: number;
56
+ };
57
+ };
58
+ required: string[];
59
+ };
60
+ };
61
+ /**
62
+ * Input parameters for the search operation
63
+ * @interface SearchInput
64
+ */
65
+ export interface SearchInput {
66
+ /** Search query string (minimum 2 characters) */
67
+ query: string;
68
+ /** Filter by skill category */
69
+ category?: string;
70
+ /** Filter by trust tier level */
71
+ trust_tier?: string;
72
+ /** Minimum quality score (0-100) */
73
+ min_score?: number;
74
+ }
75
+ /**
76
+ * Execute a search for Claude Code skills with optional filters.
77
+ *
78
+ * Uses SearchService with FTS5/BM25 ranking for relevance-based results.
79
+ * Results are sorted by BM25 rank and limited to specified count.
80
+ *
81
+ * @param input - Search parameters including query and optional filters
82
+ * @param context - Tool context with database and services
83
+ * @returns Promise resolving to search response with results and timing
84
+ * @throws {SkillsmithError} When query is empty or less than 2 characters
85
+ * @throws {SkillsmithError} When min_score is outside 0-100 range
86
+ *
87
+ * @example
88
+ * // Search for commit-related skills
89
+ * const response = await executeSearch({ query: 'commit' }, context);
90
+ * console.log(`Found ${response.total} skills in ${response.timing.totalMs}ms`);
91
+ *
92
+ * @example
93
+ * // Search with multiple filters
94
+ * const response = await executeSearch({
95
+ * query: 'react',
96
+ * category: 'testing',
97
+ * min_score: 85
98
+ * }, context);
99
+ */
100
+ export declare function executeSearch(input: SearchInput, context: ToolContext): Promise<SearchResponse>;
101
+ /**
102
+ * Format search results for terminal/CLI display.
103
+ *
104
+ * Produces a human-readable string with skill listings including
105
+ * trust badges, scores, and timing information.
106
+ *
107
+ * @param response - Search response from executeSearch
108
+ * @returns Formatted string suitable for terminal output
109
+ *
110
+ * @example
111
+ * const response = await executeSearch({ query: 'test' });
112
+ * console.log(formatSearchResults(response));
113
+ * // Output:
114
+ * // === Search Results for "test" ===
115
+ * // Found 3 skill(s):
116
+ * // 1. jest-helper [COMMUNITY]
117
+ * // Author: community | Score: 87/100
118
+ * // Generate Jest test cases...
119
+ */
120
+ export declare function formatSearchResults(response: SearchResponse): string;
121
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/tools/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAGL,KAAK,iBAAiB,IAAI,cAAc,EAMzC,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAqChD;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwC5B,CAAA;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAA;IACb,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC,CA2EzB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAgCpE"}