feat: implement MCP registry client with multi-source search

Add registry client that queries Official, Glama, and Smithery MCP
registries with caching, request deduplication, retry logic, and
result ranking/dedup. Includes 53 tests covering all components.

Also fix null priority values in cancelled tasks (19-21) that broke
Task Master, and add new tasks 25-27 for registry completion and
CLI discover/install commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Michal
2026-02-21 03:46:14 +00:00
parent d0aa0c5d63
commit 386029d052
16 changed files with 1304 additions and 147 deletions

173
pnpm-lock.yaml generated
View File

@@ -8,6 +8,9 @@ importers:
.:
devDependencies:
'@types/node':
specifier: ^25.3.0
version: 25.3.0
'@typescript-eslint/eslint-plugin':
specifier: ^8.56.0
version: 8.56.0(@typescript-eslint/parser@8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3)
@@ -16,7 +19,7 @@ importers:
version: 8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3)
'@vitest/coverage-v8':
specifier: ^4.0.18
version: 4.0.18(vitest@4.0.18(jiti@2.6.1)(tsx@4.21.0))
version: 4.0.18(vitest@4.0.18(@types/node@25.3.0)(jiti@2.6.1)(tsx@4.21.0))
eslint:
specifier: ^10.0.1
version: 10.0.1(jiti@2.6.1)
@@ -34,7 +37,7 @@ importers:
version: 5.9.3
vitest:
specifier: ^4.0.18
version: 4.0.18(jiti@2.6.1)(tsx@4.21.0)
version: 4.0.18(@types/node@25.3.0)(jiti@2.6.1)(tsx@4.21.0)
src/cli:
dependencies:
@@ -52,10 +55,13 @@ importers:
version: 13.1.0
inquirer:
specifier: ^12.0.0
version: 12.11.1
version: 12.11.1(@types/node@25.3.0)
js-yaml:
specifier: ^4.1.0
version: 4.1.1
zod:
specifier: ^3.24.0
version: 3.25.76
src/db:
dependencies:
@@ -701,6 +707,9 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
'@types/node@25.3.0':
resolution: {integrity: sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==}
'@typescript-eslint/eslint-plugin@8.56.0':
resolution: {integrity: sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1795,6 +1804,9 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
undici-types@7.18.2:
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
unpipe@1.0.0:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'}
@@ -2098,100 +2110,128 @@ snapshots:
'@inquirer/ansi@1.0.2': {}
'@inquirer/checkbox@4.3.2':
'@inquirer/checkbox@4.3.2(@types/node@25.3.0)':
dependencies:
'@inquirer/ansi': 1.0.2
'@inquirer/core': 10.3.2
'@inquirer/core': 10.3.2(@types/node@25.3.0)
'@inquirer/figures': 1.0.15
'@inquirer/type': 3.0.10
'@inquirer/type': 3.0.10(@types/node@25.3.0)
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 25.3.0
'@inquirer/confirm@5.1.21':
'@inquirer/confirm@5.1.21(@types/node@25.3.0)':
dependencies:
'@inquirer/core': 10.3.2
'@inquirer/type': 3.0.10
'@inquirer/core': 10.3.2(@types/node@25.3.0)
'@inquirer/type': 3.0.10(@types/node@25.3.0)
optionalDependencies:
'@types/node': 25.3.0
'@inquirer/core@10.3.2':
'@inquirer/core@10.3.2(@types/node@25.3.0)':
dependencies:
'@inquirer/ansi': 1.0.2
'@inquirer/figures': 1.0.15
'@inquirer/type': 3.0.10
'@inquirer/type': 3.0.10(@types/node@25.3.0)
cli-width: 4.1.0
mute-stream: 2.0.0
signal-exit: 4.1.0
wrap-ansi: 6.2.0
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 25.3.0
'@inquirer/editor@4.2.23':
'@inquirer/editor@4.2.23(@types/node@25.3.0)':
dependencies:
'@inquirer/core': 10.3.2
'@inquirer/external-editor': 1.0.3
'@inquirer/type': 3.0.10
'@inquirer/core': 10.3.2(@types/node@25.3.0)
'@inquirer/external-editor': 1.0.3(@types/node@25.3.0)
'@inquirer/type': 3.0.10(@types/node@25.3.0)
optionalDependencies:
'@types/node': 25.3.0
'@inquirer/expand@4.0.23':
'@inquirer/expand@4.0.23(@types/node@25.3.0)':
dependencies:
'@inquirer/core': 10.3.2
'@inquirer/type': 3.0.10
'@inquirer/core': 10.3.2(@types/node@25.3.0)
'@inquirer/type': 3.0.10(@types/node@25.3.0)
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 25.3.0
'@inquirer/external-editor@1.0.3':
'@inquirer/external-editor@1.0.3(@types/node@25.3.0)':
dependencies:
chardet: 2.1.1
iconv-lite: 0.7.2
optionalDependencies:
'@types/node': 25.3.0
'@inquirer/figures@1.0.15': {}
'@inquirer/input@4.3.1':
'@inquirer/input@4.3.1(@types/node@25.3.0)':
dependencies:
'@inquirer/core': 10.3.2
'@inquirer/type': 3.0.10
'@inquirer/core': 10.3.2(@types/node@25.3.0)
'@inquirer/type': 3.0.10(@types/node@25.3.0)
optionalDependencies:
'@types/node': 25.3.0
'@inquirer/number@3.0.23':
'@inquirer/number@3.0.23(@types/node@25.3.0)':
dependencies:
'@inquirer/core': 10.3.2
'@inquirer/type': 3.0.10
'@inquirer/core': 10.3.2(@types/node@25.3.0)
'@inquirer/type': 3.0.10(@types/node@25.3.0)
optionalDependencies:
'@types/node': 25.3.0
'@inquirer/password@4.0.23':
'@inquirer/password@4.0.23(@types/node@25.3.0)':
dependencies:
'@inquirer/ansi': 1.0.2
'@inquirer/core': 10.3.2
'@inquirer/type': 3.0.10
'@inquirer/core': 10.3.2(@types/node@25.3.0)
'@inquirer/type': 3.0.10(@types/node@25.3.0)
optionalDependencies:
'@types/node': 25.3.0
'@inquirer/prompts@7.10.1':
'@inquirer/prompts@7.10.1(@types/node@25.3.0)':
dependencies:
'@inquirer/checkbox': 4.3.2
'@inquirer/confirm': 5.1.21
'@inquirer/editor': 4.2.23
'@inquirer/expand': 4.0.23
'@inquirer/input': 4.3.1
'@inquirer/number': 3.0.23
'@inquirer/password': 4.0.23
'@inquirer/rawlist': 4.1.11
'@inquirer/search': 3.2.2
'@inquirer/select': 4.4.2
'@inquirer/checkbox': 4.3.2(@types/node@25.3.0)
'@inquirer/confirm': 5.1.21(@types/node@25.3.0)
'@inquirer/editor': 4.2.23(@types/node@25.3.0)
'@inquirer/expand': 4.0.23(@types/node@25.3.0)
'@inquirer/input': 4.3.1(@types/node@25.3.0)
'@inquirer/number': 3.0.23(@types/node@25.3.0)
'@inquirer/password': 4.0.23(@types/node@25.3.0)
'@inquirer/rawlist': 4.1.11(@types/node@25.3.0)
'@inquirer/search': 3.2.2(@types/node@25.3.0)
'@inquirer/select': 4.4.2(@types/node@25.3.0)
optionalDependencies:
'@types/node': 25.3.0
'@inquirer/rawlist@4.1.11':
'@inquirer/rawlist@4.1.11(@types/node@25.3.0)':
dependencies:
'@inquirer/core': 10.3.2
'@inquirer/type': 3.0.10
'@inquirer/core': 10.3.2(@types/node@25.3.0)
'@inquirer/type': 3.0.10(@types/node@25.3.0)
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 25.3.0
'@inquirer/search@3.2.2':
'@inquirer/search@3.2.2(@types/node@25.3.0)':
dependencies:
'@inquirer/core': 10.3.2
'@inquirer/core': 10.3.2(@types/node@25.3.0)
'@inquirer/figures': 1.0.15
'@inquirer/type': 3.0.10
'@inquirer/type': 3.0.10(@types/node@25.3.0)
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 25.3.0
'@inquirer/select@4.4.2':
'@inquirer/select@4.4.2(@types/node@25.3.0)':
dependencies:
'@inquirer/ansi': 1.0.2
'@inquirer/core': 10.3.2
'@inquirer/core': 10.3.2(@types/node@25.3.0)
'@inquirer/figures': 1.0.15
'@inquirer/type': 3.0.10
'@inquirer/type': 3.0.10(@types/node@25.3.0)
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 25.3.0
'@inquirer/type@3.0.10': {}
'@inquirer/type@3.0.10(@types/node@25.3.0)':
optionalDependencies:
'@types/node': 25.3.0
'@jridgewell/resolve-uri@3.1.2': {}
@@ -2353,6 +2393,10 @@ snapshots:
'@types/json-schema@7.0.15': {}
'@types/node@25.3.0':
dependencies:
undici-types: 7.18.2
'@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
@@ -2444,7 +2488,7 @@ snapshots:
'@typescript-eslint/types': 8.56.0
eslint-visitor-keys: 5.0.1
'@vitest/coverage-v8@4.0.18(vitest@4.0.18(jiti@2.6.1)(tsx@4.21.0))':
'@vitest/coverage-v8@4.0.18(vitest@4.0.18(@types/node@25.3.0)(jiti@2.6.1)(tsx@4.21.0))':
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@vitest/utils': 4.0.18
@@ -2456,7 +2500,7 @@ snapshots:
obug: 2.1.1
std-env: 3.10.0
tinyrainbow: 3.0.3
vitest: 4.0.18(jiti@2.6.1)(tsx@4.21.0)
vitest: 4.0.18(@types/node@25.3.0)(jiti@2.6.1)(tsx@4.21.0)
'@vitest/expect@4.0.18':
dependencies:
@@ -2467,13 +2511,13 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.0.3
'@vitest/mocker@4.0.18(vite@7.3.1(jiti@2.6.1)(tsx@4.21.0))':
'@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.3.0)(jiti@2.6.1)(tsx@4.21.0))':
dependencies:
'@vitest/spy': 4.0.18
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 7.3.1(jiti@2.6.1)(tsx@4.21.0)
vite: 7.3.1(@types/node@25.3.0)(jiti@2.6.1)(tsx@4.21.0)
'@vitest/pretty-format@4.0.18':
dependencies:
@@ -3033,15 +3077,17 @@ snapshots:
inherits@2.0.4: {}
inquirer@12.11.1:
inquirer@12.11.1(@types/node@25.3.0):
dependencies:
'@inquirer/ansi': 1.0.2
'@inquirer/core': 10.3.2
'@inquirer/prompts': 7.10.1
'@inquirer/type': 3.0.10
'@inquirer/core': 10.3.2(@types/node@25.3.0)
'@inquirer/prompts': 7.10.1(@types/node@25.3.0)
'@inquirer/type': 3.0.10(@types/node@25.3.0)
mute-stream: 2.0.0
run-async: 4.0.6
rxjs: 7.8.2
optionalDependencies:
'@types/node': 25.3.0
ip-address@10.0.1: {}
@@ -3532,6 +3578,8 @@ snapshots:
typescript@5.9.3: {}
undici-types@7.18.2: {}
unpipe@1.0.0: {}
uri-js@4.4.1:
@@ -3540,7 +3588,7 @@ snapshots:
vary@1.1.2: {}
vite@7.3.1(jiti@2.6.1)(tsx@4.21.0):
vite@7.3.1(@types/node@25.3.0)(jiti@2.6.1)(tsx@4.21.0):
dependencies:
esbuild: 0.27.3
fdir: 6.5.0(picomatch@4.0.3)
@@ -3549,14 +3597,15 @@ snapshots:
rollup: 4.58.0
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 25.3.0
fsevents: 2.3.3
jiti: 2.6.1
tsx: 4.21.0
vitest@4.0.18(jiti@2.6.1)(tsx@4.21.0):
vitest@4.0.18(@types/node@25.3.0)(jiti@2.6.1)(tsx@4.21.0):
dependencies:
'@vitest/expect': 4.0.18
'@vitest/mocker': 4.0.18(vite@7.3.1(jiti@2.6.1)(tsx@4.21.0))
'@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.3.0)(jiti@2.6.1)(tsx@4.21.0))
'@vitest/pretty-format': 4.0.18
'@vitest/runner': 4.0.18
'@vitest/snapshot': 4.0.18
@@ -3573,8 +3622,10 @@ snapshots:
tinyexec: 1.0.2
tinyglobby: 0.2.15
tinyrainbow: 3.0.3
vite: 7.3.1(jiti@2.6.1)(tsx@4.21.0)
vite: 7.3.1(@types/node@25.3.0)(jiti@2.6.1)(tsx@4.21.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 25.3.0
transitivePeerDependencies:
- jiti
- less