@@ -21,9 +21,11 @@ import {
2121 parseCompletionShell ,
2222 registerCompletionOption ,
2323 renderCompletion ,
24+ renderZsh ,
2425 type CompletionShell ,
2526} from "../src/completion.js" ;
2627import { ONE_SHOT_METHODS } from "@inspector/core/cli/handlers/method-types.js" ;
28+ import { CATALOG_WRITE_METHODS } from "../src/handlers/servers-write.js" ;
2729
2830async function script ( shell : CompletionShell ) : Promise < string > {
2931 const result = await runCli ( [ "--completion" , shell ] ) ;
@@ -94,6 +96,28 @@ describe("--completion", () => {
9496 expect ( out ) . toContain ( method ) ;
9597 }
9698 } ) ;
99+
100+ it ( "offers the catalog write methods the CLI implements (#2629)" , async ( ) => {
101+ // Read from servers-write itself, not from CATALOG_METHODS, so a write
102+ // method the completion list forgets fails here.
103+ expect ( CATALOG_METHODS ) . toEqual (
104+ expect . arrayContaining ( [ ...CATALOG_WRITE_METHODS ] ) ,
105+ ) ;
106+ const out = await script ( "bash" ) ;
107+ for ( const method of CATALOG_WRITE_METHODS ) {
108+ expect ( out ) . toContain ( method ) ;
109+ }
110+ } ) ;
111+
112+ it ( "offers no --method the CLI would reject as unsupported" , async ( ) => {
113+ for ( const method of VALUE_CHOICES [ "--method" ] ! ) {
114+ const result = await runCli ( [ "--method" , method ] ) ;
115+ expect ( result . stderr , method ) . not . toContain ( "Unsupported method" ) ;
116+ }
117+ // Control: an unknown method is rejected by the same check.
118+ const bogus = await runCli ( [ "--method" , "servers/bogus" ] ) ;
119+ expect ( bogus . stderr ) . toContain ( "Unsupported method: servers/bogus" ) ;
120+ } ) ;
97121} ) ;
98122
99123describe ( "collectCompletionFlags" , ( ) => {
@@ -162,6 +186,14 @@ describe("collectCompletionFlags", () => {
162186} ) ;
163187
164188describe ( "shell helpers" , ( ) => {
189+ it ( "escapes backslashes before colons in a zsh _describe name (CodeQL #78)" , ( ) => {
190+ const out = renderZsh ( [
191+ { long : "--a\\b:c" , takesValue : false , description : "Desc" } ,
192+ ] ) ;
193+ // Name --a\b:c → --a\\b\:c, then ":" and the description.
194+ expect ( out ) . toContain ( "'--a\\\\b\\:c:Desc'" ) ;
195+ } ) ;
196+
165197 it ( "parseCompletionShell / isCompletionShell" , ( ) => {
166198 expect ( isCompletionShell ( "zsh" ) ) . toBe ( true ) ;
167199 expect ( isCompletionShell ( "csh" ) ) . toBe ( false ) ;
@@ -227,6 +259,18 @@ describe.skipIf(!hasShell("bash"))("bash script", () => {
227259 expect (
228260 await complete ( [ "mcp-inspector" , "--cli" , "--transport" , "" ] ) ,
229261 ) . toEqual ( [ "stdio" , "sse" , "http" ] ) ;
262+ expect (
263+ await complete ( [ "mcp-inspector" , "--cli" , "--method" , "servers/" ] ) ,
264+ ) . toEqual ( [
265+ "servers/list" ,
266+ "servers/show" ,
267+ "servers/add" ,
268+ "servers/edit" ,
269+ "servers/remove" ,
270+ ] ) ;
271+ expect (
272+ await complete ( [ "mcp-inspector" , "--cli" , "--output-format" , "" ] ) ,
273+ ) . toEqual ( [ "raw" , "json" ] ) ;
230274 // A free-form value offers nothing (the shell falls back to files).
231275 expect (
232276 await complete ( [ "mcp-inspector" , "--cli" , "--tool-name" , "--" ] ) ,
0 commit comments