@theia/ai-registry 1.73.0-next.10

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 (78) hide show
  1. package/README.md +40 -0
  2. package/lib/browser/ai-registry-frontend-module.d.ts +5 -0
  3. package/lib/browser/ai-registry-frontend-module.d.ts.map +1 -0
  4. package/lib/browser/ai-registry-frontend-module.js +45 -0
  5. package/lib/browser/ai-registry-frontend-module.js.map +1 -0
  6. package/lib/browser/ai-registry-toolbar-contribution.d.ts +9 -0
  7. package/lib/browser/ai-registry-toolbar-contribution.d.ts.map +1 -0
  8. package/lib/browser/ai-registry-toolbar-contribution.js +53 -0
  9. package/lib/browser/ai-registry-toolbar-contribution.js.map +1 -0
  10. package/lib/browser/mcp/mcp-entries.d.ts +40 -0
  11. package/lib/browser/mcp/mcp-entries.d.ts.map +1 -0
  12. package/lib/browser/mcp/mcp-entries.js +143 -0
  13. package/lib/browser/mcp/mcp-entries.js.map +1 -0
  14. package/lib/browser/mcp/mcp-extensions-contribution.d.ts +45 -0
  15. package/lib/browser/mcp/mcp-extensions-contribution.d.ts.map +1 -0
  16. package/lib/browser/mcp/mcp-extensions-contribution.js +198 -0
  17. package/lib/browser/mcp/mcp-extensions-contribution.js.map +1 -0
  18. package/lib/browser/mcp/mcp-extensions-contribution.spec.d.ts +2 -0
  19. package/lib/browser/mcp/mcp-extensions-contribution.spec.d.ts.map +1 -0
  20. package/lib/browser/mcp/mcp-extensions-contribution.spec.js +266 -0
  21. package/lib/browser/mcp/mcp-extensions-contribution.spec.js.map +1 -0
  22. package/lib/browser/mcp/mcp-install-service.d.ts +72 -0
  23. package/lib/browser/mcp/mcp-install-service.d.ts.map +1 -0
  24. package/lib/browser/mcp/mcp-install-service.js +255 -0
  25. package/lib/browser/mcp/mcp-install-service.js.map +1 -0
  26. package/lib/browser/mcp/mcp-install-service.spec.d.ts +2 -0
  27. package/lib/browser/mcp/mcp-install-service.spec.d.ts.map +1 -0
  28. package/lib/browser/mcp/mcp-install-service.spec.js +604 -0
  29. package/lib/browser/mcp/mcp-install-service.spec.js.map +1 -0
  30. package/lib/browser/mcp/mcp-registry-ui-bridge-impl.d.ts +27 -0
  31. package/lib/browser/mcp/mcp-registry-ui-bridge-impl.d.ts.map +1 -0
  32. package/lib/browser/mcp/mcp-registry-ui-bridge-impl.js +136 -0
  33. package/lib/browser/mcp/mcp-registry-ui-bridge-impl.js.map +1 -0
  34. package/lib/common/ai-registry-configuration.d.ts +28 -0
  35. package/lib/common/ai-registry-configuration.d.ts.map +1 -0
  36. package/lib/common/ai-registry-configuration.js +56 -0
  37. package/lib/common/ai-registry-configuration.js.map +1 -0
  38. package/lib/common/mcp/mcp-registry-entry-resolver.d.ts +12 -0
  39. package/lib/common/mcp/mcp-registry-entry-resolver.d.ts.map +1 -0
  40. package/lib/common/mcp/mcp-registry-entry-resolver.js +68 -0
  41. package/lib/common/mcp/mcp-registry-entry-resolver.js.map +1 -0
  42. package/lib/common/mcp/mcp-registry-entry-resolver.spec.d.ts +2 -0
  43. package/lib/common/mcp/mcp-registry-entry-resolver.spec.d.ts.map +1 -0
  44. package/lib/common/mcp/mcp-registry-entry-resolver.spec.js +230 -0
  45. package/lib/common/mcp/mcp-registry-entry-resolver.spec.js.map +1 -0
  46. package/lib/common/mcp/mcp-registry-types.d.ts +105 -0
  47. package/lib/common/mcp/mcp-registry-types.d.ts.map +1 -0
  48. package/lib/common/mcp/mcp-registry-types.js +18 -0
  49. package/lib/common/mcp/mcp-registry-types.js.map +1 -0
  50. package/lib/common/registry-fetch-service.d.ts +24 -0
  51. package/lib/common/registry-fetch-service.d.ts.map +1 -0
  52. package/lib/common/registry-fetch-service.js +72 -0
  53. package/lib/common/registry-fetch-service.js.map +1 -0
  54. package/lib/common/registry-fetch-service.spec.d.ts +2 -0
  55. package/lib/common/registry-fetch-service.spec.d.ts.map +1 -0
  56. package/lib/common/registry-fetch-service.spec.js +129 -0
  57. package/lib/common/registry-fetch-service.spec.js.map +1 -0
  58. package/lib/package.spec.d.ts +1 -0
  59. package/lib/package.spec.d.ts.map +1 -0
  60. package/lib/package.spec.js +26 -0
  61. package/lib/package.spec.js.map +1 -0
  62. package/package.json +50 -0
  63. package/src/browser/ai-registry-frontend-module.ts +48 -0
  64. package/src/browser/ai-registry-toolbar-contribution.ts +51 -0
  65. package/src/browser/mcp/mcp-entries.tsx +288 -0
  66. package/src/browser/mcp/mcp-extensions-contribution.spec.ts +294 -0
  67. package/src/browser/mcp/mcp-extensions-contribution.ts +199 -0
  68. package/src/browser/mcp/mcp-install-service.spec.ts +673 -0
  69. package/src/browser/mcp/mcp-install-service.ts +300 -0
  70. package/src/browser/mcp/mcp-registry-ui-bridge-impl.ts +130 -0
  71. package/src/browser/style/mcp-entries.css +56 -0
  72. package/src/common/ai-registry-configuration.ts +52 -0
  73. package/src/common/mcp/mcp-registry-entry-resolver.spec.ts +248 -0
  74. package/src/common/mcp/mcp-registry-entry-resolver.ts +68 -0
  75. package/src/common/mcp/mcp-registry-types.ts +119 -0
  76. package/src/common/registry-fetch-service.spec.ts +136 -0
  77. package/src/common/registry-fetch-service.ts +78 -0
  78. package/src/package.spec.ts +28 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-install-service.js","sourceRoot":"","sources":["../../../src/browser/mcp/mcp-install-service.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;;AAEhF,4DAAkE;AAClE,sCAAiE;AACjE,oFAMqD;AACrD,8EAA4E;AAC5E,mFAAmG;AAYtF,QAAA,iBAAiB,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;AAqBtD,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAQ9B,8HAA8H;IAC9H,KAAK,CAAC,OAAO,CAAC,KAA4B,EAAE,SAA+B;QACvE,MAAM,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,KAA4B;QACxC,gFAAgF;QAChF,kFAAkF;QAClF,iFAAiF;QACjF,kFAAkF;QAClF,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,SAAS,GAAwB,EAAE,CAAC;QAC1C,IAAI,QAAQ,EAAE,SAAS,KAAK,SAAS,EAAE,CAAC;YACpC,SAAS,CAAC,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC;QAC7C,CAAC;QACD,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAA4B;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,OAAO;QACX,CAAC;QACD,mFAAmF;QACnF,iFAAiF;QACjF,MAAM,SAAS,GAAgB,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC/C,IAAI,KAAK,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACvC,OAAO,SAAS,CAAC,OAAO,CAAC;YACzB,OAAO,SAAS,CAAC,IAAI,CAAC;YACtB,OAAO,SAAS,CAAC,GAAG,CAAC;QACzB,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAC5C,OAAO,SAAS,CAAC,SAAS,CAAC;YAC3B,OAAO,SAAS,CAAC,eAAe,CAAC;YACjC,OAAO,SAAS,CAAC,qBAAqB,CAAC;YACvC,OAAO,SAAS,CAAC,OAAO,CAAC;QAC7B,CAAC;QACD,gFAAgF;QAChF,6EAA6E;QAC7E,kFAAkF;QAClF,iFAAiF;QACjF,iFAAiF;QACjF,6EAA6E;QAC7E,gEAAgE;QAChE,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC;YACjD,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE;YACnD,CAAC,CAAC,SAAS,CAAC;QAChB,gFAAgF;QAChF,+EAA+E;QAC/E,+EAA+E;QAC/E,gFAAgF;QAChF,iFAAiF;QACjF,sBAAsB;QACtB,MAAM,aAAa,GAAG,SAAS,CAAC,eAAe,KAAK,SAAS;YACzD,CAAC,CAAC,EAAE,eAAe,EAAE,SAAS,CAAC,eAAe,EAAE;YAChD,CAAC,CAAC,EAAE,CAAC;QACT,MAAM,OAAO,GAAgB;YACzB,GAAG,SAAS;YACZ,GAAG,KAAK,CAAC,MAAM;YACf,GAAG,aAAa;YAChB,GAAG,CAAC,SAAS,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;YACpC,gBAAgB,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;SACzC,CAAC;QACF,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAA4B;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,OAAO;QACX,CAAC;QACD,MAAM,IAAI,CAAC,YAAY,CAAC;YACpB,GAAG,OAAO;YACV,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,QAAQ,EAAE,gBAAgB,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;SAC7E,CAAC,CAAC;IACP,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,IAAY;QACrB,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACvD,OAAO;QACX,CAAC;QACD,MAAM,IAAI,GAAgB,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC1C,OAAO,IAAI,CAAC,gBAAgB,CAAC;QAC7B,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,IAAY;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACnC,IAAI,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,EAAE,CAAC;YACrB,OAAO;QACX,CAAC;QACD,MAAM,IAAI,GAAkB,EAAE,GAAG,OAAO,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAES,WAAW;QACjB,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAgB,kCAAgB,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;IACjF,CAAC;IAES,KAAK,CAAC,YAAY,CAAC,IAAmB;QAC5C,MAAM,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,kCAAgB,EAAE,IAAI,EAAE,sBAAe,CAAC,IAAI,CAAC,CAAC;IACnF,CAAC;IAED,8EAA8E;IACpE,QAAQ,CAAC,KAA4B;QAC3C,OAAO;YACH,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;YAC9D,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC;SAC1E,CAAC;IACN,CAAC;IAED,mBAAmB,CAAC,KAA2B,EAAE,eAAwC;QACrF,MAAM,QAAQ,GAAG,KAAK,CAAC,gBAAgB,EAAE,QAAQ,CAAC;QAClD,IAAI,QAAQ,EAAE,CAAC;YACX,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;YACtE,IAAI,CAAC,UAAU,EAAE,CAAC;gBACd,OAAO,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC;YAC5C,CAAC;YACD,OAAO,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAClD,CAAC;QACD,MAAM,aAAa,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5E,IAAI,CAAC,aAAa,EAAE,CAAC;YACjB,OAAO,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC;QAC5C,CAAC;QACD,oFAAoF;QACpF,4EAA4E;QAC5E,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC;IAC1C,CAAC;IAED,qBAAqB,CACjB,KAA4B,EAC5B,MAA8B,EAC9B,eAAwC;QAExC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;QAC3D,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;QACrC,CAAC;QACD,MAAM,QAAQ,GAAG,KAAK,CAAC,gBAAgB,EAAE,QAAQ,CAAC;QAClD,IAAI,QAAQ,KAAK,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC7C,CAAC;QACD,gFAAgF;QAChF,gFAAgF;QAChF,2EAA2E;QAC3E,IAAI,QAAQ,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,EAAE,CAAC;YAClE,OAAO,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC;QAC5C,CAAC;QACD,iFAAiF;QACjF,sFAAsF;QACtF,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC;IAC1C,CAAC;IAED;;;;;;;;;OASG;IACO,cAAc,CAAC,KAA4B,EAAE,KAA2B;QAC9E,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;YACtC,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;QAClC,CAAC;QACD,MAAM,eAAe,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC7D,OAAO,EAAE,IAAI,EAAE,yBAAyB,EAAE,eAAe,EAAE,CAAC;IAChE,CAAC;IAED;;;;;OAKG;IACO,iBAAiB,CAAC,KAA4B,EAAE,KAA2B;QACjF,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,OAAO,KAAK,CAAC,gBAAgB,EAAE,UAAU,KAAK,KAAK,CAAC,UAAU,CAAC;IACnE,CAAC;IAES,eAAe,CAAC,KAA4B,EAAE,KAA2B;QAC/E,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACrC,IAAI,CAAC,IAAA,gDAA2B,EAAC,KAAK,CAAC,EAAE,CAAC;gBACtC,OAAO,KAAK,CAAC;YACjB,CAAC;YACD,IAAI,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACzC,OAAO,KAAK,CAAC;YACjB,CAAC;YACD,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YAC1C,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;YACnC,IAAI,SAAS,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;gBACxC,OAAO,KAAK,CAAC;YACjB,CAAC;YACD,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBACjE,OAAO,KAAK,CAAC;YACjB,CAAC;YACD,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACvC,IAAI,CAAC,IAAA,iDAA4B,EAAC,KAAK,CAAC,EAAE,CAAC;gBACvC,OAAO,KAAK,CAAC;YACjB,CAAC;YACD,OAAO,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC;QACtD,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAES,UAAU,CAAC,WAA+C,EAAE,QAA4C;QAC9G,IAAI,CAAC,WAAW,EAAE,CAAC;YACf,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YACzC,IAAI,QAAQ,EAAE,CAAC,GAAG,CAAC,KAAK,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvC,OAAO,KAAK,CAAC;YACjB,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ,CAAA;AAhPY,sDAAqB;AAGX;IADlB,IAAA,kBAAM,EAAC,wBAAiB,CAAC;;gEAC8B;AAGrC;IADlB,IAAA,kBAAM,EAAC,mCAAe,CAAC;;qDACmB;gCANlC,qBAAqB;IADjC,IAAA,sBAAU,GAAE;GACA,qBAAqB,CAgPjC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mcp-install-service.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-install-service.spec.d.ts","sourceRoot":"","sources":["../../../src/browser/mcp/mcp-install-service.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,604 @@
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2026 EclipseSource GmbH.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ const chai_1 = require("chai");
19
+ const inversify_1 = require("@theia/core/shared/inversify");
20
+ const core_1 = require("@theia/core");
21
+ const mcp_preferences_1 = require("@theia/ai-mcp/lib/common/mcp-preferences");
22
+ const mcp_server_manager_1 = require("@theia/ai-mcp/lib/common/mcp-server-manager");
23
+ const mcp_server_editor_1 = require("@theia/ai-mcp/lib/browser/mcp-server-editor");
24
+ const mcp_install_service_1 = require("./mcp-install-service");
25
+ class FakePreferenceService {
26
+ constructor() {
27
+ this.store = new Map();
28
+ }
29
+ get(key, defaultValue) {
30
+ return (this.store.has(key) ? this.store.get(key) : defaultValue);
31
+ }
32
+ async set(key, value) {
33
+ this.store.set(key, value);
34
+ }
35
+ snapshot(key) {
36
+ return this.store.get(key);
37
+ }
38
+ }
39
+ describe('MCPInstallService.classifyRegistryEntry', () => {
40
+ const entry = {
41
+ serverId: 'io.github.example/example-mcp',
42
+ name: 'Example',
43
+ description: 'Example MCP server',
44
+ localName: 'example',
45
+ config: { command: 'npx', args: ['-y', 'example-mcp'] },
46
+ version: '^1.0.0',
47
+ configHash: 'hash-v1',
48
+ mcpRegistryVerified: true
49
+ };
50
+ let service;
51
+ beforeEach(() => {
52
+ service = new mcp_install_service_1.MCPInstallServiceImpl();
53
+ });
54
+ it('returns not-installed when no local server matches the registry slug', () => {
55
+ (0, chai_1.expect)(service.classifyRegistryEntry(entry, [], [entry])).to.deep.equal({ kind: 'not-installed' });
56
+ });
57
+ it('returns installed-from-registry with no update when the linked serverId matches and configHash matches', () => {
58
+ const locals = [{
59
+ name: 'example',
60
+ command: 'npx',
61
+ args: ['-y', 'example-mcp'],
62
+ registryMetadata: {
63
+ serverId: entry.serverId,
64
+ version: entry.version,
65
+ configHash: entry.configHash
66
+ }
67
+ }];
68
+ (0, chai_1.expect)(service.classifyRegistryEntry(entry, locals, [entry])).to.deep.equal({ kind: 'installed-from-registry', updateAvailable: false });
69
+ });
70
+ it('returns installed-from-registry with update available when the linked configHash differs from the entry configHash', () => {
71
+ const locals = [{
72
+ name: 'example',
73
+ command: 'npx',
74
+ args: ['-y', 'example-mcp'],
75
+ registryMetadata: {
76
+ serverId: entry.serverId,
77
+ // Display version still matches - update detection must rely on the hash alone.
78
+ version: entry.version,
79
+ configHash: 'hash-v0'
80
+ }
81
+ }];
82
+ (0, chai_1.expect)(service.classifyRegistryEntry(entry, locals, [entry])).to.deep.equal({ kind: 'installed-from-registry', updateAvailable: true });
83
+ });
84
+ it('does not offer an update when the linked version drifts but the configHash still matches - version is display-only', () => {
85
+ const locals = [{
86
+ name: 'example',
87
+ command: 'npx',
88
+ args: ['-y', 'example-mcp'],
89
+ registryMetadata: {
90
+ serverId: entry.serverId,
91
+ // Local version is stale, but the underlying approval hasn't changed.
92
+ version: '^0.9.0',
93
+ configHash: entry.configHash
94
+ }
95
+ }];
96
+ (0, chai_1.expect)(service.classifyRegistryEntry(entry, locals, [entry])).to.deep.equal({ kind: 'installed-from-registry', updateAvailable: false });
97
+ });
98
+ it('does not offer an update when the registry entry has no configHash - keeps older payloads quiet', () => {
99
+ const noHashEntry = { ...entry, configHash: undefined };
100
+ const locals = [{
101
+ name: 'example',
102
+ command: 'npx',
103
+ args: ['-y', 'example-mcp'],
104
+ registryMetadata: {
105
+ serverId: entry.serverId,
106
+ version: entry.version
107
+ }
108
+ }];
109
+ (0, chai_1.expect)(service.classifyRegistryEntry(noHashEntry, locals, [noHashEntry])).to.deep.equal({ kind: 'installed-from-registry', updateAvailable: false });
110
+ });
111
+ it('returns installed-manually when a local stdio server matches name + command + args but has no registryMetadata', () => {
112
+ const locals = [{
113
+ name: 'example',
114
+ command: 'npx',
115
+ args: ['-y', 'example-mcp']
116
+ }];
117
+ (0, chai_1.expect)(service.classifyRegistryEntry(entry, locals, [entry])).to.deep.equal({ kind: 'installed-manually' });
118
+ });
119
+ it('returns installed-manually for a remote entry when a local server matches name + serverUrl but has no registryMetadata', () => {
120
+ const remoteEntry = {
121
+ serverId: 'io.github.example/remote-mcp',
122
+ name: 'Remote Example',
123
+ description: 'Remote MCP server',
124
+ localName: 'remote-example',
125
+ config: { serverUrl: 'https://example.com/mcp' },
126
+ version: '^1.0.0',
127
+ configHash: 'hash-remote',
128
+ mcpRegistryVerified: true
129
+ };
130
+ const locals = [{
131
+ name: 'remote-example',
132
+ serverUrl: 'https://example.com/mcp'
133
+ }];
134
+ (0, chai_1.expect)(service.classifyRegistryEntry(remoteEntry, locals, [remoteEntry])).to.deep.equal({ kind: 'installed-manually' });
135
+ });
136
+ it('returns installed-manually for an unlinked local server matching the slug even if the config differs - drift only matters once linked', () => {
137
+ const locals = [{
138
+ name: 'example',
139
+ command: 'node',
140
+ args: ['-y', 'example-mcp']
141
+ }];
142
+ (0, chai_1.expect)(service.classifyRegistryEntry(entry, locals, [entry])).to.deep.equal({ kind: 'installed-manually' });
143
+ });
144
+ it('returns installed-link-stale when the slug-matching local is linked to a server id that is absent from the registry', () => {
145
+ const locals = [{
146
+ name: 'example',
147
+ command: 'npx',
148
+ args: ['-y', 'example-mcp'],
149
+ registryMetadata: {
150
+ serverId: 'io.example/gone',
151
+ version: '^1.0.0',
152
+ configHash: 'hash-v1'
153
+ }
154
+ }];
155
+ // The registry still publishes `entry` (slug `example`) but no longer publishes
156
+ // `io.example/gone`. The local must surface as link-stale so the Search view
157
+ // mirrors what the Installed view shows (Unlink + Uninstall instead of Link).
158
+ (0, chai_1.expect)(service.classifyRegistryEntry(entry, locals, [entry])).to.deep.equal({ kind: 'installed-link-stale' });
159
+ });
160
+ it('returns installed-manually (not link-stale) when the slug-matching local is linked to a different but valid registry id', () => {
161
+ const otherEntry = {
162
+ ...entry,
163
+ serverId: 'io.github.example/other-mcp',
164
+ localName: 'other'
165
+ };
166
+ const locals = [{
167
+ name: 'example',
168
+ command: 'npx',
169
+ args: ['-y', 'example-mcp'],
170
+ // The id is real - just bound to a different registry entry. The user can still
171
+ // re-link this local to `entry` from Search, so we surface Link, not Unlink.
172
+ registryMetadata: { serverId: otherEntry.serverId }
173
+ }];
174
+ (0, chai_1.expect)(service.classifyRegistryEntry(entry, locals, [entry, otherEntry])).to.deep.equal({ kind: 'installed-manually' });
175
+ });
176
+ it('returns fix-config only when the local server is already linked to this serverId but its registry-set fields diverge', () => {
177
+ const locals = [{
178
+ name: 'example',
179
+ command: 'node',
180
+ args: ['-y', 'example-mcp'],
181
+ registryMetadata: {
182
+ serverId: entry.serverId,
183
+ version: entry.version,
184
+ configHash: entry.configHash
185
+ }
186
+ }];
187
+ (0, chai_1.expect)(service.classifyRegistryEntry(entry, locals, [entry])).to.deep.equal({ kind: 'fix-config' });
188
+ });
189
+ it('treats user-added env keys absent from the registry config as non-drift (installed-from-registry) for linked servers', () => {
190
+ const entryWithEnv = {
191
+ ...entry,
192
+ config: { command: 'npx', args: ['-y', 'example-mcp'], env: { LOG_LEVEL: 'info' } }
193
+ };
194
+ const locals = [{
195
+ name: 'example',
196
+ command: 'npx',
197
+ args: ['-y', 'example-mcp'],
198
+ env: { LOG_LEVEL: 'info', USER_TOKEN: 'secret' },
199
+ registryMetadata: {
200
+ serverId: entry.serverId,
201
+ version: entry.version,
202
+ configHash: entry.configHash
203
+ }
204
+ }];
205
+ (0, chai_1.expect)(service.classifyRegistryEntry(entryWithEnv, locals, [entryWithEnv])).to.deep.equal({ kind: 'installed-from-registry', updateAvailable: false });
206
+ });
207
+ it('returns fix-config when a linked server has a registry-set env value differing from the local one', () => {
208
+ const entryWithEnv = {
209
+ ...entry,
210
+ config: { command: 'npx', args: ['-y', 'example-mcp'], env: { LOG_LEVEL: 'info' } }
211
+ };
212
+ const locals = [{
213
+ name: 'example',
214
+ command: 'npx',
215
+ args: ['-y', 'example-mcp'],
216
+ env: { LOG_LEVEL: 'debug' },
217
+ registryMetadata: {
218
+ serverId: entry.serverId,
219
+ version: entry.version,
220
+ configHash: entry.configHash
221
+ }
222
+ }];
223
+ (0, chai_1.expect)(service.classifyRegistryEntry(entryWithEnv, locals, [entryWithEnv])).to.deep.equal({ kind: 'fix-config' });
224
+ });
225
+ });
226
+ describe('MCPInstallService.classifyLocalServer', () => {
227
+ const exampleEntry = {
228
+ serverId: 'io.github.example/example-mcp',
229
+ name: 'Example',
230
+ description: 'Example MCP server',
231
+ localName: 'example',
232
+ config: { command: 'npx', args: ['-y', 'example-mcp'] },
233
+ version: '^1.0.0',
234
+ configHash: 'hash-v1',
235
+ mcpRegistryVerified: true
236
+ };
237
+ let service;
238
+ beforeEach(() => {
239
+ service = new mcp_install_service_1.MCPInstallServiceImpl();
240
+ });
241
+ it('returns installed-user-added when the local server has no registryMetadata and no registry entry matches its slug', () => {
242
+ const local = { name: 'unrelated', command: 'node', args: ['my-script.js'] };
243
+ (0, chai_1.expect)(service.classifyLocalServer(local, [exampleEntry])).to.deep.equal({ kind: 'installed-user-added' });
244
+ });
245
+ it('returns installed-from-registry with no update when the linked serverId matches and configHash matches', () => {
246
+ const local = {
247
+ name: 'example',
248
+ command: 'npx',
249
+ args: ['-y', 'example-mcp'],
250
+ registryMetadata: {
251
+ serverId: exampleEntry.serverId,
252
+ version: exampleEntry.version,
253
+ configHash: exampleEntry.configHash
254
+ }
255
+ };
256
+ (0, chai_1.expect)(service.classifyLocalServer(local, [exampleEntry])).to.deep.equal({ kind: 'installed-from-registry', updateAvailable: false });
257
+ });
258
+ it('returns installed-from-registry with update available when the linked configHash differs from the matched entry configHash', () => {
259
+ const local = {
260
+ name: 'example',
261
+ command: 'npx',
262
+ args: ['-y', 'example-mcp'],
263
+ registryMetadata: {
264
+ serverId: exampleEntry.serverId,
265
+ version: exampleEntry.version,
266
+ configHash: 'hash-v0'
267
+ }
268
+ };
269
+ (0, chai_1.expect)(service.classifyLocalServer(local, [exampleEntry])).to.deep.equal({ kind: 'installed-from-registry', updateAvailable: true });
270
+ });
271
+ it('returns installed-link-stale when the linked serverId points to a serverId no longer in the registry', () => {
272
+ const local = {
273
+ name: 'example',
274
+ command: 'npx',
275
+ args: ['-y', 'example-mcp'],
276
+ registryMetadata: {
277
+ serverId: 'io.github.example/removed-mcp',
278
+ version: '^1.0.0',
279
+ configHash: 'hash-removed'
280
+ }
281
+ };
282
+ (0, chai_1.expect)(service.classifyLocalServer(local, [exampleEntry])).to.deep.equal({ kind: 'installed-link-stale' });
283
+ });
284
+ it('returns installed-manually when the local server has no registryMetadata but its slug matches a registry entry', () => {
285
+ const local = {
286
+ name: 'example',
287
+ command: 'npx',
288
+ args: ['-y', 'example-mcp']
289
+ };
290
+ (0, chai_1.expect)(service.classifyLocalServer(local, [exampleEntry])).to.deep.equal({ kind: 'installed-manually' });
291
+ });
292
+ it('returns installed-manually when an unlinked local server has a diverging command - Link must be offered before drift is actioned', () => {
293
+ const local = {
294
+ name: 'example',
295
+ command: 'node',
296
+ args: ['-y', 'example-mcp']
297
+ };
298
+ (0, chai_1.expect)(service.classifyLocalServer(local, [exampleEntry])).to.deep.equal({ kind: 'installed-manually' });
299
+ });
300
+ it('returns fix-config when a linked local server has drifted away from the registry config', () => {
301
+ const local = {
302
+ name: 'example',
303
+ command: 'node',
304
+ args: ['-y', 'example-mcp'],
305
+ registryMetadata: {
306
+ serverId: exampleEntry.serverId,
307
+ version: exampleEntry.version,
308
+ configHash: exampleEntry.configHash
309
+ }
310
+ };
311
+ (0, chai_1.expect)(service.classifyLocalServer(local, [exampleEntry])).to.deep.equal({ kind: 'fix-config' });
312
+ });
313
+ });
314
+ describe('MCPInstallService actions', () => {
315
+ const entry = {
316
+ serverId: 'io.github.example/example-mcp',
317
+ name: 'Example',
318
+ description: 'Example MCP server',
319
+ localName: 'example',
320
+ config: { command: 'npx', args: ['-y', 'example-mcp'] },
321
+ version: '^1.0.0',
322
+ configHash: 'hash-v1',
323
+ mcpRegistryVerified: true
324
+ };
325
+ let prefs;
326
+ let service;
327
+ beforeEach(() => {
328
+ const container = new inversify_1.Container();
329
+ prefs = new FakePreferenceService();
330
+ container.bind(core_1.PreferenceService).toConstantValue(prefs);
331
+ // Stubs for the editor's deps - we only exercise installFromEntry which uses
332
+ // PreferenceService; MessageService and MCPFrontendService are referenced by other
333
+ // editor methods that the install path doesn't touch.
334
+ container.bind(core_1.MessageService).toConstantValue({ error: () => undefined });
335
+ container.bind(mcp_server_manager_1.MCPFrontendService).toConstantValue({});
336
+ // The install path here only writes preferences; bind a dialog factory that fails loudly if used.
337
+ container.bind(mcp_server_editor_1.MCPServerEditDialogFactory).toConstantValue(() => {
338
+ throw new Error('MCPServerEditDialogFactory should not be invoked in these tests');
339
+ });
340
+ container.bind(mcp_server_editor_1.MCPServerEditorImpl).toSelf().inSingletonScope();
341
+ container.bind(mcp_server_editor_1.MCPServerEditor).toService(mcp_server_editor_1.MCPServerEditorImpl);
342
+ container.bind(mcp_install_service_1.MCPInstallServiceImpl).toSelf().inSingletonScope();
343
+ container.bind(mcp_install_service_1.MCPInstallService).toService(mcp_install_service_1.MCPInstallServiceImpl);
344
+ service = container.get(mcp_install_service_1.MCPInstallService);
345
+ });
346
+ it('install with override autostart=false persists the user choice instead of leaving the registry default', async () => {
347
+ await service.install(entry, { autostart: false });
348
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF).example.autostart).to.equal(false);
349
+ });
350
+ it('install with auth token override fills it into a remote entry that advertises a serverAuthToken slot', async () => {
351
+ const remoteEntry = {
352
+ ...entry,
353
+ config: { serverUrl: 'https://example.com', serverAuthToken: '' }
354
+ };
355
+ await service.install(remoteEntry, { serverAuthToken: 'secret-123' });
356
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF).example.serverAuthToken).to.equal('secret-123');
357
+ });
358
+ it('install ignores a token override when the registry entry has no serverAuthToken slot - keeps local entries from accidentally storing one', async () => {
359
+ await service.install(entry, { serverAuthToken: 'ignored' });
360
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF).example).to.not.have.property('serverAuthToken');
361
+ });
362
+ it('install writes a new entry with the registry config and a registryMetadata block (including configHash) to the preference', async () => {
363
+ await service.install(entry);
364
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF)).to.deep.equal({
365
+ example: {
366
+ command: 'npx',
367
+ args: ['-y', 'example-mcp'],
368
+ registryMetadata: {
369
+ serverId: 'io.github.example/example-mcp',
370
+ version: '^1.0.0',
371
+ configHash: 'hash-v1'
372
+ }
373
+ }
374
+ });
375
+ });
376
+ it('uninstall removes the entry by slug and leaves unrelated servers intact', async () => {
377
+ await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
378
+ example: {
379
+ command: 'npx',
380
+ args: ['-y', 'example-mcp'],
381
+ registryMetadata: { serverId: 'io.github.example/example-mcp' }
382
+ },
383
+ other: { command: 'node', args: ['unrelated.js'] }
384
+ });
385
+ await service.uninstall('example');
386
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF)).to.deep.equal({
387
+ other: { command: 'node', args: ['unrelated.js'] }
388
+ });
389
+ });
390
+ it('unlink removes the registryMetadata block while leaving the server config intact', async () => {
391
+ await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
392
+ example: {
393
+ command: 'npx',
394
+ args: ['-y', 'example-mcp'],
395
+ env: { USER_TOKEN: 'secret' },
396
+ autostart: true,
397
+ registryMetadata: {
398
+ serverId: 'io.github.example/example-mcp',
399
+ version: '^1.0.0',
400
+ configHash: 'hash-v1'
401
+ }
402
+ }
403
+ });
404
+ await service.unlink('example');
405
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF)).to.deep.equal({
406
+ example: {
407
+ command: 'npx',
408
+ args: ['-y', 'example-mcp'],
409
+ env: { USER_TOKEN: 'secret' },
410
+ autostart: true
411
+ }
412
+ });
413
+ });
414
+ it('unlink is a no-op on entries that have no registryMetadata block', async () => {
415
+ await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
416
+ example: { command: 'npx', args: ['-y', 'example-mcp'] }
417
+ });
418
+ await service.unlink('example');
419
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF)).to.deep.equal({
420
+ example: { command: 'npx', args: ['-y', 'example-mcp'] }
421
+ });
422
+ });
423
+ it('fixConfig overwrites the local config with the registry config and sets the registryMetadata block', async () => {
424
+ await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
425
+ example: {
426
+ command: 'node',
427
+ args: ['drifted-args']
428
+ }
429
+ });
430
+ await service.fixConfig(entry);
431
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF)).to.deep.equal({
432
+ example: {
433
+ command: 'npx',
434
+ args: ['-y', 'example-mcp'],
435
+ registryMetadata: {
436
+ serverId: 'io.github.example/example-mcp',
437
+ version: '^1.0.0',
438
+ configHash: 'hash-v1'
439
+ }
440
+ }
441
+ });
442
+ });
443
+ it('fixConfig preserves the existing autostart preference - the registry has no opinion on it', async () => {
444
+ await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
445
+ example: {
446
+ command: 'node',
447
+ args: ['drifted-args'],
448
+ autostart: false
449
+ }
450
+ });
451
+ await service.fixConfig(entry);
452
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF).example.autostart).to.equal(false);
453
+ });
454
+ it('link sets the registryMetadata block on the existing entry, leaving its config untouched', async () => {
455
+ await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
456
+ example: {
457
+ command: 'npx',
458
+ args: ['-y', 'example-mcp'],
459
+ env: { USER_TOKEN: 'secret' },
460
+ autostart: true
461
+ }
462
+ });
463
+ await service.link(entry);
464
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF)).to.deep.equal({
465
+ example: {
466
+ command: 'npx',
467
+ args: ['-y', 'example-mcp'],
468
+ env: { USER_TOKEN: 'secret' },
469
+ autostart: true,
470
+ registryMetadata: {
471
+ serverId: 'io.github.example/example-mcp',
472
+ version: '^1.0.0',
473
+ configHash: 'hash-v1'
474
+ }
475
+ }
476
+ });
477
+ });
478
+ it('update preserves a user-supplied serverAuthToken when the registry approval ships an empty slot', async () => {
479
+ const remoteEntry = {
480
+ ...entry,
481
+ config: { serverUrl: 'https://example.com/mcp', serverAuthToken: '' },
482
+ configHash: 'hash-v2'
483
+ };
484
+ await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
485
+ example: {
486
+ serverUrl: 'https://example.com/mcp',
487
+ serverAuthToken: 'user-secret',
488
+ registryMetadata: {
489
+ serverId: 'io.github.example/example-mcp',
490
+ version: '^1.0.0',
491
+ configHash: 'hash-v1'
492
+ }
493
+ }
494
+ });
495
+ await service.update(remoteEntry);
496
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF).example.serverAuthToken).to.equal('user-secret');
497
+ });
498
+ it('update strips stale local fields when the registry switches a remote entry from command/args to serverUrl', async () => {
499
+ const remoteEntry = {
500
+ ...entry,
501
+ config: { serverUrl: 'https://example.com/mcp' },
502
+ configHash: 'hash-v2'
503
+ };
504
+ await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
505
+ example: {
506
+ command: 'npx',
507
+ args: ['-y', 'example-mcp'],
508
+ env: { LOG_LEVEL: 'debug' },
509
+ autostart: true,
510
+ registryMetadata: {
511
+ serverId: 'io.github.example/example-mcp',
512
+ version: '^1.0.0',
513
+ configHash: 'hash-v1'
514
+ }
515
+ }
516
+ });
517
+ await service.update(remoteEntry);
518
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF)).to.deep.equal({
519
+ example: {
520
+ serverUrl: 'https://example.com/mcp',
521
+ autostart: true,
522
+ registryMetadata: {
523
+ serverId: 'io.github.example/example-mcp',
524
+ version: '^1.0.0',
525
+ configHash: 'hash-v2'
526
+ }
527
+ }
528
+ });
529
+ });
530
+ it('update strips stale remote fields when the registry switches an entry from serverUrl to command/args', async () => {
531
+ const localEntry = {
532
+ ...entry,
533
+ config: { command: 'npx', args: ['-y', 'example-mcp'] },
534
+ configHash: 'hash-v2'
535
+ };
536
+ await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
537
+ example: {
538
+ serverUrl: 'https://example.com/mcp',
539
+ serverAuthToken: 'user-secret',
540
+ serverAuthTokenHeader: 'X-Token',
541
+ headers: { 'X-Custom': 'value' },
542
+ autostart: true,
543
+ registryMetadata: {
544
+ serverId: 'io.github.example/example-mcp',
545
+ version: '^1.0.0',
546
+ configHash: 'hash-v1'
547
+ }
548
+ }
549
+ });
550
+ await service.update(localEntry);
551
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF)).to.deep.equal({
552
+ example: {
553
+ command: 'npx',
554
+ args: ['-y', 'example-mcp'],
555
+ autostart: true,
556
+ registryMetadata: {
557
+ serverId: 'io.github.example/example-mcp',
558
+ version: '^1.0.0',
559
+ configHash: 'hash-v2'
560
+ }
561
+ }
562
+ });
563
+ });
564
+ it('update overwrites registry-set fields, preserves user-added env keys and autostart, and bumps the registryMetadata block', async () => {
565
+ const newEntry = {
566
+ ...entry,
567
+ config: {
568
+ command: 'npx',
569
+ args: ['-y', 'example-mcp@1.0.0'],
570
+ env: { LOG_LEVEL: 'info' }
571
+ },
572
+ version: '^1.0.0',
573
+ configHash: 'hash-v2'
574
+ };
575
+ await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
576
+ example: {
577
+ command: 'npx',
578
+ args: ['-y', 'example-mcp@0.9.0'],
579
+ env: { LOG_LEVEL: 'debug', USER_TOKEN: 'secret' },
580
+ autostart: false,
581
+ registryMetadata: {
582
+ serverId: 'io.github.example/example-mcp',
583
+ version: '^0.9.0',
584
+ configHash: 'hash-v1'
585
+ }
586
+ }
587
+ });
588
+ await service.update(newEntry);
589
+ (0, chai_1.expect)(prefs.snapshot(mcp_preferences_1.MCP_SERVERS_PREF)).to.deep.equal({
590
+ example: {
591
+ command: 'npx',
592
+ args: ['-y', 'example-mcp@1.0.0'],
593
+ env: { LOG_LEVEL: 'info', USER_TOKEN: 'secret' },
594
+ autostart: false,
595
+ registryMetadata: {
596
+ serverId: 'io.github.example/example-mcp',
597
+ version: '^1.0.0',
598
+ configHash: 'hash-v2'
599
+ }
600
+ }
601
+ });
602
+ });
603
+ });
604
+ //# sourceMappingURL=mcp-install-service.spec.js.map