@qase/mcp-server 1.1.7 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +75 -551
  3. package/build/auth/client-context.d.ts +12 -0
  4. package/build/auth/client-context.d.ts.map +1 -0
  5. package/build/auth/client-context.js +12 -0
  6. package/build/auth/client-context.js.map +1 -0
  7. package/build/auth/jwks-verifier.d.ts +15 -0
  8. package/build/auth/jwks-verifier.d.ts.map +1 -0
  9. package/build/auth/jwks-verifier.js +31 -0
  10. package/build/auth/jwks-verifier.js.map +1 -0
  11. package/build/auth/mcp-guard.d.ts +15 -0
  12. package/build/auth/mcp-guard.d.ts.map +1 -0
  13. package/build/auth/mcp-guard.js +44 -0
  14. package/build/auth/mcp-guard.js.map +1 -0
  15. package/build/auth/oauth-config.d.ts +40 -0
  16. package/build/auth/oauth-config.d.ts.map +1 -0
  17. package/build/auth/oauth-config.js +34 -0
  18. package/build/auth/oauth-config.js.map +1 -0
  19. package/build/auth/proxy-provider.d.ts +31 -0
  20. package/build/auth/proxy-provider.d.ts.map +1 -0
  21. package/build/auth/proxy-provider.js +87 -0
  22. package/build/auth/proxy-provider.js.map +1 -0
  23. package/build/auth/token-type.d.ts +7 -0
  24. package/build/auth/token-type.d.ts.map +1 -0
  25. package/build/auth/token-type.js +10 -0
  26. package/build/auth/token-type.js.map +1 -0
  27. package/build/cache/circuit-breaker.d.ts +33 -0
  28. package/build/cache/circuit-breaker.d.ts.map +1 -0
  29. package/build/cache/circuit-breaker.js +68 -0
  30. package/build/cache/circuit-breaker.js.map +1 -0
  31. package/build/cache/index.d.ts +24 -0
  32. package/build/cache/index.d.ts.map +1 -0
  33. package/build/cache/index.js +86 -0
  34. package/build/cache/index.js.map +1 -0
  35. package/build/cache/keys.d.ts +25 -0
  36. package/build/cache/keys.d.ts.map +1 -0
  37. package/build/cache/keys.js +36 -0
  38. package/build/cache/keys.js.map +1 -0
  39. package/build/cache/layered.d.ts +31 -0
  40. package/build/cache/layered.d.ts.map +1 -0
  41. package/build/cache/layered.js +88 -0
  42. package/build/cache/layered.js.map +1 -0
  43. package/build/cache/memory.d.ts +32 -0
  44. package/build/cache/memory.d.ts.map +1 -0
  45. package/build/cache/memory.js +108 -0
  46. package/build/cache/memory.js.map +1 -0
  47. package/build/cache/metrics.d.ts +31 -0
  48. package/build/cache/metrics.d.ts.map +1 -0
  49. package/build/cache/metrics.js +95 -0
  50. package/build/cache/metrics.js.map +1 -0
  51. package/build/cache/prom-format.d.ts +7 -0
  52. package/build/cache/prom-format.d.ts.map +1 -0
  53. package/build/cache/prom-format.js +16 -0
  54. package/build/cache/prom-format.js.map +1 -0
  55. package/build/cache/redis-bus.d.ts +29 -0
  56. package/build/cache/redis-bus.d.ts.map +1 -0
  57. package/build/cache/redis-bus.js +50 -0
  58. package/build/cache/redis-bus.js.map +1 -0
  59. package/build/cache/redis.d.ts +32 -0
  60. package/build/cache/redis.d.ts.map +1 -0
  61. package/build/cache/redis.js +89 -0
  62. package/build/cache/redis.js.map +1 -0
  63. package/build/cache/types.d.ts +38 -0
  64. package/build/cache/types.d.ts.map +1 -0
  65. package/build/cache/types.js +2 -0
  66. package/build/cache/types.js.map +1 -0
  67. package/build/client/index.d.ts +10 -3
  68. package/build/client/index.d.ts.map +1 -1
  69. package/build/client/index.js +75 -50
  70. package/build/client/index.js.map +1 -1
  71. package/build/http/agent.d.ts +16 -0
  72. package/build/http/agent.d.ts.map +1 -0
  73. package/build/http/agent.js +16 -0
  74. package/build/http/agent.js.map +1 -0
  75. package/build/http/dedupe.d.ts +14 -0
  76. package/build/http/dedupe.d.ts.map +1 -0
  77. package/build/http/dedupe.js +69 -0
  78. package/build/http/dedupe.js.map +1 -0
  79. package/build/http/index.d.ts +6 -0
  80. package/build/http/index.d.ts.map +1 -0
  81. package/build/http/index.js +4 -0
  82. package/build/http/index.js.map +1 -0
  83. package/build/http/retry.d.ts +18 -0
  84. package/build/http/retry.d.ts.map +1 -0
  85. package/build/http/retry.js +52 -0
  86. package/build/http/retry.js.map +1 -0
  87. package/build/index.d.ts +1 -18
  88. package/build/index.d.ts.map +1 -1
  89. package/build/index.js +95 -61
  90. package/build/index.js.map +1 -1
  91. package/build/operations-v2/composites/ci-report.d.ts +2 -0
  92. package/build/operations-v2/composites/ci-report.d.ts.map +1 -0
  93. package/build/operations-v2/composites/ci-report.js +99 -0
  94. package/build/operations-v2/composites/ci-report.js.map +1 -0
  95. package/build/operations-v2/composites/regression-run.d.ts +2 -0
  96. package/build/operations-v2/composites/regression-run.d.ts.map +1 -0
  97. package/build/operations-v2/composites/regression-run.js +81 -0
  98. package/build/operations-v2/composites/regression-run.js.map +1 -0
  99. package/build/operations-v2/composites/triage-defect.d.ts +2 -0
  100. package/build/operations-v2/composites/triage-defect.d.ts.map +1 -0
  101. package/build/operations-v2/composites/triage-defect.js +67 -0
  102. package/build/operations-v2/composites/triage-defect.js.map +1 -0
  103. package/build/operations-v2/escape/api.d.ts +2 -0
  104. package/build/operations-v2/escape/api.d.ts.map +1 -0
  105. package/build/operations-v2/escape/api.js +34 -0
  106. package/build/operations-v2/escape/api.js.map +1 -0
  107. package/build/operations-v2/index.d.ts +19 -0
  108. package/build/operations-v2/index.d.ts.map +1 -0
  109. package/build/operations-v2/index.js +25 -0
  110. package/build/operations-v2/index.js.map +1 -0
  111. package/build/operations-v2/meta/discover.d.ts +9 -0
  112. package/build/operations-v2/meta/discover.d.ts.map +1 -0
  113. package/build/operations-v2/meta/discover.js +76 -0
  114. package/build/operations-v2/meta/discover.js.map +1 -0
  115. package/build/{operations/search.d.ts → operations-v2/qql/index.d.ts} +1 -1
  116. package/build/operations-v2/qql/index.d.ts.map +1 -0
  117. package/build/{operations/search.js → operations-v2/qql/index.js} +34 -9
  118. package/build/operations-v2/qql/index.js.map +1 -0
  119. package/build/operations-v2/read/get.d.ts +2 -0
  120. package/build/operations-v2/read/get.d.ts.map +1 -0
  121. package/build/operations-v2/read/get.js +91 -0
  122. package/build/operations-v2/read/get.js.map +1 -0
  123. package/build/operations-v2/read/project-context.d.ts +2 -0
  124. package/build/operations-v2/read/project-context.d.ts.map +1 -0
  125. package/build/operations-v2/read/project-context.js +102 -0
  126. package/build/operations-v2/read/project-context.js.map +1 -0
  127. package/build/operations-v2/write/attachments.d.ts +2 -0
  128. package/build/operations-v2/write/attachments.d.ts.map +1 -0
  129. package/build/operations-v2/write/attachments.js +58 -0
  130. package/build/operations-v2/write/attachments.js.map +1 -0
  131. package/build/operations-v2/write/cases.d.ts +2 -0
  132. package/build/operations-v2/write/cases.d.ts.map +1 -0
  133. package/build/operations-v2/write/cases.js +121 -0
  134. package/build/operations-v2/write/cases.js.map +1 -0
  135. package/build/operations-v2/write/defects.d.ts +2 -0
  136. package/build/operations-v2/write/defects.d.ts.map +1 -0
  137. package/build/operations-v2/write/defects.js +81 -0
  138. package/build/operations-v2/write/defects.js.map +1 -0
  139. package/build/operations-v2/write/environments.d.ts +2 -0
  140. package/build/operations-v2/write/environments.d.ts.map +1 -0
  141. package/build/operations-v2/write/environments.js +56 -0
  142. package/build/operations-v2/write/environments.js.map +1 -0
  143. package/build/operations-v2/write/milestones.d.ts +2 -0
  144. package/build/operations-v2/write/milestones.d.ts.map +1 -0
  145. package/build/operations-v2/write/milestones.js +56 -0
  146. package/build/operations-v2/write/milestones.js.map +1 -0
  147. package/build/operations-v2/write/plans.d.ts +2 -0
  148. package/build/operations-v2/write/plans.d.ts.map +1 -0
  149. package/build/operations-v2/write/plans.js +55 -0
  150. package/build/operations-v2/write/plans.js.map +1 -0
  151. package/build/operations-v2/write/results.d.ts +2 -0
  152. package/build/operations-v2/write/results.d.ts.map +1 -0
  153. package/build/operations-v2/write/results.js +72 -0
  154. package/build/operations-v2/write/results.js.map +1 -0
  155. package/build/operations-v2/write/runs.d.ts +2 -0
  156. package/build/operations-v2/write/runs.d.ts.map +1 -0
  157. package/build/operations-v2/write/runs.js +84 -0
  158. package/build/operations-v2/write/runs.js.map +1 -0
  159. package/build/operations-v2/write/shared-steps.d.ts +2 -0
  160. package/build/operations-v2/write/shared-steps.d.ts.map +1 -0
  161. package/build/operations-v2/write/shared-steps.js +60 -0
  162. package/build/operations-v2/write/shared-steps.js.map +1 -0
  163. package/build/operations-v2/write/suites.d.ts +2 -0
  164. package/build/operations-v2/write/suites.d.ts.map +1 -0
  165. package/build/operations-v2/write/suites.js +63 -0
  166. package/build/operations-v2/write/suites.js.map +1 -0
  167. package/build/prompts/index.d.ts +31 -0
  168. package/build/prompts/index.d.ts.map +1 -0
  169. package/build/prompts/index.js +229 -0
  170. package/build/prompts/index.js.map +1 -0
  171. package/build/transports/sse.d.ts.map +1 -1
  172. package/build/transports/sse.js +6 -0
  173. package/build/transports/sse.js.map +1 -1
  174. package/build/transports/streamableHttp.d.ts +6 -1
  175. package/build/transports/streamableHttp.d.ts.map +1 -1
  176. package/build/transports/streamableHttp.js +128 -16
  177. package/build/transports/streamableHttp.js.map +1 -1
  178. package/build/utils/auth-context.d.ts +8 -0
  179. package/build/utils/auth-context.d.ts.map +1 -1
  180. package/build/utils/auth-context.js +18 -0
  181. package/build/utils/auth-context.js.map +1 -1
  182. package/build/utils/case-enums.d.ts +5 -3
  183. package/build/utils/case-enums.d.ts.map +1 -1
  184. package/build/utils/case-enums.js +78 -59
  185. package/build/utils/case-enums.js.map +1 -1
  186. package/build/utils/output-schemas.d.ts +16 -0
  187. package/build/utils/output-schemas.d.ts.map +1 -0
  188. package/build/utils/output-schemas.js +82 -0
  189. package/build/utils/output-schemas.js.map +1 -0
  190. package/build/utils/registry.d.ts +42 -9
  191. package/build/utils/registry.d.ts.map +1 -1
  192. package/build/utils/registry.js +64 -11
  193. package/build/utils/registry.js.map +1 -1
  194. package/build/utils/response-shape.d.ts +23 -0
  195. package/build/utils/response-shape.d.ts.map +1 -0
  196. package/build/utils/response-shape.js +73 -0
  197. package/build/utils/response-shape.js.map +1 -0
  198. package/build/utils/rich-response.d.ts +58 -0
  199. package/build/utils/rich-response.d.ts.map +1 -0
  200. package/build/utils/rich-response.js +93 -0
  201. package/build/utils/rich-response.js.map +1 -0
  202. package/build/utils/server-context.d.ts +65 -0
  203. package/build/utils/server-context.d.ts.map +1 -0
  204. package/build/utils/server-context.js +67 -0
  205. package/build/utils/server-context.js.map +1 -0
  206. package/build/version.d.ts +1 -1
  207. package/build/version.js +1 -1
  208. package/docs/connect.md +81 -0
  209. package/docs/migration.md +351 -0
  210. package/docs/self-run.md +270 -0
  211. package/docs/tools.md +109 -0
  212. package/docs/troubleshooting.md +144 -0
  213. package/package.json +12 -3
  214. package/server.json +8 -2
  215. package/build/operations/attachments.d.ts +0 -8
  216. package/build/operations/attachments.d.ts.map +0 -1
  217. package/build/operations/attachments.js +0 -146
  218. package/build/operations/attachments.js.map +0 -1
  219. package/build/operations/authors.d.ts +0 -8
  220. package/build/operations/authors.d.ts.map +0 -1
  221. package/build/operations/authors.js +0 -70
  222. package/build/operations/authors.js.map +0 -1
  223. package/build/operations/cases.d.ts +0 -8
  224. package/build/operations/cases.d.ts.map +0 -1
  225. package/build/operations/cases.js +0 -338
  226. package/build/operations/cases.js.map +0 -1
  227. package/build/operations/configurations.d.ts +0 -10
  228. package/build/operations/configurations.d.ts.map +0 -1
  229. package/build/operations/configurations.js +0 -125
  230. package/build/operations/configurations.js.map +0 -1
  231. package/build/operations/custom-fields.d.ts +0 -8
  232. package/build/operations/custom-fields.d.ts.map +0 -1
  233. package/build/operations/custom-fields.js +0 -172
  234. package/build/operations/custom-fields.js.map +0 -1
  235. package/build/operations/defects.d.ts +0 -8
  236. package/build/operations/defects.d.ts.map +0 -1
  237. package/build/operations/defects.js +0 -256
  238. package/build/operations/defects.js.map +0 -1
  239. package/build/operations/environments.d.ts +0 -8
  240. package/build/operations/environments.d.ts.map +0 -1
  241. package/build/operations/environments.js +0 -154
  242. package/build/operations/environments.js.map +0 -1
  243. package/build/operations/milestones.d.ts +0 -8
  244. package/build/operations/milestones.d.ts.map +0 -1
  245. package/build/operations/milestones.js +0 -155
  246. package/build/operations/milestones.js.map +0 -1
  247. package/build/operations/plans.d.ts +0 -8
  248. package/build/operations/plans.d.ts.map +0 -1
  249. package/build/operations/plans.js +0 -158
  250. package/build/operations/plans.js.map +0 -1
  251. package/build/operations/projects.d.ts +0 -8
  252. package/build/operations/projects.d.ts.map +0 -1
  253. package/build/operations/projects.js +0 -192
  254. package/build/operations/projects.js.map +0 -1
  255. package/build/operations/results.d.ts +0 -8
  256. package/build/operations/results.d.ts.map +0 -1
  257. package/build/operations/results.js +0 -214
  258. package/build/operations/results.js.map +0 -1
  259. package/build/operations/runs.d.ts +0 -8
  260. package/build/operations/runs.d.ts.map +0 -1
  261. package/build/operations/runs.js +0 -224
  262. package/build/operations/runs.js.map +0 -1
  263. package/build/operations/search.d.ts.map +0 -1
  264. package/build/operations/search.js.map +0 -1
  265. package/build/operations/shared-parameters.d.ts +0 -10
  266. package/build/operations/shared-parameters.d.ts.map +0 -1
  267. package/build/operations/shared-parameters.js +0 -93
  268. package/build/operations/shared-parameters.js.map +0 -1
  269. package/build/operations/shared-steps.d.ts +0 -8
  270. package/build/operations/shared-steps.d.ts.map +0 -1
  271. package/build/operations/shared-steps.js +0 -160
  272. package/build/operations/shared-steps.js.map +0 -1
  273. package/build/operations/suites.d.ts +0 -8
  274. package/build/operations/suites.d.ts.map +0 -1
  275. package/build/operations/suites.js +0 -169
  276. package/build/operations/suites.js.map +0 -1
  277. package/build/operations/system-fields.d.ts +0 -10
  278. package/build/operations/system-fields.d.ts.map +0 -1
  279. package/build/operations/system-fields.js +0 -47
  280. package/build/operations/system-fields.js.map +0 -1
  281. package/build/operations/users.d.ts +0 -10
  282. package/build/operations/users.d.ts.map +0 -1
  283. package/build/operations/users.js +0 -78
  284. package/build/operations/users.js.map +0 -1
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Server Context
3
+ *
4
+ * Provides access to the MCP Server instance within tool handlers
5
+ * via AsyncLocalStorage, following the same pattern as auth-context.ts.
6
+ *
7
+ * This enables features that require server-level access (elicitation,
8
+ * tool list notifications) without passing the server through handler signatures.
9
+ */
10
+ import { AsyncLocalStorage } from 'async_hooks';
11
+ /**
12
+ * Per-request server storage.
13
+ * Holds the Server instance for the current request context.
14
+ */
15
+ export const serverStorage = new AsyncLocalStorage();
16
+ /**
17
+ * Get the Server instance from the current async context.
18
+ * Returns undefined if called outside of a serverStorage.run() scope.
19
+ */
20
+ export function getServer() {
21
+ return serverStorage.getStore();
22
+ }
23
+ /**
24
+ * Ask the user to confirm a destructive action via MCP elicitation.
25
+ *
26
+ * Graceful degradation:
27
+ * - No server in context → proceed (return true)
28
+ * - Client doesn't support elicitation → proceed
29
+ * - elicitInput() throws → proceed (log error)
30
+ * - User declines or cancels → return false
31
+ */
32
+ export async function confirmDestructiveAction(toolName, args) {
33
+ const server = getServer();
34
+ if (!server)
35
+ return true;
36
+ // Check if the client supports elicitation
37
+ const caps = server.getClientCapabilities();
38
+ if (!caps?.elicitation)
39
+ return true;
40
+ try {
41
+ const argsPreview = Object.entries(args)
42
+ .map(([k, v]) => ` ${k}: ${JSON.stringify(v)}`)
43
+ .join('\n');
44
+ const result = await server.elicitInput({
45
+ message: `Confirm destructive action: ${toolName}\n\n${argsPreview}`,
46
+ requestedSchema: {
47
+ type: 'object',
48
+ properties: {
49
+ confirm: {
50
+ type: 'boolean',
51
+ title: 'Confirm deletion',
52
+ description: 'This will permanently delete the resource. Proceed?',
53
+ default: false,
54
+ },
55
+ },
56
+ required: ['confirm'],
57
+ },
58
+ });
59
+ return result.action === 'accept' && result.content?.confirm === true;
60
+ }
61
+ catch (error) {
62
+ // Elicitation failed — graceful degradation: proceed without confirmation
63
+ console.error('[Server] Elicitation failed, proceeding without confirmation:', error);
64
+ return true;
65
+ }
66
+ }
67
+ //# sourceMappingURL=server-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-context.js","sourceRoot":"","sources":["../../src/utils/server-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,iBAAiB,EAAU,CAAC;AAE7D;;;GAGG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,aAAa,CAAC,QAAQ,EAAE,CAAC;AAClC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,QAAgB,EAChB,IAA6B;IAE7B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,2CAA2C;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,qBAAqB,EAAE,CAAC;IAC5C,IAAI,CAAC,IAAI,EAAE,WAAW;QAAE,OAAO,IAAI,CAAC;IAEpC,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;aACrC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/C,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC;YACtC,OAAO,EAAE,+BAA+B,QAAQ,OAAO,WAAW,EAAE;YACpE,eAAe,EAAE;gBACf,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,OAAO,EAAE;wBACP,IAAI,EAAE,SAAS;wBACf,KAAK,EAAE,kBAAkB;wBACzB,WAAW,EAAE,qDAAqD;wBAClE,OAAO,EAAE,KAAK;qBACf;iBACF;gBACD,QAAQ,EAAE,CAAC,SAAS,CAAC;aACtB;SACF,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACxE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0EAA0E;QAC1E,OAAO,CAAC,KAAK,CAAC,+DAA+D,EAAE,KAAK,CAAC,CAAC;QACtF,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "1.1.7";
1
+ export declare const VERSION = "2.0.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/build/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild script — do not edit manually
2
- export const VERSION = '1.1.7';
2
+ export const VERSION = '2.0.0';
3
3
  //# sourceMappingURL=version.js.map
@@ -0,0 +1,81 @@
1
+ # Connect to the hosted Qase MCP
2
+
3
+ The quickest way to use Qase — no install and no API token. Connect to the Qase-hosted MCP server at `https://mcp.qase.io/mcp` and sign in with your Qase account. Any MCP client that supports remote servers (OAuth 2.1) works; the client handles the OAuth flow for you — Claude, Cursor, Codex, and VS Code are shown below.
4
+
5
+ > **Note:** The hosted Qase MCP is available on the **Enterprise** plan in Qase. On other plans you'll be denied access when connecting — [run the server yourself](self-run.md) with your own API token instead.
6
+
7
+ Prefer to run the server yourself with your own `QASE_API_TOKEN`? See [Self-Run Guide (Local / stdio)](self-run.md).
8
+
9
+ ## Claude
10
+
11
+ Qase publishes an official **Qase Test Management** connector in Claude's directory:
12
+
13
+ 1. In Claude, open **Settings → Connectors** and find **Qase Test Management**.
14
+ 2. Click **Connect** and complete the Qase sign-in when prompted.
15
+
16
+ ## Cursor
17
+
18
+ Add the hosted server by URL in `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project):
19
+
20
+ ```json
21
+ {
22
+ "mcpServers": {
23
+ "qase": {
24
+ "url": "https://mcp.qase.io/mcp"
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ Cursor opens your browser to sign in to Qase; the tools appear once you've authorized.
31
+
32
+ ## Codex
33
+
34
+ **ChatGPT / Codex app** — open **Settings → MCPs → Add server**, enter the URL `https://mcp.qase.io/mcp`, and click **Authenticate**.
35
+
36
+ **Codex CLI** — add to `~/.codex/config.toml`:
37
+
38
+ ```toml
39
+ [mcp_servers.qase]
40
+ url = "https://mcp.qase.io/mcp"
41
+ auth = "oauth"
42
+ ```
43
+
44
+ Then run `codex mcp login qase` and complete the Qase sign-in in your browser.
45
+
46
+ > **Note:** Enter the URL exactly as shown — without surrounding quotes. A stray quote (or its encoded form, `%22`) in the server URL breaks OAuth; if a connection ever fails to authenticate, remove the server entry and re-add it, typing the URL by hand.
47
+
48
+ ## VS Code
49
+
50
+ Add the hosted server to `.vscode/mcp.json` (workspace-scoped):
51
+
52
+ ```json
53
+ {
54
+ "servers": {
55
+ "qase": {
56
+ "type": "http",
57
+ "url": "https://mcp.qase.io/mcp"
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ Or run **MCP: Add Server** from the Command Palette (`⇧⌘P` / `Ctrl+Shift+P`), choose **HTTP**, and enter the URL. VS Code opens your browser to sign in to Qase; the tools appear once you've authorized.
64
+
65
+ ## Other remote clients
66
+
67
+ Any MCP client that supports remote (HTTP) servers with OAuth 2.1 can connect the same way — point it at:
68
+
69
+ ```
70
+ https://mcp.qase.io/mcp
71
+ ```
72
+
73
+ In every case the hosted server authenticates via your Qase login (OAuth) — no local installation or `QASE_API_TOKEN` needed.
74
+
75
+ ## Active workspace
76
+
77
+ The connector operates on the workspace currently selected in your Qase UI. To work in a different workspace, just switch it in Qase — the connector automatically routes subsequent requests to the newly selected workspace, with no need to reconnect or re-authorize.
78
+
79
+ ## Troubleshooting
80
+
81
+ Connector not appearing, empty tool list, or OAuth sign-in failing? See [Troubleshooting](troubleshooting.md).
@@ -0,0 +1,351 @@
1
+ # Migration Guide: v1 → v2
2
+
3
+ > **Breaking change**: v2 replaces all 83 v1 tool names with a consolidated set of 29 task-oriented tools (30 total, including the `qase_discover_tools` discovery tool).
4
+ > Every tool name has changed. Update your prompts, workflows, and any automation that references tool names.
5
+
6
+ ## What changed at a glance
7
+
8
+ | Area | v1 | v2 |
9
+ |---|---|---|
10
+ | Tool count | 83 | 29 task-oriented (30 total) |
11
+ | Naming convention | snake_case verbs (`list_cases`, `create_run`) | `qase_` prefix + noun+verb (`qase_case_upsert`) |
12
+ | Read tools | One tool per entity type | `qase_get` handles all entity types |
13
+ | List/search | Separate `list_*` per entity | `qql_search` with `entity=` parameter |
14
+ | Metadata bootstrap | 6 separate list calls | `qase_project_context` (single call, cached) |
15
+ | CI reporting | 3–4 manual steps | `qase_ci_report` composite |
16
+ | Response format | Pretty-printed JSON, nulls included | Compact JSON (no indent), nulls stripped |
17
+
18
+ ---
19
+
20
+ ## Tool mapping table
21
+
22
+ All 83 v1 tools mapped to their v2 equivalents.
23
+
24
+ ### Projects
25
+
26
+ | v1 tool | v2 equivalent | Notes |
27
+ |---|---|---|
28
+ | `list_projects` | `qase_project_context` | Returns project + suites + milestones + envs + custom fields + users in one call |
29
+ | `get_project` | `qase_get` with `entity="project"` | No `code` required; pass project code as `id` |
30
+ | `create_project` | `qase_api` | Use escape hatch: `POST /project` |
31
+ | `delete_project` | `qase_api` | Use escape hatch: `DELETE /project/{code}` |
32
+ | `grant_project_access` | `qase_api` | Use escape hatch: `POST /project/{code}/access` |
33
+ | `revoke_project_access` | `qase_api` | Use escape hatch: `DELETE /project/{code}/access` |
34
+
35
+ ### Test Cases
36
+
37
+ | v1 tool | v2 equivalent | Notes |
38
+ |---|---|---|
39
+ | `list_cases` | `qql_search` with `entity="case"` | Supports full QQL filters |
40
+ | `get_case` | `qase_get` with `entity="case"` | Supports `fields` projection |
41
+ | `create_case` | `qase_case_upsert` (omit `id`) | Pass all case fields; no `id` = create |
42
+ | `update_case` | `qase_case_upsert` (include `id`) | Include `id` to update existing case |
43
+ | `delete_case` | `qase_case_delete` | — |
44
+ | `bulk_create_cases` | `qase_case_upsert` (call per case) | Call once per case without `id` |
45
+ | `attach_external_issue` | `qase_api` | Use escape hatch: `POST /case/{code}/{id}/external-issues` |
46
+ | `detach_external_issue` | `qase_api` | Use escape hatch: `DELETE /case/{code}/{id}/external-issues` |
47
+
48
+ ### Test Suites
49
+
50
+ | v1 tool | v2 equivalent | Notes |
51
+ |---|---|---|
52
+ | `list_suites` | `qase_project_context` | Suites tree is included in context response |
53
+ | `get_suite` | `qase_get` with `entity="suite"` | — |
54
+ | `create_suite` | `qase_suite_upsert` (omit `id`) | — |
55
+ | `update_suite` | `qase_suite_upsert` (include `id`) | — |
56
+ | `delete_suite` | `qase_suite_delete` | — |
57
+
58
+ ### Test Runs
59
+
60
+ | v1 tool | v2 equivalent | Notes |
61
+ |---|---|---|
62
+ | `list_runs` | `qql_search` with `entity="run"` | — |
63
+ | `get_run` | `qase_get` with `entity="run"` | — |
64
+ | `create_run` | `qase_run_upsert` (omit `id`) | Or use `qase_ci_report` / `qase_regression_run` composites |
65
+ | `delete_run` | `qase_run_delete` | — |
66
+ | `complete_run` | `qase_run_complete` | — |
67
+ | `get_run_public_link` | `qase_api` | Use escape hatch: `GET /run/{code}/{id}/public-link` |
68
+ | `delete_run_public_link` | `qase_api` | Use escape hatch: `DELETE /run/{code}/{id}/public-link` |
69
+
70
+ ### Test Results
71
+
72
+ | v1 tool | v2 equivalent | Notes |
73
+ |---|---|---|
74
+ | `list_results` | `qql_search` with `entity="result"` | — |
75
+ | `get_result` | `qase_get` with `entity="result"` | — |
76
+ | `create_result` | `qase_result_record` | Accepts single result or array via `results` |
77
+ | `create_results_bulk` | `qase_result_record` | Same tool handles bulk via `results` array |
78
+ | `update_result` | `qase_api` | Use escape hatch: `PATCH /result/{code}/{id}` |
79
+ | `delete_result` | `qase_result_delete` | — |
80
+
81
+ ### Test Plans
82
+
83
+ | v1 tool | v2 equivalent | Notes |
84
+ |---|---|---|
85
+ | `list_plans` | `qql_search` with `entity="plan"` | — |
86
+ | `get_plan` | `qase_get` with `entity="plan"` | — |
87
+ | `create_plan` | `qase_plan_upsert` (omit `id`) | — |
88
+ | `update_plan` | `qase_plan_upsert` (include `id`) | — |
89
+ | `delete_plan` | `qase_plan_delete` | — |
90
+
91
+ ### Defects
92
+
93
+ | v1 tool | v2 equivalent | Notes |
94
+ |---|---|---|
95
+ | `list_defects` | `qql_search` with `entity="defect"` | — |
96
+ | `get_defect` | `qase_get` with `entity="defect"` | — |
97
+ | `create_defect` | `qase_defect_upsert` (omit `id`) | Or use `qase_triage_defect` composite |
98
+ | `update_defect` | `qase_defect_upsert` (include `id`) | — |
99
+ | `delete_defect` | `qase_defect_delete` | — |
100
+ | `resolve_defect` | `qase_defect_upsert` with `status="resolved"` | Pass `id` + `status` field |
101
+ | `update_defect_status` | `qase_defect_upsert` with `status` field | Pass `id` + desired `status` |
102
+
103
+ ### Milestones
104
+
105
+ | v1 tool | v2 equivalent | Notes |
106
+ |---|---|---|
107
+ | `list_milestones` | `qase_project_context` | Milestones are included in context response |
108
+ | `get_milestone` | `qase_get` with `entity="milestone"` | — |
109
+ | `create_milestone` | `qase_milestone_upsert` (omit `id`) | — |
110
+ | `update_milestone` | `qase_milestone_upsert` (include `id`) | — |
111
+ | `delete_milestone` | `qase_milestone_delete` | — |
112
+
113
+ ### Environments
114
+
115
+ | v1 tool | v2 equivalent | Notes |
116
+ |---|---|---|
117
+ | `list_environments` | `qase_project_context` | Environments are included in context response |
118
+ | `get_environment` | `qase_get` with `entity="environment"` | — |
119
+ | `create_environment` | `qase_environment_upsert` (omit `id`) | — |
120
+ | `update_environment` | `qase_environment_upsert` (include `id`) | — |
121
+ | `delete_environment` | `qase_environment_delete` | — |
122
+
123
+ ### Shared Steps
124
+
125
+ | v1 tool | v2 equivalent | Notes |
126
+ |---|---|---|
127
+ | `list_shared_steps` | `qql_search` with `entity="shared_step"` | — |
128
+ | `get_shared_step` | `qase_get` with `entity="shared_step"` | — |
129
+ | `create_shared_step` | `qase_shared_step_upsert` (omit `id`) | — |
130
+ | `update_shared_step` | `qase_shared_step_upsert` (include `id`) | — |
131
+ | `delete_shared_step` | `qase_shared_step_delete` | — |
132
+
133
+ ### Shared Parameters
134
+
135
+ | v1 tool | v2 equivalent | Notes |
136
+ |---|---|---|
137
+ | `list_shared_parameters` | `qql_search` with `entity="shared_parameter"` | — |
138
+ | `get_shared_parameter` | `qase_get` with `entity="shared_parameter"` | No `code` required |
139
+
140
+ ### Attachments
141
+
142
+ | v1 tool | v2 equivalent | Notes |
143
+ |---|---|---|
144
+ | `list_attachments` | `qase_api` | Use escape hatch: `GET /attachment` |
145
+ | `get_attachment` | `qase_get` with `entity="attachment"` | Pass hash as `id` |
146
+ | `upload_attachment` | `qase_attachment_upload` | — |
147
+ | `delete_attachment` | `qase_attachment_delete` | — |
148
+
149
+ ### Authors
150
+
151
+ | v1 tool | v2 equivalent | Notes |
152
+ |---|---|---|
153
+ | `list_authors` | `qase_api` | Use escape hatch: `GET /author` |
154
+ | `get_author` | `qase_get` with `entity="author"` | — |
155
+
156
+ ### Custom Fields
157
+
158
+ | v1 tool | v2 equivalent | Notes |
159
+ |---|---|---|
160
+ | `list_custom_fields` | `qase_project_context` | Custom fields are included in context response |
161
+ | `get_custom_field` | `qase_get` with `entity="custom_field"` | — |
162
+ | `create_custom_field` | `qase_api` | Use escape hatch: `POST /custom-field` |
163
+ | `update_custom_field` | `qase_api` | Use escape hatch: `PATCH /custom-field/{id}` |
164
+ | `delete_custom_field` | `qase_api` | Use escape hatch: `DELETE /custom-field/{id}` |
165
+
166
+ ### System Fields
167
+
168
+ | v1 tool | v2 equivalent | Notes |
169
+ |---|---|---|
170
+ | `list_system_fields` | `qase_api` | Use escape hatch: `GET /system-field` |
171
+
172
+ ### Configurations
173
+
174
+ | v1 tool | v2 equivalent | Notes |
175
+ |---|---|---|
176
+ | `list_configurations` | `qase_get` with `entity="configuration"` | Returns all config groups for a project |
177
+ | `create_configuration_group` | `qase_api` | Use escape hatch: `POST /configuration/{code}` |
178
+ | `delete_configuration_group` | `qase_api` | Use escape hatch: `DELETE /configuration/{code}/{id}` |
179
+
180
+ ### Users
181
+
182
+ | v1 tool | v2 equivalent | Notes |
183
+ |---|---|---|
184
+ | `list_users` | `qase_project_context` | Users are included in context response |
185
+ | `get_user` | `qase_get` with `entity="user"` | — |
186
+
187
+ ### QQL Search
188
+
189
+ | v1 tool | v2 equivalent | Notes |
190
+ |---|---|---|
191
+ | `qql_search` | `qql_search` | Unchanged — same tool, same interface |
192
+ | `qql_help` | `qql_help` | Unchanged — same tool, same interface |
193
+
194
+ ---
195
+
196
+ ## Response format changes
197
+
198
+ In v1, responses were pretty-printed JSON with `null` values included:
199
+
200
+ ```json
201
+ {
202
+ "id": 42,
203
+ "title": "Login test",
204
+ "description": null,
205
+ "preconditions": null,
206
+ "priority": 2
207
+ }
208
+ ```
209
+
210
+ In v2, responses are compact JSON with `null` values stripped:
211
+
212
+ ```json
213
+ {"id":42,"title":"Login test","priority":2}
214
+ ```
215
+
216
+ This reduces token usage significantly on large result sets. If your workflow parses response strings directly rather than using structured tool output, update your parsing logic accordingly.
217
+
218
+ Additionally, `qase_get` supports **field projection** via the `fields` parameter:
219
+
220
+ ```json
221
+ { "entity": "case", "code": "MYPROJECT", "id": 42, "fields": ["id", "title", "status"] }
222
+ ```
223
+
224
+ Pass `["*"]` to get all fields.
225
+
226
+ ---
227
+
228
+ ## New composite tools
229
+
230
+ These tools combine multiple API calls into a single operation, reducing round-trips and LLM context usage.
231
+
232
+ ### `qase_ci_report`
233
+
234
+ Replaces the 3–4 step workflow of `create_run → create_results_bulk → complete_run`.
235
+
236
+ Accepts a project code, run title, and an array of test results. Creates the run, records all results, and optionally completes it in one call.
237
+
238
+ ### `qase_triage_defect`
239
+
240
+ Streamlines the defect triage workflow. Creates a defect from a test failure description and optionally links it to failed result hashes from a run.
241
+
242
+ Replaces: `create_defect` (then manual linking).
243
+
244
+ ### `qase_regression_run`
245
+
246
+ Sets up a regression test run in one call. Accepts case selection by suite IDs, explicit case IDs, or plan ID. Creates the run and populates it with all matching cases.
247
+
248
+ Replaces: `list_cases` (per suite) → `create_run` → manually adding cases.
249
+
250
+ ---
251
+
252
+ ## Before / after examples
253
+
254
+ ### Example 1: Report CI results
255
+
256
+ **v1 (3 calls)**
257
+
258
+ ```
259
+ 1. create_run { code: "PROJ", title: "CI Build #42", cases: [101, 102, 103] }
260
+ → { id: 7 }
261
+
262
+ 2. create_results_bulk { code: "PROJ", id: 7, results: [...] }
263
+
264
+ 3. complete_run { code: "PROJ", id: 7 }
265
+ ```
266
+
267
+ **v2 (1 call)**
268
+
269
+ ```
270
+ qase_ci_report {
271
+ code: "PROJ",
272
+ title: "CI Build #42",
273
+ results: [
274
+ { case_id: 101, status: "passed", time_ms: 1200 },
275
+ { case_id: 102, status: "failed", stacktrace: "AssertionError..." },
276
+ { case_id: 103, status: "skipped" }
277
+ ]
278
+ }
279
+ → { run_id: 7, run_status: "complete", results_recorded: 3 }
280
+ ```
281
+
282
+ ---
283
+
284
+ ### Example 2: Get project metadata before creating a test case
285
+
286
+ **v1 (up to 6 calls)**
287
+
288
+ ```
289
+ 1. list_suites { code: "PROJ" }
290
+ 2. list_milestones { code: "PROJ" }
291
+ 3. list_environments { code: "PROJ" }
292
+ 4. list_custom_fields {}
293
+ 5. list_users {}
294
+ 6. get_project { code: "PROJ" }
295
+ ```
296
+
297
+ **v2 (1 call)**
298
+
299
+ ```
300
+ qase_project_context { code: "PROJ" }
301
+ → {
302
+ project: { ... },
303
+ suites: { entities: [...] },
304
+ milestones: { entities: [...] },
305
+ environments: { entities: [...] },
306
+ custom_fields: { entities: [...] },
307
+ users: { entities: [...] }
308
+ }
309
+ ```
310
+
311
+ Result is cached for 5 minutes — subsequent calls within the same session return instantly.
312
+
313
+ ---
314
+
315
+ ### Example 3: Create or update a test case
316
+
317
+ **v1 (separate tools for create vs update)**
318
+
319
+ ```
320
+ # Create:
321
+ create_case { code: "PROJ", title: "Login happy path", priority: "high" }
322
+
323
+ # Update:
324
+ update_case { code: "PROJ", id: 55, title: "Login happy path v2" }
325
+ ```
326
+
327
+ **v2 (single upsert tool)**
328
+
329
+ ```
330
+ # Create (no id):
331
+ qase_case_upsert { code: "PROJ", title: "Login happy path", priority: "high" }
332
+
333
+ # Update (with id):
334
+ qase_case_upsert { code: "PROJ", id: 55, title: "Login happy path v2" }
335
+ ```
336
+
337
+ ---
338
+
339
+ ## Escape hatch for unsupported operations
340
+
341
+ For v1 operations that have no direct v2 equivalent (project management, configuration groups, system fields, etc.), use `qase_api`:
342
+
343
+ ```
344
+ qase_api {
345
+ method: "GET",
346
+ path: "/system-field",
347
+ query: {}
348
+ }
349
+ ```
350
+
351
+ This gives direct access to any Qase REST API endpoint. See the `qase_api` tool description for full parameter documentation.