mcp-server-verify 1.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.
- package/README.md +586 -0
- package/dist/cli.cjs +748 -0
- package/package.json +46 -0
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,748 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";var qr=Object.create;var ge=Object.defineProperty;var zr=Object.getOwnPropertyDescriptor;var Wr=Object.getOwnPropertyNames;var Ur=Object.getPrototypeOf,Br=Object.prototype.hasOwnProperty;var Gr=(n,e)=>()=>(n&&(e=n(n=0)),e);var z=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports),Bt=(n,e)=>{for(var t in e)ge(n,t,{get:e[t],enumerable:!0})},Gt=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Wr(e))!Br.call(n,o)&&o!==t&&ge(n,o,{get:()=>e[o],enumerable:!(r=zr(e,o))||r.enumerable});return n};var $e=(n,e,t)=>(t=n!=null?qr(Ur(n)):{},Gt(e||!n||!n.__esModule?ge(t,"default",{value:n,enumerable:!0}):t,n)),Yr=n=>Gt(ge({},"__esModule",{value:!0}),n);var se=z(Ae=>{"use strict";var ye=class extends Error{constructor(e,t,r){super(r),Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.code=t,this.exitCode=e,this.nestedError=void 0}},_e=class extends ye{constructor(e){super(1,"commander.invalidArgument",e),Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name}};Ae.CommanderError=ye;Ae.InvalidArgumentError=_e});var ve=z(Ne=>{"use strict";var{InvalidArgumentError:Kr}=se(),Ie=class{constructor(e,t){switch(this.description=t||"",this.variadic=!1,this.parseArg=void 0,this.defaultValue=void 0,this.defaultValueDescription=void 0,this.argChoices=void 0,e[0]){case"<":this.required=!0,this._name=e.slice(1,-1);break;case"[":this.required=!1,this._name=e.slice(1,-1);break;default:this.required=!0,this._name=e;break}this._name.length>3&&this._name.slice(-3)==="..."&&(this.variadic=!0,this._name=this._name.slice(0,-3))}name(){return this._name}_concatValue(e,t){return t===this.defaultValue||!Array.isArray(t)?[e]:t.concat(e)}default(e,t){return this.defaultValue=e,this.defaultValueDescription=t,this}argParser(e){return this.parseArg=e,this}choices(e){return this.argChoices=e.slice(),this.parseArg=(t,r)=>{if(!this.argChoices.includes(t))throw new Kr(`Allowed choices are ${this.argChoices.join(", ")}.`);return this.variadic?this._concatValue(t,r):t},this}argRequired(){return this.required=!0,this}argOptional(){return this.required=!1,this}};function Xr(n){let e=n.name()+(n.variadic===!0?"...":"");return n.required?"<"+e+">":"["+e+"]"}Ne.Argument=Ie;Ne.humanReadableArgName=Xr});var je=z(Yt=>{"use strict";var{humanReadableArgName:Zr}=ve(),Ve=class{constructor(){this.helpWidth=void 0,this.sortSubcommands=!1,this.sortOptions=!1,this.showGlobalOptions=!1}visibleCommands(e){let t=e.commands.filter(o=>!o._hidden),r=e._getHelpCommand();return r&&!r._hidden&&t.push(r),this.sortSubcommands&&t.sort((o,s)=>o.name().localeCompare(s.name())),t}compareOptions(e,t){let r=o=>o.short?o.short.replace(/^-/,""):o.long.replace(/^--/,"");return r(e).localeCompare(r(t))}visibleOptions(e){let t=e.options.filter(o=>!o.hidden),r=e._getHelpOption();if(r&&!r.hidden){let o=r.short&&e._findOption(r.short),s=r.long&&e._findOption(r.long);!o&&!s?t.push(r):r.long&&!s?t.push(e.createOption(r.long,r.description)):r.short&&!o&&t.push(e.createOption(r.short,r.description))}return this.sortOptions&&t.sort(this.compareOptions),t}visibleGlobalOptions(e){if(!this.showGlobalOptions)return[];let t=[];for(let r=e.parent;r;r=r.parent){let o=r.options.filter(s=>!s.hidden);t.push(...o)}return this.sortOptions&&t.sort(this.compareOptions),t}visibleArguments(e){return e._argsDescription&&e.registeredArguments.forEach(t=>{t.description=t.description||e._argsDescription[t.name()]||""}),e.registeredArguments.find(t=>t.description)?e.registeredArguments:[]}subcommandTerm(e){let t=e.registeredArguments.map(r=>Zr(r)).join(" ");return e._name+(e._aliases[0]?"|"+e._aliases[0]:"")+(e.options.length?" [options]":"")+(t?" "+t:"")}optionTerm(e){return e.flags}argumentTerm(e){return e.name()}longestSubcommandTermLength(e,t){return t.visibleCommands(e).reduce((r,o)=>Math.max(r,t.subcommandTerm(o).length),0)}longestOptionTermLength(e,t){return t.visibleOptions(e).reduce((r,o)=>Math.max(r,t.optionTerm(o).length),0)}longestGlobalOptionTermLength(e,t){return t.visibleGlobalOptions(e).reduce((r,o)=>Math.max(r,t.optionTerm(o).length),0)}longestArgumentTermLength(e,t){return t.visibleArguments(e).reduce((r,o)=>Math.max(r,t.argumentTerm(o).length),0)}commandUsage(e){let t=e._name;e._aliases[0]&&(t=t+"|"+e._aliases[0]);let r="";for(let o=e.parent;o;o=o.parent)r=o.name()+" "+r;return r+t+" "+e.usage()}commandDescription(e){return e.description()}subcommandDescription(e){return e.summary()||e.description()}optionDescription(e){let t=[];return e.argChoices&&t.push(`choices: ${e.argChoices.map(r=>JSON.stringify(r)).join(", ")}`),e.defaultValue!==void 0&&(e.required||e.optional||e.isBoolean()&&typeof e.defaultValue=="boolean")&&t.push(`default: ${e.defaultValueDescription||JSON.stringify(e.defaultValue)}`),e.presetArg!==void 0&&e.optional&&t.push(`preset: ${JSON.stringify(e.presetArg)}`),e.envVar!==void 0&&t.push(`env: ${e.envVar}`),t.length>0?`${e.description} (${t.join(", ")})`:e.description}argumentDescription(e){let t=[];if(e.argChoices&&t.push(`choices: ${e.argChoices.map(r=>JSON.stringify(r)).join(", ")}`),e.defaultValue!==void 0&&t.push(`default: ${e.defaultValueDescription||JSON.stringify(e.defaultValue)}`),t.length>0){let r=`(${t.join(", ")})`;return e.description?`${e.description} ${r}`:r}return e.description}formatHelp(e,t){let r=t.padWidth(e,t),o=t.helpWidth||80,s=2,i=2;function c(f,h){if(h){let y=`${f.padEnd(r+i)}${h}`;return t.wrap(y,o-s,r+i)}return f}function a(f){return f.join(`
|
|
3
|
+
`).replace(/^/gm," ".repeat(s))}let l=[`Usage: ${t.commandUsage(e)}`,""],p=t.commandDescription(e);p.length>0&&(l=l.concat([t.wrap(p,o,0),""]));let u=t.visibleArguments(e).map(f=>c(t.argumentTerm(f),t.argumentDescription(f)));u.length>0&&(l=l.concat(["Arguments:",a(u),""]));let d=t.visibleOptions(e).map(f=>c(t.optionTerm(f),t.optionDescription(f)));if(d.length>0&&(l=l.concat(["Options:",a(d),""])),this.showGlobalOptions){let f=t.visibleGlobalOptions(e).map(h=>c(t.optionTerm(h),t.optionDescription(h)));f.length>0&&(l=l.concat(["Global Options:",a(f),""]))}let m=t.visibleCommands(e).map(f=>c(t.subcommandTerm(f),t.subcommandDescription(f)));return m.length>0&&(l=l.concat(["Commands:",a(m),""])),l.join(`
|
|
4
|
+
`)}padWidth(e,t){return Math.max(t.longestOptionTermLength(e,t),t.longestGlobalOptionTermLength(e,t),t.longestSubcommandTermLength(e,t),t.longestArgumentTermLength(e,t))}wrap(e,t,r,o=40){let s=" \\f\\t\\v\xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF",i=new RegExp(`[\\n][${s}]+`);if(e.match(i))return e;let c=t-r;if(c<o)return e;let a=e.slice(0,r),l=e.slice(r).replace(`\r
|
|
5
|
+
`,`
|
|
6
|
+
`),p=" ".repeat(r),d="\\s\u200B",m=new RegExp(`
|
|
7
|
+
|.{1,${c-1}}([${d}]|$)|[^${d}]+?([${d}]|$)`,"g"),f=l.match(m)||[];return a+f.map((h,y)=>h===`
|
|
8
|
+
`?"":(y>0?p:"")+h.trimEnd()).join(`
|
|
9
|
+
`)}};Yt.Help=Ve});var De=z(Le=>{"use strict";var{InvalidArgumentError:Qr}=se(),Me=class{constructor(e,t){this.flags=e,this.description=t||"",this.required=e.includes("<"),this.optional=e.includes("["),this.variadic=/\w\.\.\.[>\]]$/.test(e),this.mandatory=!1;let r=tn(e);this.short=r.shortFlag,this.long=r.longFlag,this.negate=!1,this.long&&(this.negate=this.long.startsWith("--no-")),this.defaultValue=void 0,this.defaultValueDescription=void 0,this.presetArg=void 0,this.envVar=void 0,this.parseArg=void 0,this.hidden=!1,this.argChoices=void 0,this.conflictsWith=[],this.implied=void 0}default(e,t){return this.defaultValue=e,this.defaultValueDescription=t,this}preset(e){return this.presetArg=e,this}conflicts(e){return this.conflictsWith=this.conflictsWith.concat(e),this}implies(e){let t=e;return typeof e=="string"&&(t={[e]:!0}),this.implied=Object.assign(this.implied||{},t),this}env(e){return this.envVar=e,this}argParser(e){return this.parseArg=e,this}makeOptionMandatory(e=!0){return this.mandatory=!!e,this}hideHelp(e=!0){return this.hidden=!!e,this}_concatValue(e,t){return t===this.defaultValue||!Array.isArray(t)?[e]:t.concat(e)}choices(e){return this.argChoices=e.slice(),this.parseArg=(t,r)=>{if(!this.argChoices.includes(t))throw new Qr(`Allowed choices are ${this.argChoices.join(", ")}.`);return this.variadic?this._concatValue(t,r):t},this}name(){return this.long?this.long.replace(/^--/,""):this.short.replace(/^-/,"")}attributeName(){return en(this.name().replace(/^no-/,""))}is(e){return this.short===e||this.long===e}isBoolean(){return!this.required&&!this.optional&&!this.negate}},He=class{constructor(e){this.positiveOptions=new Map,this.negativeOptions=new Map,this.dualOptions=new Set,e.forEach(t=>{t.negate?this.negativeOptions.set(t.attributeName(),t):this.positiveOptions.set(t.attributeName(),t)}),this.negativeOptions.forEach((t,r)=>{this.positiveOptions.has(r)&&this.dualOptions.add(r)})}valueFromOption(e,t){let r=t.attributeName();if(!this.dualOptions.has(r))return!0;let o=this.negativeOptions.get(r).presetArg,s=o!==void 0?o:!1;return t.negate===(s===e)}};function en(n){return n.split("-").reduce((e,t)=>e+t[0].toUpperCase()+t.slice(1))}function tn(n){let e,t,r=n.split(/[ |,]+/);return r.length>1&&!/^[[<]/.test(r[1])&&(e=r.shift()),t=r.shift(),!e&&/^-[^-]$/.test(t)&&(e=t,t=void 0),{shortFlag:e,longFlag:t}}Le.Option=Me;Le.DualOptions=He});var Xt=z(Kt=>{"use strict";function rn(n,e){if(Math.abs(n.length-e.length)>3)return Math.max(n.length,e.length);let t=[];for(let r=0;r<=n.length;r++)t[r]=[r];for(let r=0;r<=e.length;r++)t[0][r]=r;for(let r=1;r<=e.length;r++)for(let o=1;o<=n.length;o++){let s=1;n[o-1]===e[r-1]?s=0:s=1,t[o][r]=Math.min(t[o-1][r]+1,t[o][r-1]+1,t[o-1][r-1]+s),o>1&&r>1&&n[o-1]===e[r-2]&&n[o-2]===e[r-1]&&(t[o][r]=Math.min(t[o][r],t[o-2][r-2]+1))}return t[n.length][e.length]}function nn(n,e){if(!e||e.length===0)return"";e=Array.from(new Set(e));let t=n.startsWith("--");t&&(n=n.slice(2),e=e.map(i=>i.slice(2)));let r=[],o=3,s=.4;return e.forEach(i=>{if(i.length<=1)return;let c=rn(n,i),a=Math.max(n.length,i.length);(a-c)/a>s&&(c<o?(o=c,r=[i]):c===o&&r.push(i))}),r.sort((i,c)=>i.localeCompare(c)),t&&(r=r.map(i=>`--${i}`)),r.length>1?`
|
|
10
|
+
(Did you mean one of ${r.join(", ")}?)`:r.length===1?`
|
|
11
|
+
(Did you mean ${r[0]}?)`:""}Kt.suggestSimilar=nn});var rr=z(tr=>{"use strict";var on=require("events").EventEmitter,Fe=require("child_process"),L=require("path"),Je=require("fs"),w=require("process"),{Argument:sn,humanReadableArgName:an}=ve(),{CommanderError:qe}=se(),{Help:cn}=je(),{Option:Zt,DualOptions:ln}=De(),{suggestSimilar:Qt}=Xt(),ze=class n extends on{constructor(e){super(),this.commands=[],this.options=[],this.parent=null,this._allowUnknownOption=!1,this._allowExcessArguments=!0,this.registeredArguments=[],this._args=this.registeredArguments,this.args=[],this.rawArgs=[],this.processedArgs=[],this._scriptPath=null,this._name=e||"",this._optionValues={},this._optionValueSources={},this._storeOptionsAsProperties=!1,this._actionHandler=null,this._executableHandler=!1,this._executableFile=null,this._executableDir=null,this._defaultCommandName=null,this._exitCallback=null,this._aliases=[],this._combineFlagAndOptionalValue=!0,this._description="",this._summary="",this._argsDescription=void 0,this._enablePositionalOptions=!1,this._passThroughOptions=!1,this._lifeCycleHooks={},this._showHelpAfterError=!1,this._showSuggestionAfterError=!0,this._outputConfiguration={writeOut:t=>w.stdout.write(t),writeErr:t=>w.stderr.write(t),getOutHelpWidth:()=>w.stdout.isTTY?w.stdout.columns:void 0,getErrHelpWidth:()=>w.stderr.isTTY?w.stderr.columns:void 0,outputError:(t,r)=>r(t)},this._hidden=!1,this._helpOption=void 0,this._addImplicitHelpCommand=void 0,this._helpCommand=void 0,this._helpConfiguration={}}copyInheritedSettings(e){return this._outputConfiguration=e._outputConfiguration,this._helpOption=e._helpOption,this._helpCommand=e._helpCommand,this._helpConfiguration=e._helpConfiguration,this._exitCallback=e._exitCallback,this._storeOptionsAsProperties=e._storeOptionsAsProperties,this._combineFlagAndOptionalValue=e._combineFlagAndOptionalValue,this._allowExcessArguments=e._allowExcessArguments,this._enablePositionalOptions=e._enablePositionalOptions,this._showHelpAfterError=e._showHelpAfterError,this._showSuggestionAfterError=e._showSuggestionAfterError,this}_getCommandAndAncestors(){let e=[];for(let t=this;t;t=t.parent)e.push(t);return e}command(e,t,r){let o=t,s=r;typeof o=="object"&&o!==null&&(s=o,o=null),s=s||{};let[,i,c]=e.match(/([^ ]+) *(.*)/),a=this.createCommand(i);return o&&(a.description(o),a._executableHandler=!0),s.isDefault&&(this._defaultCommandName=a._name),a._hidden=!!(s.noHelp||s.hidden),a._executableFile=s.executableFile||null,c&&a.arguments(c),this._registerCommand(a),a.parent=this,a.copyInheritedSettings(this),o?this:a}createCommand(e){return new n(e)}createHelp(){return Object.assign(new cn,this.configureHelp())}configureHelp(e){return e===void 0?this._helpConfiguration:(this._helpConfiguration=e,this)}configureOutput(e){return e===void 0?this._outputConfiguration:(Object.assign(this._outputConfiguration,e),this)}showHelpAfterError(e=!0){return typeof e!="string"&&(e=!!e),this._showHelpAfterError=e,this}showSuggestionAfterError(e=!0){return this._showSuggestionAfterError=!!e,this}addCommand(e,t){if(!e._name)throw new Error(`Command passed to .addCommand() must have a name
|
|
12
|
+
- specify the name in Command constructor or using .name()`);return t=t||{},t.isDefault&&(this._defaultCommandName=e._name),(t.noHelp||t.hidden)&&(e._hidden=!0),this._registerCommand(e),e.parent=this,e._checkForBrokenPassThrough(),this}createArgument(e,t){return new sn(e,t)}argument(e,t,r,o){let s=this.createArgument(e,t);return typeof r=="function"?s.default(o).argParser(r):s.default(r),this.addArgument(s),this}arguments(e){return e.trim().split(/ +/).forEach(t=>{this.argument(t)}),this}addArgument(e){let t=this.registeredArguments.slice(-1)[0];if(t&&t.variadic)throw new Error(`only the last argument can be variadic '${t.name()}'`);if(e.required&&e.defaultValue!==void 0&&e.parseArg===void 0)throw new Error(`a default value for a required argument is never used: '${e.name()}'`);return this.registeredArguments.push(e),this}helpCommand(e,t){if(typeof e=="boolean")return this._addImplicitHelpCommand=e,this;e=e??"help [command]";let[,r,o]=e.match(/([^ ]+) *(.*)/),s=t??"display help for command",i=this.createCommand(r);return i.helpOption(!1),o&&i.arguments(o),s&&i.description(s),this._addImplicitHelpCommand=!0,this._helpCommand=i,this}addHelpCommand(e,t){return typeof e!="object"?(this.helpCommand(e,t),this):(this._addImplicitHelpCommand=!0,this._helpCommand=e,this)}_getHelpCommand(){return this._addImplicitHelpCommand??(this.commands.length&&!this._actionHandler&&!this._findCommand("help"))?(this._helpCommand===void 0&&this.helpCommand(void 0,void 0),this._helpCommand):null}hook(e,t){let r=["preSubcommand","preAction","postAction"];if(!r.includes(e))throw new Error(`Unexpected value for event passed to hook : '${e}'.
|
|
13
|
+
Expecting one of '${r.join("', '")}'`);return this._lifeCycleHooks[e]?this._lifeCycleHooks[e].push(t):this._lifeCycleHooks[e]=[t],this}exitOverride(e){return e?this._exitCallback=e:this._exitCallback=t=>{if(t.code!=="commander.executeSubCommandAsync")throw t},this}_exit(e,t,r){this._exitCallback&&this._exitCallback(new qe(e,t,r)),w.exit(e)}action(e){let t=r=>{let o=this.registeredArguments.length,s=r.slice(0,o);return this._storeOptionsAsProperties?s[o]=this:s[o]=this.opts(),s.push(this),e.apply(this,s)};return this._actionHandler=t,this}createOption(e,t){return new Zt(e,t)}_callParseArg(e,t,r,o){try{return e.parseArg(t,r)}catch(s){if(s.code==="commander.invalidArgument"){let i=`${o} ${s.message}`;this.error(i,{exitCode:s.exitCode,code:s.code})}throw s}}_registerOption(e){let t=e.short&&this._findOption(e.short)||e.long&&this._findOption(e.long);if(t){let r=e.long&&this._findOption(e.long)?e.long:e.short;throw new Error(`Cannot add option '${e.flags}'${this._name&&` to command '${this._name}'`} due to conflicting flag '${r}'
|
|
14
|
+
- already used by option '${t.flags}'`)}this.options.push(e)}_registerCommand(e){let t=o=>[o.name()].concat(o.aliases()),r=t(e).find(o=>this._findCommand(o));if(r){let o=t(this._findCommand(r)).join("|"),s=t(e).join("|");throw new Error(`cannot add command '${s}' as already have command '${o}'`)}this.commands.push(e)}addOption(e){this._registerOption(e);let t=e.name(),r=e.attributeName();if(e.negate){let s=e.long.replace(/^--no-/,"--");this._findOption(s)||this.setOptionValueWithSource(r,e.defaultValue===void 0?!0:e.defaultValue,"default")}else e.defaultValue!==void 0&&this.setOptionValueWithSource(r,e.defaultValue,"default");let o=(s,i,c)=>{s==null&&e.presetArg!==void 0&&(s=e.presetArg);let a=this.getOptionValue(r);s!==null&&e.parseArg?s=this._callParseArg(e,s,a,i):s!==null&&e.variadic&&(s=e._concatValue(s,a)),s==null&&(e.negate?s=!1:e.isBoolean()||e.optional?s=!0:s=""),this.setOptionValueWithSource(r,s,c)};return this.on("option:"+t,s=>{let i=`error: option '${e.flags}' argument '${s}' is invalid.`;o(s,i,"cli")}),e.envVar&&this.on("optionEnv:"+t,s=>{let i=`error: option '${e.flags}' value '${s}' from env '${e.envVar}' is invalid.`;o(s,i,"env")}),this}_optionEx(e,t,r,o,s){if(typeof t=="object"&&t instanceof Zt)throw new Error("To add an Option object use addOption() instead of option() or requiredOption()");let i=this.createOption(t,r);if(i.makeOptionMandatory(!!e.mandatory),typeof o=="function")i.default(s).argParser(o);else if(o instanceof RegExp){let c=o;o=(a,l)=>{let p=c.exec(a);return p?p[0]:l},i.default(s).argParser(o)}else i.default(o);return this.addOption(i)}option(e,t,r,o){return this._optionEx({},e,t,r,o)}requiredOption(e,t,r,o){return this._optionEx({mandatory:!0},e,t,r,o)}combineFlagAndOptionalValue(e=!0){return this._combineFlagAndOptionalValue=!!e,this}allowUnknownOption(e=!0){return this._allowUnknownOption=!!e,this}allowExcessArguments(e=!0){return this._allowExcessArguments=!!e,this}enablePositionalOptions(e=!0){return this._enablePositionalOptions=!!e,this}passThroughOptions(e=!0){return this._passThroughOptions=!!e,this._checkForBrokenPassThrough(),this}_checkForBrokenPassThrough(){if(this.parent&&this._passThroughOptions&&!this.parent._enablePositionalOptions)throw new Error(`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`)}storeOptionsAsProperties(e=!0){if(this.options.length)throw new Error("call .storeOptionsAsProperties() before adding options");if(Object.keys(this._optionValues).length)throw new Error("call .storeOptionsAsProperties() before setting option values");return this._storeOptionsAsProperties=!!e,this}getOptionValue(e){return this._storeOptionsAsProperties?this[e]:this._optionValues[e]}setOptionValue(e,t){return this.setOptionValueWithSource(e,t,void 0)}setOptionValueWithSource(e,t,r){return this._storeOptionsAsProperties?this[e]=t:this._optionValues[e]=t,this._optionValueSources[e]=r,this}getOptionValueSource(e){return this._optionValueSources[e]}getOptionValueSourceWithGlobals(e){let t;return this._getCommandAndAncestors().forEach(r=>{r.getOptionValueSource(e)!==void 0&&(t=r.getOptionValueSource(e))}),t}_prepareUserArgs(e,t){if(e!==void 0&&!Array.isArray(e))throw new Error("first parameter to parse must be array or undefined");if(t=t||{},e===void 0&&t.from===void 0){w.versions?.electron&&(t.from="electron");let o=w.execArgv??[];(o.includes("-e")||o.includes("--eval")||o.includes("-p")||o.includes("--print"))&&(t.from="eval")}e===void 0&&(e=w.argv),this.rawArgs=e.slice();let r;switch(t.from){case void 0:case"node":this._scriptPath=e[1],r=e.slice(2);break;case"electron":w.defaultApp?(this._scriptPath=e[1],r=e.slice(2)):r=e.slice(1);break;case"user":r=e.slice(0);break;case"eval":r=e.slice(1);break;default:throw new Error(`unexpected parse option { from: '${t.from}' }`)}return!this._name&&this._scriptPath&&this.nameFromFilename(this._scriptPath),this._name=this._name||"program",r}parse(e,t){let r=this._prepareUserArgs(e,t);return this._parseCommand([],r),this}async parseAsync(e,t){let r=this._prepareUserArgs(e,t);return await this._parseCommand([],r),this}_executeSubCommand(e,t){t=t.slice();let r=!1,o=[".js",".ts",".tsx",".mjs",".cjs"];function s(p,u){let d=L.resolve(p,u);if(Je.existsSync(d))return d;if(o.includes(L.extname(u)))return;let m=o.find(f=>Je.existsSync(`${d}${f}`));if(m)return`${d}${m}`}this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let i=e._executableFile||`${this._name}-${e._name}`,c=this._executableDir||"";if(this._scriptPath){let p;try{p=Je.realpathSync(this._scriptPath)}catch{p=this._scriptPath}c=L.resolve(L.dirname(p),c)}if(c){let p=s(c,i);if(!p&&!e._executableFile&&this._scriptPath){let u=L.basename(this._scriptPath,L.extname(this._scriptPath));u!==this._name&&(p=s(c,`${u}-${e._name}`))}i=p||i}r=o.includes(L.extname(i));let a;w.platform!=="win32"?r?(t.unshift(i),t=er(w.execArgv).concat(t),a=Fe.spawn(w.argv[0],t,{stdio:"inherit"})):a=Fe.spawn(i,t,{stdio:"inherit"}):(t.unshift(i),t=er(w.execArgv).concat(t),a=Fe.spawn(w.execPath,t,{stdio:"inherit"})),a.killed||["SIGUSR1","SIGUSR2","SIGTERM","SIGINT","SIGHUP"].forEach(u=>{w.on(u,()=>{a.killed===!1&&a.exitCode===null&&a.kill(u)})});let l=this._exitCallback;a.on("close",p=>{p=p??1,l?l(new qe(p,"commander.executeSubCommandAsync","(close)")):w.exit(p)}),a.on("error",p=>{if(p.code==="ENOENT"){let u=c?`searched for local subcommand relative to directory '${c}'`:"no directory for search for local subcommand, use .executableDir() to supply a custom directory",d=`'${i}' does not exist
|
|
15
|
+
- if '${e._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
|
|
16
|
+
- if the default executable name is not suitable, use the executableFile option to supply a custom name or path
|
|
17
|
+
- ${u}`;throw new Error(d)}else if(p.code==="EACCES")throw new Error(`'${i}' not executable`);if(!l)w.exit(1);else{let u=new qe(1,"commander.executeSubCommandAsync","(error)");u.nestedError=p,l(u)}}),this.runningCommand=a}_dispatchSubcommand(e,t,r){let o=this._findCommand(e);o||this.help({error:!0});let s;return s=this._chainOrCallSubCommandHook(s,o,"preSubcommand"),s=this._chainOrCall(s,()=>{if(o._executableHandler)this._executeSubCommand(o,t.concat(r));else return o._parseCommand(t,r)}),s}_dispatchHelpCommand(e){e||this.help();let t=this._findCommand(e);return t&&!t._executableHandler&&t.help(),this._dispatchSubcommand(e,[],[this._getHelpOption()?.long??this._getHelpOption()?.short??"--help"])}_checkNumberOfArguments(){this.registeredArguments.forEach((e,t)=>{e.required&&this.args[t]==null&&this.missingArgument(e.name())}),!(this.registeredArguments.length>0&&this.registeredArguments[this.registeredArguments.length-1].variadic)&&this.args.length>this.registeredArguments.length&&this._excessArguments(this.args)}_processArguments(){let e=(r,o,s)=>{let i=o;if(o!==null&&r.parseArg){let c=`error: command-argument value '${o}' is invalid for argument '${r.name()}'.`;i=this._callParseArg(r,o,s,c)}return i};this._checkNumberOfArguments();let t=[];this.registeredArguments.forEach((r,o)=>{let s=r.defaultValue;r.variadic?o<this.args.length?(s=this.args.slice(o),r.parseArg&&(s=s.reduce((i,c)=>e(r,c,i),r.defaultValue))):s===void 0&&(s=[]):o<this.args.length&&(s=this.args[o],r.parseArg&&(s=e(r,s,r.defaultValue))),t[o]=s}),this.processedArgs=t}_chainOrCall(e,t){return e&&e.then&&typeof e.then=="function"?e.then(()=>t()):t()}_chainOrCallHooks(e,t){let r=e,o=[];return this._getCommandAndAncestors().reverse().filter(s=>s._lifeCycleHooks[t]!==void 0).forEach(s=>{s._lifeCycleHooks[t].forEach(i=>{o.push({hookedCommand:s,callback:i})})}),t==="postAction"&&o.reverse(),o.forEach(s=>{r=this._chainOrCall(r,()=>s.callback(s.hookedCommand,this))}),r}_chainOrCallSubCommandHook(e,t,r){let o=e;return this._lifeCycleHooks[r]!==void 0&&this._lifeCycleHooks[r].forEach(s=>{o=this._chainOrCall(o,()=>s(this,t))}),o}_parseCommand(e,t){let r=this.parseOptions(t);if(this._parseOptionsEnv(),this._parseOptionsImplied(),e=e.concat(r.operands),t=r.unknown,this.args=e.concat(t),e&&this._findCommand(e[0]))return this._dispatchSubcommand(e[0],e.slice(1),t);if(this._getHelpCommand()&&e[0]===this._getHelpCommand().name())return this._dispatchHelpCommand(e[1]);if(this._defaultCommandName)return this._outputHelpIfRequested(t),this._dispatchSubcommand(this._defaultCommandName,e,t);this.commands.length&&this.args.length===0&&!this._actionHandler&&!this._defaultCommandName&&this.help({error:!0}),this._outputHelpIfRequested(r.unknown),this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let o=()=>{r.unknown.length>0&&this.unknownOption(r.unknown[0])},s=`command:${this.name()}`;if(this._actionHandler){o(),this._processArguments();let i;return i=this._chainOrCallHooks(i,"preAction"),i=this._chainOrCall(i,()=>this._actionHandler(this.processedArgs)),this.parent&&(i=this._chainOrCall(i,()=>{this.parent.emit(s,e,t)})),i=this._chainOrCallHooks(i,"postAction"),i}if(this.parent&&this.parent.listenerCount(s))o(),this._processArguments(),this.parent.emit(s,e,t);else if(e.length){if(this._findCommand("*"))return this._dispatchSubcommand("*",e,t);this.listenerCount("command:*")?this.emit("command:*",e,t):this.commands.length?this.unknownCommand():(o(),this._processArguments())}else this.commands.length?(o(),this.help({error:!0})):(o(),this._processArguments())}_findCommand(e){if(e)return this.commands.find(t=>t._name===e||t._aliases.includes(e))}_findOption(e){return this.options.find(t=>t.is(e))}_checkForMissingMandatoryOptions(){this._getCommandAndAncestors().forEach(e=>{e.options.forEach(t=>{t.mandatory&&e.getOptionValue(t.attributeName())===void 0&&e.missingMandatoryOptionValue(t)})})}_checkForConflictingLocalOptions(){let e=this.options.filter(r=>{let o=r.attributeName();return this.getOptionValue(o)===void 0?!1:this.getOptionValueSource(o)!=="default"});e.filter(r=>r.conflictsWith.length>0).forEach(r=>{let o=e.find(s=>r.conflictsWith.includes(s.attributeName()));o&&this._conflictingOption(r,o)})}_checkForConflictingOptions(){this._getCommandAndAncestors().forEach(e=>{e._checkForConflictingLocalOptions()})}parseOptions(e){let t=[],r=[],o=t,s=e.slice();function i(a){return a.length>1&&a[0]==="-"}let c=null;for(;s.length;){let a=s.shift();if(a==="--"){o===r&&o.push(a),o.push(...s);break}if(c&&!i(a)){this.emit(`option:${c.name()}`,a);continue}if(c=null,i(a)){let l=this._findOption(a);if(l){if(l.required){let p=s.shift();p===void 0&&this.optionMissingArgument(l),this.emit(`option:${l.name()}`,p)}else if(l.optional){let p=null;s.length>0&&!i(s[0])&&(p=s.shift()),this.emit(`option:${l.name()}`,p)}else this.emit(`option:${l.name()}`);c=l.variadic?l:null;continue}}if(a.length>2&&a[0]==="-"&&a[1]!=="-"){let l=this._findOption(`-${a[1]}`);if(l){l.required||l.optional&&this._combineFlagAndOptionalValue?this.emit(`option:${l.name()}`,a.slice(2)):(this.emit(`option:${l.name()}`),s.unshift(`-${a.slice(2)}`));continue}}if(/^--[^=]+=/.test(a)){let l=a.indexOf("="),p=this._findOption(a.slice(0,l));if(p&&(p.required||p.optional)){this.emit(`option:${p.name()}`,a.slice(l+1));continue}}if(i(a)&&(o=r),(this._enablePositionalOptions||this._passThroughOptions)&&t.length===0&&r.length===0){if(this._findCommand(a)){t.push(a),s.length>0&&r.push(...s);break}else if(this._getHelpCommand()&&a===this._getHelpCommand().name()){t.push(a),s.length>0&&t.push(...s);break}else if(this._defaultCommandName){r.push(a),s.length>0&&r.push(...s);break}}if(this._passThroughOptions){o.push(a),s.length>0&&o.push(...s);break}o.push(a)}return{operands:t,unknown:r}}opts(){if(this._storeOptionsAsProperties){let e={},t=this.options.length;for(let r=0;r<t;r++){let o=this.options[r].attributeName();e[o]=o===this._versionOptionName?this._version:this[o]}return e}return this._optionValues}optsWithGlobals(){return this._getCommandAndAncestors().reduce((e,t)=>Object.assign(e,t.opts()),{})}error(e,t){this._outputConfiguration.outputError(`${e}
|
|
18
|
+
`,this._outputConfiguration.writeErr),typeof this._showHelpAfterError=="string"?this._outputConfiguration.writeErr(`${this._showHelpAfterError}
|
|
19
|
+
`):this._showHelpAfterError&&(this._outputConfiguration.writeErr(`
|
|
20
|
+
`),this.outputHelp({error:!0}));let r=t||{},o=r.exitCode||1,s=r.code||"commander.error";this._exit(o,s,e)}_parseOptionsEnv(){this.options.forEach(e=>{if(e.envVar&&e.envVar in w.env){let t=e.attributeName();(this.getOptionValue(t)===void 0||["default","config","env"].includes(this.getOptionValueSource(t)))&&(e.required||e.optional?this.emit(`optionEnv:${e.name()}`,w.env[e.envVar]):this.emit(`optionEnv:${e.name()}`))}})}_parseOptionsImplied(){let e=new ln(this.options),t=r=>this.getOptionValue(r)!==void 0&&!["default","implied"].includes(this.getOptionValueSource(r));this.options.filter(r=>r.implied!==void 0&&t(r.attributeName())&&e.valueFromOption(this.getOptionValue(r.attributeName()),r)).forEach(r=>{Object.keys(r.implied).filter(o=>!t(o)).forEach(o=>{this.setOptionValueWithSource(o,r.implied[o],"implied")})})}missingArgument(e){let t=`error: missing required argument '${e}'`;this.error(t,{code:"commander.missingArgument"})}optionMissingArgument(e){let t=`error: option '${e.flags}' argument missing`;this.error(t,{code:"commander.optionMissingArgument"})}missingMandatoryOptionValue(e){let t=`error: required option '${e.flags}' not specified`;this.error(t,{code:"commander.missingMandatoryOptionValue"})}_conflictingOption(e,t){let r=i=>{let c=i.attributeName(),a=this.getOptionValue(c),l=this.options.find(u=>u.negate&&c===u.attributeName()),p=this.options.find(u=>!u.negate&&c===u.attributeName());return l&&(l.presetArg===void 0&&a===!1||l.presetArg!==void 0&&a===l.presetArg)?l:p||i},o=i=>{let c=r(i),a=c.attributeName();return this.getOptionValueSource(a)==="env"?`environment variable '${c.envVar}'`:`option '${c.flags}'`},s=`error: ${o(e)} cannot be used with ${o(t)}`;this.error(s,{code:"commander.conflictingOption"})}unknownOption(e){if(this._allowUnknownOption)return;let t="";if(e.startsWith("--")&&this._showSuggestionAfterError){let o=[],s=this;do{let i=s.createHelp().visibleOptions(s).filter(c=>c.long).map(c=>c.long);o=o.concat(i),s=s.parent}while(s&&!s._enablePositionalOptions);t=Qt(e,o)}let r=`error: unknown option '${e}'${t}`;this.error(r,{code:"commander.unknownOption"})}_excessArguments(e){if(this._allowExcessArguments)return;let t=this.registeredArguments.length,r=t===1?"":"s",s=`error: too many arguments${this.parent?` for '${this.name()}'`:""}. Expected ${t} argument${r} but got ${e.length}.`;this.error(s,{code:"commander.excessArguments"})}unknownCommand(){let e=this.args[0],t="";if(this._showSuggestionAfterError){let o=[];this.createHelp().visibleCommands(this).forEach(s=>{o.push(s.name()),s.alias()&&o.push(s.alias())}),t=Qt(e,o)}let r=`error: unknown command '${e}'${t}`;this.error(r,{code:"commander.unknownCommand"})}version(e,t,r){if(e===void 0)return this._version;this._version=e,t=t||"-V, --version",r=r||"output the version number";let o=this.createOption(t,r);return this._versionOptionName=o.attributeName(),this._registerOption(o),this.on("option:"+o.name(),()=>{this._outputConfiguration.writeOut(`${e}
|
|
21
|
+
`),this._exit(0,"commander.version",e)}),this}description(e,t){return e===void 0&&t===void 0?this._description:(this._description=e,t&&(this._argsDescription=t),this)}summary(e){return e===void 0?this._summary:(this._summary=e,this)}alias(e){if(e===void 0)return this._aliases[0];let t=this;if(this.commands.length!==0&&this.commands[this.commands.length-1]._executableHandler&&(t=this.commands[this.commands.length-1]),e===t._name)throw new Error("Command alias can't be the same as its name");let r=this.parent?._findCommand(e);if(r){let o=[r.name()].concat(r.aliases()).join("|");throw new Error(`cannot add alias '${e}' to command '${this.name()}' as already have command '${o}'`)}return t._aliases.push(e),this}aliases(e){return e===void 0?this._aliases:(e.forEach(t=>this.alias(t)),this)}usage(e){if(e===void 0){if(this._usage)return this._usage;let t=this.registeredArguments.map(r=>an(r));return[].concat(this.options.length||this._helpOption!==null?"[options]":[],this.commands.length?"[command]":[],this.registeredArguments.length?t:[]).join(" ")}return this._usage=e,this}name(e){return e===void 0?this._name:(this._name=e,this)}nameFromFilename(e){return this._name=L.basename(e,L.extname(e)),this}executableDir(e){return e===void 0?this._executableDir:(this._executableDir=e,this)}helpInformation(e){let t=this.createHelp();return t.helpWidth===void 0&&(t.helpWidth=e&&e.error?this._outputConfiguration.getErrHelpWidth():this._outputConfiguration.getOutHelpWidth()),t.formatHelp(this,t)}_getHelpContext(e){e=e||{};let t={error:!!e.error},r;return t.error?r=o=>this._outputConfiguration.writeErr(o):r=o=>this._outputConfiguration.writeOut(o),t.write=e.write||r,t.command=this,t}outputHelp(e){let t;typeof e=="function"&&(t=e,e=void 0);let r=this._getHelpContext(e);this._getCommandAndAncestors().reverse().forEach(s=>s.emit("beforeAllHelp",r)),this.emit("beforeHelp",r);let o=this.helpInformation(r);if(t&&(o=t(o),typeof o!="string"&&!Buffer.isBuffer(o)))throw new Error("outputHelp callback must return a string or a Buffer");r.write(o),this._getHelpOption()?.long&&this.emit(this._getHelpOption().long),this.emit("afterHelp",r),this._getCommandAndAncestors().forEach(s=>s.emit("afterAllHelp",r))}helpOption(e,t){return typeof e=="boolean"?(e?this._helpOption=this._helpOption??void 0:this._helpOption=null,this):(e=e??"-h, --help",t=t??"display help for command",this._helpOption=this.createOption(e,t),this)}_getHelpOption(){return this._helpOption===void 0&&this.helpOption(void 0,void 0),this._helpOption}addHelpOption(e){return this._helpOption=e,this}help(e){this.outputHelp(e);let t=w.exitCode||0;t===0&&e&&typeof e!="function"&&e.error&&(t=1),this._exit(t,"commander.help","(outputHelp)")}addHelpText(e,t){let r=["beforeAll","before","after","afterAll"];if(!r.includes(e))throw new Error(`Unexpected value for position to addHelpText.
|
|
22
|
+
Expecting one of '${r.join("', '")}'`);let o=`${e}Help`;return this.on(o,s=>{let i;typeof t=="function"?i=t({error:s.error,command:s.command}):i=t,i&&s.write(`${i}
|
|
23
|
+
`)}),this}_outputHelpIfRequested(e){let t=this._getHelpOption();t&&e.find(o=>t.is(o))&&(this.outputHelp(),this._exit(0,"commander.helpDisplayed","(outputHelp)"))}};function er(n){return n.map(e=>{if(!e.startsWith("--inspect"))return e;let t,r="127.0.0.1",o="9229",s;return(s=e.match(/^(--inspect(-brk)?)$/))!==null?t=s[1]:(s=e.match(/^(--inspect(-brk|-port)?)=([^:]+)$/))!==null?(t=s[1],/^\d+$/.test(s[3])?o=s[3]:r=s[3]):(s=e.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null&&(t=s[1],r=s[3],o=s[4]),t&&o!=="0"?`${t}=${r}:${parseInt(o)+1}`:e})}tr.Command=ze});var ir=z(_=>{"use strict";var{Argument:nr}=ve(),{Command:We}=rr(),{CommanderError:pn,InvalidArgumentError:or}=se(),{Help:un}=je(),{Option:sr}=De();_.program=new We;_.createCommand=n=>new We(n);_.createOption=(n,e)=>new sr(n,e);_.createArgument=(n,e)=>new nr(n,e);_.Command=We;_.Option=sr;_.Argument=nr;_.Help=un;_.CommanderError=pn;_.InvalidArgumentError=or;_.InvalidOptionArgumentError=or});var Or={};Bt(Or,{TerminalReporter:()=>re});function lo(n){return!(n||process.env.NO_COLOR!==void 0||!process.stdout.isTTY)}function po(n){return function(t,r){return n?`${t}${r}${co}`:r}}function mo(){return`\u2554${"\u2550".repeat(q)}\u2557`}function kr(){return`\u2560${"\u2550".repeat(q)}\u2563`}function ho(){return`\u255A${"\u2550".repeat(q)}\u255D`}function At(n){return`\u2551${n.padEnd(q," ")}\u2551`}function xr(){return At("")}function Pr(n,e){return n>=80?e(G,String(n)):n>=50?e(Re,String(n)):e(te,String(n))}function go(n,e){switch(n){case"failure":return e(te,"[FAIL]");case"warning":return e(Re,"[WARN]");case"info":return e($,"[INFO]");case"pass":return e(G,"[PASS]")}}function yo(n){return n==="http"?"HTTP+SSE":"stdio"}function vo(n){return n<1e3?`${n}ms`:`${(n/1e3).toFixed(1)}s`}function bo(n,e){switch(n){case"critical":return e(te,"[CRITICAL]");case"high":return e(te,"[HIGH]");case"medium":return e(Re,"[MEDIUM]");case"low":return e($,"[LOW]");case"info":return e(Ce,"[INFO]")}}var co,ee,Ce,te,G,Re,$,uo,fo,wr,q,re,Se=Gr(()=>{"use strict";co="\x1B[0m",ee="\x1B[1m",Ce="\x1B[2m",te="\x1B[31m",G="\x1B[32m",Re="\x1B[33m",$="\x1B[36m";uo={"jsonrpc-base":"JSON-RPC Base",initialization:"Initialization",tools:"Tools",resources:"Resources",prompts:"Prompts",transport:"Transport","error-handling":"Error Handling"},fo=["jsonrpc-base","initialization","tools","resources","prompts","transport"],wr=["jsonrpc-base","initialization","tools","resources","prompts","transport","error-handling"],q=54;re=class{useColor;constructor(e=!1){this.useColor=lo(e)}format(e){let t=po(this.useColor),r=[],{meta:o,conformance:s,summary:i}=e,c=s.score,a=i.pass?"PASS":"FAIL",l=i.pass?t(G,`Verdict: ${a}`):t(te,`Verdict: ${a}`);r.push(t($,mo()));let p="MCP Verify Report",u=Math.floor((q-p.length)/2),d=q-p.length-u;r.push(t($,At(" ".repeat(u)+t(ee,p)+" ".repeat(d)))),r.push(t($,kr()));let m=[["Target:",o.target],["Transport:",yo(o.transport)],["Server:",`${o.toolVersion}`],["Spec:",`MCP ${o.specVersion}`],["Timestamp:",o.timestamp],["Duration:",vo(o.durationMs)]];for(let[S,E]of m){let K=` ${S.padEnd(12)}${E}`;r.push(t($,At(K)))}r.push(t($,kr())),r.push(t($,xr()));let f="Conformance Score: ",h=`${Pr(c,t)} / 100`,y=`${c} / 100`,v=q-2-f.length-y.length;r.push(t($,`\u2551 ${f}${h}${" ".repeat(Math.max(0,v))}\u2551`)),r.push(t($,xr()));let C=` ${l}`,g=` Verdict: ${a}`,b=q-g.length;r.push(t($,`\u2551${C}${" ".repeat(Math.max(0,b))}\u2551`)),r.push(t($,ho())),r.push(""),r.push(t(ee,"=== Conformance Breakdown ===")),r.push("");let R=new Map;for(let S of wr)R.set(S,[]);for(let S of s.violations){let E=R.get(S.category);E!==void 0&&E.push(S)}for(let S of wr){let E=uo[S],K=R.get(S)??[];if(fo.includes(S)){let H=s.breakdown[S]??0,fe=Pr(H,t),me=` ${E}:`,he=Math.max(1,18-me.length);r.push(` ${t(ee,`${E}:`)}${" ".repeat(he)}${fe}/100`)}else r.push(` ${t(ee,`${E}:`)}`);if(K.length===0)r.push(` ${t(G,"\u2713 No violations")}`);else for(let H of K){let fe=go(H.level,t),me=H.field!==void 0?` (${H.field})`:"",he=` (${H.checkId})`;H.level==="pass"?r.push(` ${fe} ${H.description}${me}${he}`):r.push(` ${fe} ${H.description}${me}${he}`)}r.push("")}r.push(t(ee,"=== Security Findings ===")),r.push("");let x=e.security.findings,O=e.security.suppressed;if(x.length===0&&O.length===0)r.push(` ${t(G,"\u2713 No security findings detected")}`);else{if(x.length>0)for(let S of x){let E=bo(S.severity,t),K=S.confidence==="deterministic"?t($,"[deterministic]"):t(Re,"[heuristic]");r.push(` ${E} ${K} ${S.title}`),r.push(` ${t(Ce,S.checkId)} | CVSS ${S.cvssScore} | ${S.component}`),r.push(` ${S.description}`),r.push(` ${t(G,"Remediation:")} ${S.remediation}`),r.push("")}if(O.length>0){r.push(` ${t(Ce,`${O.length} suppressed finding(s)`)}`);for(let S of O){let E=S.justification!==void 0?` \u2014 ${S.justification}`:"";r.push(` ${t(Ce,`[SUPPRESSED] ${S.checkId}: ${S.title}${E}`)}`)}}}r.push("");let V=`=== ${a} ===`,Te=i.pass?t(G,V):t(te,V);return r.push(t(ee,Te)),r.join(`
|
|
24
|
+
`)}}});var Lo={};Bt(Lo,{ExitCode:()=>Lr,buildProgram:()=>Fr,exitWithError:()=>Y,main:()=>Jr,parseConformanceThreshold:()=>Wt,parseFailOnSeverity:()=>zt,parseFormat:()=>Jt,parsePort:()=>Dr,parseTimeout:()=>Ft,parseTransport:()=>qt});module.exports=Yr(Lo);var ar=$e(ir(),1),{program:Go,createCommand:Yo,createArgument:Ko,createOption:Xo,CommanderError:Zo,InvalidArgumentError:W,InvalidOptionArgumentError:Qo,Command:cr,Argument:es,Option:ts,Help:rs}=ar.default;var Ut=require("fs");var k={timeout:1e4,format:"terminal",transport:null,failOnSeverity:"critical",conformanceThreshold:0,skip:[],skipJustifications:{},checkMode:"balanced",noColor:!1,verbose:!1,output:null,noHistory:!1};function Ue(n){if(n.startsWith("http://")||n.startsWith("https://"))return"http";if(n.startsWith("stdio://"))return"stdio";let e=new Error(`Cannot detect transport for target: "${n}". Valid schemes are: http://, https://, stdio://`);throw e.code="2",e}var lr=require("child_process"),pr=require("path"),ie=class{executablePath;timeout;verbose;process=null;stdoutBuffer="";pending=new Map;preProtocolOutput=[];timings=[];firstJsonSeen=!1;closed=!1;constructor(e,t,r=!1){this.executablePath=e.replace(/^stdio:\/\//,""),this.timeout=t,this.verbose=r}ensureSpawned(){if(this.process!==null)return;let e=this.executablePath,t=(0,pr.extname)(e).toLowerCase(),r,o;t===".js"||t===".ts"?(r=process.execPath,o=[e]):(r=e,o=[]),this.process=(0,lr.spawn)(r,o,{stdio:["pipe","pipe","pipe"]}),this.process.stdout.on("data",s=>{this.stdoutBuffer+=s.toString("utf8"),this.drainBuffer()}),this.verbose&&this.process.stderr.on("data",s=>{process.stderr.write(s)}),this.process.on("error",s=>{this.rejectAll(s)}),this.process.on("exit",s=>{let i=new Error(`Child process exited with code ${s??"null"}`);this.rejectAll(i)})}async close(){if(this.closed||this.process===null){this.closed=!0;return}this.closed=!0;let e=this.process;return new Promise(t=>{let r=setTimeout(()=>{e.kill("SIGKILL"),t()},2e3);e.once("exit",()=>{clearTimeout(r),t()}),e.kill("SIGTERM")})}async send(e){return this.ensureSpawned(),new Promise((t,r)=>{let o=Date.now(),s=setTimeout(()=>{this.pending.delete(e.id),r(new Error(`Timeout waiting for response to "${e.method}" (id: ${e.id})`))},this.timeout);this.pending.set(e.id,{resolve:i=>{clearTimeout(s);let c=Date.now();this.timings.push({method:e.method,requestTimestamp:o,responseTimestamp:c,durationMs:c-o}),t(i)},reject:i=>{clearTimeout(s),r(i)},timer:s,method:e.method,requestTimestamp:o}),this.writeToProcess(JSON.stringify(e)+`
|
|
25
|
+
`)})}async notify(e){this.ensureSpawned(),this.writeToProcess(JSON.stringify(e)+`
|
|
26
|
+
`)}async sendRaw(e){this.ensureSpawned();let t=`raw-${Date.now()}`;return new Promise(r=>{let o=setTimeout(()=>{this.pending.delete(t),r(null)},this.timeout);this.pending.set(t,{resolve:s=>{clearTimeout(o),r(s)},reject:s=>{clearTimeout(o),r(null)},timer:o,method:"raw",requestTimestamp:Date.now()}),this.writeToProcess(e+`
|
|
27
|
+
`)})}getMetadata(){return{type:"stdio",target:this.executablePath,httpHeaders:{},sseObservations:[],preProtocolOutput:[...this.preProtocolOutput],timing:[...this.timings]}}writeToProcess(e){this.process===null||this.closed||this.process.stdin.write(e,"utf8")}drainBuffer(){let e;for(;(e=this.stdoutBuffer.indexOf(`
|
|
28
|
+
`))!==-1;){let t=this.stdoutBuffer.slice(0,e).trimEnd();if(this.stdoutBuffer=this.stdoutBuffer.slice(e+1),!t)continue;let r;try{r=JSON.parse(t)}catch{this.firstJsonSeen||this.preProtocolOutput.push(t);continue}if(this.firstJsonSeen=!0,!dn(r))continue;let o=r;if(o.id!==null&&this.pending.has(o.id)){let s=this.pending.get(o.id);if(s){this.pending.delete(o.id),s.resolve(o);continue}}if(o.id===null){for(let[s,i]of this.pending.entries())if(String(s).startsWith("raw-")){this.pending.delete(s),i.resolve(o);break}}}}rejectAll(e){for(let[t,r]of this.pending.entries())this.pending.delete(t),clearTimeout(r.timer),r.reject(e)}};function dn(n){if(typeof n!="object"||n===null)return!1;let e=n;return typeof e.jsonrpc=="string"&&(e.id===null||typeof e.id=="string"||typeof e.id=="number")&&(Object.prototype.hasOwnProperty.call(e,"result")||Object.prototype.hasOwnProperty.call(e,"error"))}var mn=$e(require("http"),1),hn=$e(require("https"),1),ur=require("url");function Be(n){let e=[],t=[],r=n.split(/\r?\n\r?\n/);for(let o of r){if(!o.trim())continue;let s=o.split(/\r?\n/),i=null;for(let c of s)c&&(c.startsWith("data:")?(i=c.slice(5).trimStart(),t.push({hasDataPrefix:!0,hasEventType:!1,rawLine:c})):c.startsWith("event:")?t.push({hasDataPrefix:!1,hasEventType:!0,rawLine:c}):c.startsWith("id:")||c.startsWith(":")?t.push({hasDataPrefix:!1,hasEventType:!1,rawLine:c}):t.push({hasDataPrefix:!1,hasEventType:!1,rawLine:c}));if(i!==null)try{let c=JSON.parse(i);fn(c)&&e.push(c)}catch{}}return{responses:e,observations:t}}function fn(n){if(typeof n!="object"||n===null)return!1;let e=n;return typeof e.jsonrpc=="string"&&(e.id===null||typeof e.id=="string"||typeof e.id=="number")}var ae=class{url;timeout;capturedHeaders={};sseObservations=[];timings=[];activeSockets=new Set;constructor(e,t){this.url=e,this.timeout=t}async send(e){let t=Date.now(),r=await this.post(JSON.stringify(e),e.id),o=Date.now();return this.timings.push({method:e.method,requestTimestamp:t,responseTimestamp:o,durationMs:o-t}),r}async notify(e){try{await this.post(JSON.stringify(e),null)}catch{}}async sendRaw(e){try{return await this.post(e,null)}catch{return null}}getMetadata(){return{type:"http",target:this.url,httpHeaders:{...this.capturedHeaders},sseObservations:[...this.sseObservations],preProtocolOutput:[],timing:[...this.timings]}}async close(){for(let e of this.activeSockets)e.destroy();this.activeSockets.clear()}post(e,t){return new Promise((r,o)=>{let s=new ur.URL(this.url),i=s.protocol==="https:",c=i?hn:mn,a={method:"POST",hostname:s.hostname,port:s.port?parseInt(s.port,10):i?443:80,path:s.pathname+s.search,headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(e,"utf8"),Accept:"application/json, text/event-stream"}},l=setTimeout(()=>{p.destroy(new Error(`HTTP request timed out after ${this.timeout}ms`))},this.timeout),p=c.request(a,u=>{clearTimeout(l);let d=`${a.method} ${a.path}`,m={};for(let[v,C]of Object.entries(u.headers))C!==void 0&&(m[v]=Array.isArray(C)?C.join(", "):C);this.capturedHeaders[d]=m;let h=(u.headers["content-type"]??"").includes("text/event-stream"),y=[];u.on("data",v=>{y.push(v)}),u.on("end",()=>{this.activeSockets.delete(p);let v=Buffer.concat(y).toString("utf8");if(h){let{responses:C,observations:g}=Be(v);for(let R of g)this.sseObservations.push(R);let b=t!==null?C.find(R=>R.id===t):C[0];b!==void 0?r(b):C.length>0&&C[0]!==void 0?r(C[0]):o(new Error("No JSON-RPC response found in SSE stream"))}else{let C;try{C=JSON.parse(v)}catch(g){o(new Error(`Failed to parse JSON response: ${String(g)}`));return}if(!gn(C)){o(new Error("Response is not a valid JSON-RPC response"));return}r(C)}}),u.on("error",v=>{this.activeSockets.delete(p),o(v)})});p.on("error",u=>{clearTimeout(l),this.activeSockets.delete(p),o(u)}),this.activeSockets.add(p),p.write(e,"utf8"),p.end()})}};function gn(n){if(typeof n!="object"||n===null)return!1;let e=n;return typeof e.jsonrpc=="string"&&(e.id===null||typeof e.id=="string"||typeof e.id=="number")}function Ge(n,e){let t=e.transport??Ue(n);switch(t){case"stdio":return new ie(n,e.timeout,e.verbose);case"http":return new ae(n,e.timeout);default:{let r=t;throw new Error(`Unsupported transport type: ${String(r)}`)}}}var yn=1;function X(){return yn++}var be="2024-11-05";function Ye(n){return{jsonrpc:"2.0",id:X(),method:"initialize",params:{protocolVersion:be,capabilities:{},clientInfo:{name:"mcp-verify",version:n}}}}function Ke(){return{jsonrpc:"2.0",method:"notifications/initialized"}}function Xe(n){let e={};return n!==void 0&&(e.cursor=n),{jsonrpc:"2.0",id:X(),method:"tools/list",params:e}}function Ze(){return{jsonrpc:"2.0",id:X(),method:"resources/list",params:{}}}function Qe(n){return{jsonrpc:"2.0",id:X(),method:"resources/read",params:{uri:n}}}function et(){return{jsonrpc:"2.0",id:X(),method:"prompts/list",params:{}}}function tt(){return{jsonrpc:"2.0",id:X(),method:"mcp-verify/probe-unknown-method",params:{}}}function rt(n){if(n.error!==void 0)return{};let e=n.result;if(typeof e!="object"||e===null)return{};let r=e.capabilities;return typeof r!="object"||r===null?{}:r}function Z(n,e){return Object.prototype.hasOwnProperty.call(n,e)&&n[e]!==null&&n[e]!==void 0}var vn="0.2.0-alpha",bn=500;async function ot(n,e){let t=[],r={},o=Ye(vn),s=null,i=null;{let{result:g,stepResult:b}=await U("initialize",()=>n.send(o),e);r.initialize=b,s=g,g!==null?i=Cn(g,be):t.push({step:"initialize",message:b.error??"initialize failed",code:b.status==="timeout"?"TIMEOUT":"ERROR"})}let c=!1;{let g=Date.now();try{await n.notify(Ke()),c=!0,r.initialized={status:"completed",durationMs:Date.now()-g}}catch(b){r.initialized={status:"error",durationMs:Date.now()-g,error:String(b)}}}let a=s!==null?rt(s):{},l=[],p=[];if(Z(a,"tools")){let g,b=0,R=!1;do{let x=Xe(g),{result:O,stepResult:V}=await U("tools/list",()=>n.send(x),e);if(b===0&&(r["tools/list"]=V),O===null||V.status!=="completed"){b===0&&t.push({step:"tools/list",message:V.error??"tools/list failed",code:V.status==="timeout"?"TIMEOUT":"ERROR"});break}l.push(O);let Te=nt(O,"tools");for(let E of Te)p.length<bn?p.push(E):R=!0;if(g=Rn(O),b++,R)break}while(g!==void 0);Object.prototype.hasOwnProperty.call(r,"tools/list")||(r["tools/list"]={status:"skipped",durationMs:0})}else r["tools/list"]={status:"skipped",durationMs:0};let u=null,d=[];if(Z(a,"resources")){let{result:g,stepResult:b}=await U("resources/list",()=>n.send(Ze()),e);if(r["resources/list"]=b,u=g,g!==null&&b.status==="completed"){let R=nt(g,"resources");for(let x of R)d.push(x)}else g===null&&t.push({step:"resources/list",message:b.error??"resources/list failed",code:b.status==="timeout"?"TIMEOUT":"ERROR"})}else r["resources/list"]={status:"skipped",durationMs:0};let m=null;if(Z(a,"resources")&&d.length>0){let g=d[0],b=Sn(g);if(b!==null){let{result:R,stepResult:x}=await U("resources/read",()=>n.send(Qe(b)),e);r["resources/read"]=x,m=R,R===null&&t.push({step:"resources/read",message:x.error??"resources/read failed",code:x.status==="timeout"?"TIMEOUT":"ERROR"})}else r["resources/read"]={status:"skipped",durationMs:0}}else r["resources/read"]={status:"skipped",durationMs:0};let f=null,h=[];if(Z(a,"prompts")){let{result:g,stepResult:b}=await U("prompts/list",()=>n.send(et()),e);if(r["prompts/list"]=b,f=g,g!==null&&b.status==="completed"){let R=nt(g,"prompts");for(let x of R)h.push(x)}else g===null&&t.push({step:"prompts/list",message:b.error??"prompts/list failed",code:b.status==="timeout"?"TIMEOUT":"ERROR"})}else r["prompts/list"]={status:"skipped",durationMs:0};let y=null;{let g=tt(),{result:b,stepResult:R}=await U("error-probe-unknown",()=>n.send(g),e);r["error-probe-unknown"]=R,y=b}let v=null;{let{result:g,stepResult:b}=await U("error-probe-malformed",()=>n.sendRaw("{ invalid json %%%"),e);r["error-probe-malformed"]=b,v=g}let C=["initialize","initialized","tools/list","resources/list","resources/read","prompts/list","error-probe-unknown","error-probe-malformed"];for(let g of C)Object.prototype.hasOwnProperty.call(r,g)||(r[g]={status:"skipped",durationMs:0});return{initializeRequest:o,initializeResponse:s,initializedSent:c,serverInfo:i,toolsListResponses:l,tools:p,resourcesListResponse:u,resources:d,resourceReadResponse:m,promptsListResponse:f,prompts:h,unknownMethodProbeResponse:y,malformedJsonProbeResponse:v,transportMetadata:n.getMetadata(),errors:t,stepResults:r}}async function U(n,e,t){let r=Date.now();try{return{result:await e(),stepResult:{status:"completed",durationMs:Date.now()-r}}}catch(o){let s=o instanceof Error?o.message:String(o);return{result:null,stepResult:{status:s.toLowerCase().includes("timeout")||s.toLowerCase().includes("timed out")?"timeout":"error",durationMs:Date.now()-r,error:s}}}}function Cn(n,e){if(n.error!==void 0)return null;let t=n.result;if(typeof t!="object"||t===null)return null;let r=t,o=r.serverInfo,s=typeof r.protocolVersion=="string"?r.protocolVersion:e;if(typeof o!="object"||o===null)return{name:"unknown",protocolVersion:s};let i=o;return{name:typeof i.name=="string"?i.name:"unknown",version:typeof i.version=="string"?i.version:void 0,protocolVersion:s}}function nt(n,e){if(n.result===void 0||n.result===null)return[];if(typeof n.result!="object")return[];let r=n.result[e];return Array.isArray(r)?r:[]}function Rn(n){if(n.result===void 0||n.result===null||typeof n.result!="object")return;let t=n.result.nextCursor;return typeof t=="string"&&t.length>0?t:void 0}function Sn(n){if(typeof n!="object"||n===null)return null;let e=n;return typeof e.uri=="string"?e.uri:null}var wn=new Set([-32700,-32600,-32601,-32602,-32603]);function dr(n){return wn.has(n)}function fr(n){return n>=-32099&&n<=-32e3}function kn(n){return n>=-32699&&n<=-32604}function xn(n){return dr(n)||fr(n)}function Pn(n){let e=[];n.initializeResponse!==null&&e.push({response:n.initializeResponse,label:"initialize"});for(let t=0;t<n.toolsListResponses.length;t++){let r=n.toolsListResponses[t];r!==void 0&&e.push({response:r,label:`tools/list[${t}]`})}return n.resourcesListResponse!==null&&e.push({response:n.resourcesListResponse,label:"resources/list"}),n.resourceReadResponse!==null&&e.push({response:n.resourceReadResponse,label:"resources/read"}),n.promptsListResponse!==null&&e.push({response:n.promptsListResponse,label:"prompts/list"}),n.unknownMethodProbeResponse!==null&&e.push({response:n.unknownMethodProbeResponse,label:"error-probe-unknown"}),n.malformedJsonProbeResponse!==null&&e.push({response:n.malformedJsonProbeResponse,label:"error-probe-malformed"}),e}function On(n,e){let{response:t,label:r}=n,o=t.id??void 0,s=t.jsonrpc==="2.0";e.push({checkId:"JSONRPC-001",name:"JSON-RPC version field",category:"jsonrpc-base",level:s?"pass":"failure",description:s?`Response for "${r}" has jsonrpc: "2.0"`:`Response for "${r}" has incorrect or missing jsonrpc field (got: ${JSON.stringify(t.jsonrpc)})`,specVersion:"2024-11-05",specReference:"JSON-RPC 2.0 \xA74",confidence:"deterministic",messageId:o,field:"jsonrpc",details:{label:r}});let i=t.id,a=typeof i=="string"||typeof i=="number"||(r==="error-probe-unknown"||r==="error-probe-malformed")&&i===null;e.push({checkId:"JSONRPC-002",name:"JSON-RPC id field type",category:"jsonrpc-base",level:a?"pass":"failure",description:a?`Response for "${r}" has a valid id field`:`Response for "${r}" has null or invalid id field (got: ${JSON.stringify(i)})`,specVersion:"2024-11-05",specReference:"JSON-RPC 2.0 \xA74",confidence:"deterministic",messageId:o,field:"id",details:{label:r}});let l="result"in t,p="error"in t,u=l&&p,d=!l&&!p,m="pass",f=`Response for "${r}" correctly has either result or error (not both)`;u?(m="failure",f=`Response for "${r}" contains both "result" and "error" fields \u2014 they are mutually exclusive per JSON-RPC 2.0`):d&&(m="failure",f=`Response for "${r}" contains neither "result" nor "error" field \u2014 one is required per JSON-RPC 2.0`),e.push({checkId:"JSONRPC-003",name:"JSON-RPC result/error mutual exclusion",category:"jsonrpc-base",level:m,description:f,specVersion:"2024-11-05",specReference:"JSON-RPC 2.0 \xA75",confidence:"deterministic",messageId:o,details:{label:r,hasResult:l,hasError:p}})}function En(n,e){let{response:t,label:r}=n,o=t.id??void 0;if(!("error"in t)||t.error===void 0){e.push({checkId:"JSONRPC-004",name:"JSON-RPC error code validity",category:"jsonrpc-base",level:"pass",description:`Response for "${r}" has no error object \u2014 error code check not applicable`,specVersion:"2024-11-05",specReference:"JSON-RPC 2.0 \xA75.1",confidence:"deterministic",messageId:o,details:{label:r}});return}let s=t.error.code,i=s>0,c=dr(s),a=fr(s),l=kn(s),p=xn(s),u="pass",d=`Response for "${r}" has a valid error code ${s}`;i?(u="failure",d=`Response for "${r}" has a positive error code ${s} \u2014 JSON-RPC error codes must be negative integers`):!p&&!l?(u="failure",d=`Response for "${r}" has error code ${s} which is outside all valid JSON-RPC ranges`):l?(u="warning",d=`Response for "${r}" uses reserved error code ${s} (range -32699 to -32604 is currently unassigned)`):c?d=`Response for "${r}" uses standard error code ${s}`:a&&(d=`Response for "${r}" uses server-defined error code ${s} (range -32099 to -32000)`),e.push({checkId:"JSONRPC-004",name:"JSON-RPC error code validity",category:"jsonrpc-base",level:u,description:d,specVersion:"2024-11-05",specReference:"JSON-RPC 2.0 \xA75.1",confidence:"deterministic",messageId:o,field:"error.code",details:{label:r,code:s,isStandardRange:c,isServerDefinedRange:a}});let m=typeof t.error.message=="string";e.push({checkId:"JSONRPC-005",name:"JSON-RPC error message type",category:"jsonrpc-base",level:m?"pass":"failure",description:m?`Response for "${r}" error object has a string message field`:`Response for "${r}" error object message field is not a string (got: ${typeof t.error.message})`,specVersion:"2024-11-05",specReference:"JSON-RPC 2.0 \xA75.1",confidence:"deterministic",messageId:o,field:"error.message",details:{label:r}})}function st(n,e){let t=[],r=Pn(n);if(r.length===0)return t.push({checkId:"JSONRPC-000",name:"JSON-RPC responses present",category:"jsonrpc-base",level:"failure",description:"No JSON-RPC responses found in the exchange record \u2014 cannot validate envelope",specVersion:"2024-11-05",specReference:"JSON-RPC 2.0 \xA74",confidence:"deterministic"}),t;for(let o of r)On(o,t),En(o,t);return t}var P="2024-11-05";function Tn(n){let e=n.initializeResponse;return e===null||!("result"in e)||e.result===null||typeof e.result!="object"?null:e.result}function $n(n,e){if(n===null){e.push({checkId:"INIT-001",name:"Initialize response present",category:"initialization",level:"failure",description:"No initialize response was received \u2014 cannot validate initialization handshake",specVersion:P,specReference:"MCP spec \xA73.1 (Initialization)",confidence:"deterministic"});return}e.push({checkId:"INIT-001",name:"Initialize response present",category:"initialization",level:"pass",description:"Initialize response was received from the server",specVersion:P,specReference:"MCP spec \xA73.1 (Initialization)",confidence:"deterministic"});let t=n.protocolVersion,r=t!=null&&typeof t=="string",o=r&&t.length>0;e.push({checkId:"INIT-002",name:"protocolVersion field",category:"initialization",level:r&&o?"pass":"failure",description:r&&o?`protocolVersion is present and valid: "${t}"`:r?"protocolVersion field is an empty string":"protocolVersion field is absent or not a string in the initialize response",specVersion:P,specReference:"MCP spec \xA73.1 (Initialization)",confidence:"deterministic",field:"result.protocolVersion",details:{protocolVersion:t}})}function _n(n,e){if(n===null)return null;let t=n.capabilities,r=t!=null&&typeof t=="object"&&!Array.isArray(t);if(e.push({checkId:"INIT-003",name:"capabilities object present",category:"initialization",level:r?"pass":"failure",description:r?"capabilities object is present in the initialize response":"capabilities object is absent or not an object in the initialize response",specVersion:P,specReference:"MCP spec \xA73.1 (Initialization)",confidence:"deterministic",field:"result.capabilities"}),!r)return null;let o=t;return e.push({checkId:"INIT-004",name:"capabilities structure",category:"initialization",level:"pass",description:"capabilities is a valid object (not an array)",specVersion:P,specReference:"MCP spec \xA73.1 (Initialization)",confidence:"deterministic",field:"result.capabilities"}),o}function An(n,e,t){let r=n!==null?n.serverInfo:void 0,o=e.serverInfo,s=r!=null||o!==null;if(t.push({checkId:"INIT-005",name:"serverInfo presence",category:"initialization",level:s?"pass":"warning",description:s?"serverInfo object is present in the initialize response":"serverInfo object is absent from the initialize response \u2014 recommended for identification",specVersion:P,specReference:"MCP spec \xA73.1 (Initialization)",confidence:"deterministic",field:"result.serverInfo"}),!s)return;let i=r??o;if(i===null||typeof i!="object"){t.push({checkId:"INIT-006",name:"serverInfo.name field",category:"initialization",level:"warning",description:"serverInfo is not a valid object \u2014 cannot validate name field",specVersion:P,specReference:"MCP spec \xA73.1 (Initialization)",confidence:"deterministic",field:"result.serverInfo.name"});return}let c=i.name,a=typeof c=="string"&&c.length>0;t.push({checkId:"INIT-006",name:"serverInfo.name field",category:"initialization",level:a?"pass":"warning",description:a?`serverInfo.name is present: "${c}"`:"serverInfo.name is absent or empty \u2014 recommended for server identification",specVersion:P,specReference:"MCP spec \xA73.1 (Initialization)",confidence:"deterministic",field:"result.serverInfo.name",details:{name:c}})}function In(n,e){e.push({checkId:"INIT-007",name:"initialized notification sent",category:"initialization",level:n.initializedSent?"pass":"warning",description:n.initializedSent?"The initialized notification was sent after the initialize response":"The initialized notification was not sent \u2014 the server may not consider the session active",specVersion:P,specReference:"MCP spec \xA73.1 (Initialization)",confidence:"deterministic",details:{initializedSent:n.initializedSent}})}function Nn(n,e,t){if(n===null){t.push({checkId:"INIT-008",name:"Capability negotiation cross-check",category:"initialization",level:"info",description:"Cannot cross-check capability negotiation \u2014 capabilities object was not available",specVersion:P,specReference:"MCP spec \xA73.1 (Capability Negotiation)",confidence:"deterministic"});return}let r="tools"in n&&n.tools!==void 0,o=e.toolsListResponses,s=o.length===0||o.every(h=>"error"in h&&h.error!==void 0);r&&s?t.push({checkId:"INIT-008",name:"tools capability vs tools/list response",category:"initialization",level:"failure",description:"Server declared tools capability but tools/list returned an error or no response",specVersion:P,specReference:"MCP spec \xA73.1 (Capability Negotiation)",confidence:"deterministic",details:{toolsDeclared:r,toolsListResponseCount:o.length}}):t.push({checkId:"INIT-008",name:"tools capability vs tools/list response",category:"initialization",level:"pass",description:r?"Server declared tools capability and tools/list responded successfully":"Server did not declare tools capability \u2014 tools/list check not required",specVersion:P,specReference:"MCP spec \xA73.1 (Capability Negotiation)",confidence:"deterministic",details:{toolsDeclared:r}});let i="resources"in n&&n.resources!==void 0,c=e.resourcesListResponse,a=i&&(c===null||"error"in c&&c.error!==void 0);i&&a?t.push({checkId:"INIT-009",name:"resources capability vs resources/list response",category:"initialization",level:"failure",description:"Server declared resources capability but resources/list returned an error or no response",specVersion:P,specReference:"MCP spec \xA73.1 (Capability Negotiation)",confidence:"deterministic",details:{resourcesDeclared:i}}):t.push({checkId:"INIT-009",name:"resources capability vs resources/list response",category:"initialization",level:"pass",description:i?"Server declared resources capability and resources/list responded successfully":"Server did not declare resources capability \u2014 resources/list check not required",specVersion:P,specReference:"MCP spec \xA73.1 (Capability Negotiation)",confidence:"deterministic",details:{resourcesDeclared:i}});let l="prompts"in n&&n.prompts!==void 0,p=e.promptsListResponse,u=l&&(p===null||"error"in p&&p.error!==void 0);l&&u?t.push({checkId:"INIT-010",name:"prompts capability vs prompts/list response",category:"initialization",level:"failure",description:"Server declared prompts capability but prompts/list returned an error or no response",specVersion:P,specReference:"MCP spec \xA73.1 (Capability Negotiation)",confidence:"deterministic",details:{promptsDeclared:l}}):t.push({checkId:"INIT-010",name:"prompts capability vs prompts/list response",category:"initialization",level:"pass",description:l?"Server declared prompts capability and prompts/list responded successfully":"Server did not declare prompts capability \u2014 prompts/list check not required",specVersion:P,specReference:"MCP spec \xA73.1 (Capability Negotiation)",confidence:"deterministic",details:{promptsDeclared:l}});let d=o.some(h=>"result"in h&&h.result!==void 0);!r&&d&&t.push({checkId:"INIT-011",name:"Undeclared tools capability responds",category:"initialization",level:"warning",description:"Server did not declare tools capability but tools/list returned a successful response \u2014 capability advertisement is inconsistent",specVersion:P,specReference:"MCP spec \xA73.1 (Capability Negotiation)",confidence:"high",details:{toolsDeclared:r}});let m=c!==null&&"result"in c&&c.result!==void 0;!i&&m&&t.push({checkId:"INIT-012",name:"Undeclared resources capability responds",category:"initialization",level:"warning",description:"Server did not declare resources capability but resources/list returned a successful response \u2014 capability advertisement is inconsistent",specVersion:P,specReference:"MCP spec \xA73.1 (Capability Negotiation)",confidence:"high",details:{resourcesDeclared:i}});let f=p!==null&&"result"in p&&p.result!==void 0;!l&&f&&t.push({checkId:"INIT-013",name:"Undeclared prompts capability responds",category:"initialization",level:"warning",description:"Server did not declare prompts capability but prompts/list returned a successful response \u2014 capability advertisement is inconsistent",specVersion:P,specReference:"MCP spec \xA73.1 (Capability Negotiation)",confidence:"high",details:{promptsDeclared:l}})}function it(n,e){let t=[],r=Tn(n);$n(r,t);let o=_n(r,t);return An(r,n,t),In(n,t),Nn(o,n,t),t}var A="2024-11-05";function D(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function Vn(n){return typeof n=="string"&&n.trim().length>0}var mr=new Set(["string","number","integer","boolean","null","array","object"]);function J(n,e,t){if(!D(n)){if(typeof n=="boolean")return;t.push({path:e,message:`Schema node must be an object or boolean, got: ${typeof n}`});return}if("type"in n){let r=n.type;if(Array.isArray(r))for(let o of r)mr.has(o)||t.push({path:`${e}.type`,message:`Unknown type value: ${JSON.stringify(o)}`});else r!==void 0&&!mr.has(r)&&t.push({path:`${e}.type`,message:`Unknown type value: ${JSON.stringify(r)}`})}if("properties"in n){let r=n.properties;if(!D(r))t.push({path:`${e}.properties`,message:"properties must be an object"});else for(let[o,s]of Object.entries(r))J(s,`${e}.properties.${o}`,t)}if("items"in n){let r=n.items;Array.isArray(r)?r.forEach((o,s)=>J(o,`${e}.items[${s}]`,t)):J(r,`${e}.items`,t)}if("additionalProperties"in n){let r=n.additionalProperties;typeof r!="boolean"&&J(r,`${e}.additionalProperties`,t)}if("required"in n){let r=n.required;if(!Array.isArray(r))t.push({path:`${e}.required`,message:"required must be an array"});else for(let o of r)typeof o!="string"&&t.push({path:`${e}.required`,message:`required array items must be strings, got: ${typeof o}`})}for(let r of["allOf","anyOf","oneOf"])if(r in n){let o=n[r];Array.isArray(o)?o.forEach((s,i)=>J(s,`${e}.${r}[${i}]`,t)):t.push({path:`${e}.${r}`,message:`${r} must be an array`})}"not"in n&&J(n.not,`${e}.not`,t);for(let r of["definitions","$defs"])if(r in n){let o=n[r];if(!D(o))t.push({path:`${e}.${r}`,message:`${r} must be an object`});else for(let[s,i]of Object.entries(o))J(i,`${e}.${r}.${s}`,t)}}function jn(n,e,t){let r=`tools[${e}]`;if(!D(n)){t.push({checkId:"TOOL-001",name:"Tool object structure",category:"tools",level:"failure",description:`${r} is not a valid object`,specVersion:A,specReference:"MCP spec \xA75 (Tools)",confidence:"deterministic",details:{index:e}});return}let o=n.name,s=Vn(o),i=s?`"${o}"`:`#${e}`;t.push({checkId:"TOOL-001",name:"Tool name field",category:"tools",level:s?"pass":"failure",description:s?`Tool ${i} has a valid name field`:`Tool at index ${e} is missing a valid name field (got: ${JSON.stringify(o)})`,specVersion:A,specReference:"MCP spec \xA75 (Tools)",confidence:"deterministic",field:`${r}.name`,details:{index:e,name:o}});let a=typeof n.description=="string";t.push({checkId:"TOOL-002",name:"Tool description field",category:"tools",level:a?"pass":"warning",description:a?`Tool ${i} has a description field`:`Tool ${i} is missing a description field \u2014 recommended for discoverability`,specVersion:A,specReference:"MCP spec \xA75 (Tools)",confidence:"deterministic",field:`${r}.description`,details:{index:e,toolName:o}});let l=n.inputSchema,p=l!=null;if(t.push({checkId:"TOOL-003",name:"Tool inputSchema presence",category:"tools",level:p?"pass":"failure",description:p?`Tool ${i} has an inputSchema field`:`Tool ${i} is missing the required inputSchema field`,specVersion:A,specReference:"MCP spec \xA75 (Tools)",confidence:"deterministic",field:`${r}.inputSchema`,details:{index:e,toolName:o}}),!p)return;if(!D(l)){t.push({checkId:"TOOL-004",name:"Tool inputSchema type field",category:"tools",level:"failure",description:`Tool ${i} inputSchema is not a valid object`,specVersion:A,specReference:"MCP spec \xA75 (Tools)",confidence:"deterministic",field:`${r}.inputSchema`,details:{index:e,toolName:o}});return}let u=l.type,d=u==="object";t.push({checkId:"TOOL-004",name:"Tool inputSchema type field",category:"tools",level:d?"pass":"failure",description:d?`Tool ${i} inputSchema.type is "object"`:`Tool ${i} inputSchema.type must be "object" (got: ${JSON.stringify(u)})`,specVersion:A,specReference:"MCP spec \xA75 (Tools)",confidence:"deterministic",field:`${r}.inputSchema.type`,details:{index:e,toolName:o,schemaType:u}});let m=l.properties,f="properties"in l&&m!==void 0;if(f){let C=D(m);t.push({checkId:"TOOL-005",name:"Tool inputSchema properties structure",category:"tools",level:C?"pass":"failure",description:C?`Tool ${i} inputSchema.properties is a valid object`:`Tool ${i} inputSchema.properties must be an object (got: ${Array.isArray(m)?"array":typeof m})`,specVersion:A,specReference:"MCP spec \xA75 (Tools)",confidence:"deterministic",field:`${r}.inputSchema.properties`,details:{index:e,toolName:o}})}let h=l.required;if("required"in l&&h!==void 0){let C=Array.isArray(h),g=C&&h.every(x=>typeof x=="string"),b="pass",R=`Tool ${i} inputSchema.required is a valid string array`;if(!C)b="failure",R=`Tool ${i} inputSchema.required must be an array (got: ${typeof h})`;else if(!g)b="failure",R=`Tool ${i} inputSchema.required must be an array of strings`;else if(f&&D(m)){let x=new Set(Object.keys(m)),O=h.filter(V=>!x.has(V));O.length>0&&(b="failure",R=`Tool ${i} inputSchema.required references properties not defined in properties: ${O.map(V=>`"${V}"`).join(", ")}`)}t.push({checkId:"TOOL-006",name:"Tool inputSchema required array",category:"tools",level:b,description:R,specVersion:A,specReference:"MCP spec \xA75 (Tools) / JSON Schema draft-07",confidence:"deterministic",field:`${r}.inputSchema.required`,details:{index:e,toolName:o}})}let v=[];if(J(l,`${r}.inputSchema`,v),v.length>0)for(let C of v)t.push({checkId:"TOOL-007",name:"Tool inputSchema structural validity",category:"tools",level:"warning",description:`Tool ${i} inputSchema structural issue at ${C.path}: ${C.message}`,specVersion:A,specReference:"JSON Schema draft-07",confidence:"high",field:C.path,details:{index:e,toolName:o,issuePath:C.path}});else t.push({checkId:"TOOL-007",name:"Tool inputSchema structural validity",category:"tools",level:"pass",description:`Tool ${i} inputSchema passes structural JSON Schema draft-07 validation`,specVersion:A,specReference:"JSON Schema draft-07",confidence:"high",details:{index:e,toolName:o}})}function at(n,e){let t=[],r=n.tools;if(r.length===0){let o=n.initializeResponse,s=!1;if(o!==null&&"result"in o&&o.result!==null&&D(o.result)){let i=o.result.capabilities;D(i)&&"tools"in i&&(s=!0)}return t.push({checkId:"TOOL-000",name:"Tools list presence",category:"tools",level:s?"warning":"info",description:s?"Server declared tools capability but no tools were returned in tools/list":"No tools found in exchange record \u2014 tools capability may not be declared",specVersion:A,specReference:"MCP spec \xA75 (Tools)",confidence:"deterministic"}),t}t.push({checkId:"TOOL-000",name:"Tools list presence",category:"tools",level:"pass",description:`${r.length} tool(s) found in exchange record`,specVersion:A,specReference:"MCP spec \xA75 (Tools)",confidence:"deterministic",details:{count:r.length}});for(let o=0;o<r.length;o++)jn(r[o],o,t);return t}var I="2024-11-05";function ct(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function Mn(n){return typeof n=="string"&&n.trim().length>0}function lt(n,e){let t=[],r=n.resourcesListResponse;if(r===null)return t.push({checkId:"RSRC-001",name:"resources/list response presence",category:"resources",level:"info",description:"No resources/list response found \u2014 server may not support resources",specVersion:I,specReference:"MCP spec \xA76 (Resources)",confidence:"deterministic"}),t;if("error"in r&&r.error!==void 0)return t.push({checkId:"RSRC-001",name:"resources/list response presence",category:"resources",level:"info",description:`resources/list returned an error: ${r.error.message} (code: ${r.error.code})`,specVersion:I,specReference:"MCP spec \xA76 (Resources)",confidence:"deterministic",details:{errorCode:r.error.code,errorMessage:r.error.message}}),t;t.push({checkId:"RSRC-001",name:"resources/list response presence",category:"resources",level:"pass",description:"resources/list response was received from the server",specVersion:I,specReference:"MCP spec \xA76 (Resources)",confidence:"deterministic"});let o=r.result;if(!ct(o))return t.push({checkId:"RSRC-002",name:"resources array in response",category:"resources",level:"failure",description:"resources/list result is not a valid object",specVersion:I,specReference:"MCP spec \xA76 (Resources)",confidence:"deterministic",field:"result"}),t;let s=o.resources,i=Array.isArray(s);if(t.push({checkId:"RSRC-002",name:"resources array in response",category:"resources",level:i?"pass":"failure",description:i?`resources/list result contains a resources array with ${s.length} item(s)`:`resources/list result.resources is not an array (got: ${typeof s})`,specVersion:I,specReference:"MCP spec \xA76 (Resources)",confidence:"deterministic",field:"result.resources",details:i?{count:s.length}:{}}),!i)return t;let c=s;for(let d=0;d<c.length;d++){let m=c[d],f=`resources[${d}]`;if(!ct(m)){t.push({checkId:"RSRC-003",name:"Resource object structure",category:"resources",level:"failure",description:`${f} is not a valid object`,specVersion:I,specReference:"MCP spec \xA76 (Resources)",confidence:"deterministic",details:{index:d}});continue}let h=m.uri,y=m.name,v=Mn(y)?`"${y}"`:`#${d}`,C=typeof h=="string";t.push({checkId:"RSRC-003",name:"Resource uri field",category:"resources",level:C?"pass":"failure",description:C?`Resource ${v} has a valid uri field: "${h}"`:`Resource ${v} is missing a valid uri field (got: ${JSON.stringify(h)})`,specVersion:I,specReference:"MCP spec \xA76 (Resources)",confidence:"deterministic",field:`${f}.uri`,details:{index:d,uri:h}});let g=typeof y=="string";t.push({checkId:"RSRC-004",name:"Resource name field",category:"resources",level:g?"pass":"failure",description:g?`Resource ${v} has a valid name field`:`Resource at index ${d} is missing a valid name field (got: ${JSON.stringify(y)})`,specVersion:I,specReference:"MCP spec \xA76 (Resources)",confidence:"deterministic",field:`${f}.name`,details:{index:d,name:y}})}let a=n.resourceReadResponse;if(a===null)return t.push({checkId:"RSRC-005",name:"resources/read response contents",category:"resources",level:"info",description:"No resources/read response found \u2014 read validation skipped",specVersion:I,specReference:"MCP spec \xA76 (Resources)",confidence:"deterministic"}),t;if("error"in a&&a.error!==void 0)return t.push({checkId:"RSRC-005",name:"resources/read response contents",category:"resources",level:"failure",description:`resources/read returned an error: ${a.error.message} (code: ${a.error.code})`,specVersion:I,specReference:"MCP spec \xA76 (Resources)",confidence:"deterministic",details:{errorCode:a.error.code,errorMessage:a.error.message}}),t;let l=a.result;if(!ct(l))return t.push({checkId:"RSRC-005",name:"resources/read response contents",category:"resources",level:"failure",description:"resources/read result is not a valid object",specVersion:I,specReference:"MCP spec \xA76 (Resources)",confidence:"deterministic",field:"result"}),t;let p=l.contents,u=Array.isArray(p);return t.push({checkId:"RSRC-005",name:"resources/read response contents",category:"resources",level:u?"pass":"failure",description:u?`resources/read result contains a contents array with ${p.length} item(s)`:`resources/read result.contents is not an array (got: ${typeof p})`,specVersion:I,specReference:"MCP spec \xA76 (Resources)",confidence:"deterministic",field:"result.contents",details:u?{count:p.length}:{}}),t}var T="2024-11-05";function pt(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function ut(n){return typeof n=="string"&&n.trim().length>0}function dt(n,e){let t=[],r=n.promptsListResponse;if(r===null)return t.push({checkId:"PROMPT-001",name:"prompts/list response presence",category:"prompts",level:"info",description:"No prompts/list response found \u2014 server may not support prompts",specVersion:T,specReference:"MCP spec \xA77 (Prompts)",confidence:"deterministic"}),t;if("error"in r&&r.error!==void 0)return t.push({checkId:"PROMPT-001",name:"prompts/list response presence",category:"prompts",level:"info",description:`prompts/list returned an error: ${r.error.message} (code: ${r.error.code})`,specVersion:T,specReference:"MCP spec \xA77 (Prompts)",confidence:"deterministic",details:{errorCode:r.error.code,errorMessage:r.error.message}}),t;t.push({checkId:"PROMPT-001",name:"prompts/list response presence",category:"prompts",level:"pass",description:"prompts/list response was received from the server",specVersion:T,specReference:"MCP spec \xA77 (Prompts)",confidence:"deterministic"});let o=r.result;if(!pt(o))return t.push({checkId:"PROMPT-002",name:"prompts array in response",category:"prompts",level:"failure",description:"prompts/list result is not a valid object",specVersion:T,specReference:"MCP spec \xA77 (Prompts)",confidence:"deterministic",field:"result"}),t;let s=o.prompts,i=Array.isArray(s);if(t.push({checkId:"PROMPT-002",name:"prompts array in response",category:"prompts",level:i?"pass":"failure",description:i?`prompts/list result contains a prompts array with ${s.length} item(s)`:`prompts/list result.prompts is not an array (got: ${typeof s})`,specVersion:T,specReference:"MCP spec \xA77 (Prompts)",confidence:"deterministic",field:"result.prompts",details:i?{count:s.length}:{}}),!i)return t;let c=s;for(let a=0;a<c.length;a++){let l=c[a],p=`prompts[${a}]`;if(!pt(l)){t.push({checkId:"PROMPT-003",name:"Prompt object structure",category:"prompts",level:"failure",description:`${p} is not a valid object`,specVersion:T,specReference:"MCP spec \xA77 (Prompts)",confidence:"deterministic",details:{index:a}});continue}let u=l.name,d=ut(u),m=d?`"${u}"`:`#${a}`;t.push({checkId:"PROMPT-003",name:"Prompt name field",category:"prompts",level:d?"pass":"failure",description:d?`Prompt ${m} has a valid name field`:`Prompt at index ${a} is missing a valid name field (got: ${JSON.stringify(u)})`,specVersion:T,specReference:"MCP spec \xA77 (Prompts)",confidence:"deterministic",field:`${p}.name`,details:{index:a,name:u}});let f=l.arguments;if(f==null){t.push({checkId:"PROMPT-004",name:"Prompt arguments structure",category:"prompts",level:"pass",description:`Prompt ${m} has no arguments defined`,specVersion:T,specReference:"MCP spec \xA77 (Prompts)",confidence:"deterministic",details:{index:a,promptName:u}});continue}if(!Array.isArray(f)){t.push({checkId:"PROMPT-004",name:"Prompt arguments structure",category:"prompts",level:"failure",description:`Prompt ${m} arguments must be an array (got: ${typeof f})`,specVersion:T,specReference:"MCP spec \xA77 (Prompts)",confidence:"deterministic",field:`${p}.arguments`,details:{index:a,promptName:u}});continue}t.push({checkId:"PROMPT-004",name:"Prompt arguments structure",category:"prompts",level:"pass",description:`Prompt ${m} has a valid arguments array with ${f.length} item(s)`,specVersion:T,specReference:"MCP spec \xA77 (Prompts)",confidence:"deterministic",field:`${p}.arguments`,details:{index:a,promptName:u,argCount:f.length}});let h=f;for(let y=0;y<h.length;y++){let v=h[y],C=`${p}.arguments[${y}]`;if(!pt(v)){t.push({checkId:"PROMPT-005",name:"Prompt argument object structure",category:"prompts",level:"failure",description:`Prompt ${m} argument at index ${y} is not a valid object`,specVersion:T,specReference:"MCP spec \xA77 (Prompts)",confidence:"deterministic",field:C,details:{promptIndex:a,argIndex:y,promptName:u}});continue}let g=v.name,b=v.required,R=ut(g)?`"${g}"`:`#${y}`,x=ut(g);if(t.push({checkId:"PROMPT-005",name:"Prompt argument name field",category:"prompts",level:x?"pass":"failure",description:x?`Prompt ${m} argument ${R} has a valid name field`:`Prompt ${m} argument at index ${y} is missing a valid name field (got: ${JSON.stringify(g)})`,specVersion:T,specReference:"MCP spec \xA77 (Prompts)",confidence:"deterministic",field:`${C}.name`,details:{promptIndex:a,argIndex:y,promptName:u,argName:g}}),"required"in v){let O=typeof b=="boolean";t.push({checkId:"PROMPT-006",name:"Prompt argument required field",category:"prompts",level:O?"pass":"failure",description:O?`Prompt ${m} argument ${R} has a valid required field (${b})`:`Prompt ${m} argument ${R} required field must be a boolean (got: ${typeof b})`,specVersion:T,specReference:"MCP spec \xA77 (Prompts)",confidence:"deterministic",field:`${C}.required`,details:{promptIndex:a,argIndex:y,promptName:u,argName:g,argRequired:b}})}}}return t}var ft="2024-11-05";function mt(n,e){let t=[],r=n.transportMetadata;if(r.type!=="stdio")return t;let o=r.preProtocolOutput,s=Array.isArray(o)&&o.length>0;t.push({checkId:"XPORT-001",name:"Stdio extraneous output",category:"transport",level:s?"failure":"pass",description:s?`Server emitted ${o.length} line(s) of non-JSON output before the protocol exchange \u2014 stdio MCP servers must write only JSON-RPC messages on stdout`:"No extraneous output detected before the protocol exchange",specVersion:ft,specReference:"MCP spec \xA72 (Transports) \u2014 stdio",confidence:"deterministic",details:s?{lineCount:o.length,firstLine:o[0]}:{}});let i=r.timing,c=Array.isArray(i)&&i.length>0,a=n.errors.filter(u=>u.message.toLowerCase().includes("frame")||u.message.toLowerCase().includes("delimit")||u.message.toLowerCase().includes("parse")||u.message.toLowerCase().includes("newline")),l=a.length>0;t.push({checkId:"XPORT-002",name:"Stdio line-delimited framing",category:"transport",level:l?"failure":c?"pass":"info",description:l?`Stdio framing errors detected: ${a.map(u=>u.message).join("; ")}`:c?`Stdio line-delimited framing appears correct \u2014 ${i.length} message exchange(s) completed`:"No message timings recorded \u2014 unable to verify stdio framing",specVersion:ft,specReference:"MCP spec \xA72 (Transports) \u2014 stdio",confidence:l?"deterministic":"high",details:{framingErrorCount:a.length,timingCount:i.length}});let p=s?o.filter(u=>{try{return JSON.parse(u),!1}catch{return!0}}):[];return t.push({checkId:"XPORT-003",name:"Stdio stdout JSON-only output",category:"transport",level:p.length>0?"failure":"pass",description:p.length>0?`${p.length} non-JSON line(s) detected on stdout \u2014 stdio MCP servers must not write non-JSON data to stdout`:"All stdout output appears to be valid JSON (no non-JSON lines detected)",specVersion:ft,specReference:"MCP spec \xA72 (Transports) \u2014 stdio",confidence:"deterministic",details:{nonJsonLineCount:p.length,firstNonJsonLine:p[0]??null}}),t}var Q="2024-11-05";function ht(n,e){let t=[],r=n.transportMetadata;if(r.type!=="http")return t;let o=r.httpHeaders,s=r.sseObservations,i=[];for(let[d,m]of Object.entries(o)){let f=m["content-type"]??m["Content-Type"];f!==void 0&&i.push(`${d}: ${f}`)}let c=i.length>0,a=i.some(d=>d.toLowerCase().includes("application/json")),l=i.some(d=>d.toLowerCase().includes("text/event-stream")),p=a||l;if(t.push({checkId:"XPORT-010",name:"HTTP Content-Type headers",category:"transport",level:c?p?"pass":"warning":"info",description:c?p?"HTTP responses have appropriate Content-Type headers (application/json or text/event-stream)":`HTTP responses do not have expected Content-Type headers (got: ${i.join(", ")})`:"No HTTP Content-Type headers recorded \u2014 cannot validate content types",specVersion:Q,specReference:"MCP spec \xA72 (Transports) \u2014 Streamable HTTP",confidence:c?"deterministic":"low",details:{contentTypeEntries:i,hasJsonContentType:a,hasSseContentType:l}}),s.length===0)t.push({checkId:"XPORT-011",name:"SSE format validation",category:"transport",level:"info",description:"No SSE observations recorded \u2014 SSE format check skipped",specVersion:Q,specReference:"MCP spec \xA72 (Transports) \u2014 Streamable HTTP / SSE",confidence:"deterministic"});else{let d=s.filter(v=>v.hasDataPrefix),m=s.filter(v=>!v.hasDataPrefix&&!v.hasEventType&&v.rawLine.trim().length>0&&!v.rawLine.startsWith("id:")&&!v.rawLine.startsWith(":")),f=d.length>0,h=m.length>0;t.push({checkId:"XPORT-011",name:"SSE format validation",category:"transport",level:h?"warning":f?"pass":"warning",description:h?`SSE stream contains ${m.length} line(s) that do not conform to SSE format`:f?`SSE stream format is valid \u2014 ${d.length} data line(s) observed`:"SSE observations recorded but no data: lines found \u2014 stream may be empty",specVersion:Q,specReference:"MCP spec \xA72 (Transports) \u2014 Streamable HTTP / SSE",confidence:"high",details:{totalObservations:s.length,dataLineCount:d.length,malformedLineCount:m.length}});let y=s.filter(v=>v.rawLine.trim().length>0&&!v.rawLine.startsWith(":")).filter(v=>!v.hasDataPrefix&&!v.hasEventType&&!v.rawLine.startsWith("id:"));y.length>0?t.push({checkId:"XPORT-012",name:"SSE data prefix compliance",category:"transport",level:"warning",description:`${y.length} SSE line(s) are missing the required "data:" prefix for data payloads`,specVersion:Q,specReference:"MCP spec \xA72 (Transports) \u2014 Streamable HTTP / SSE",confidence:"high",details:{violatingLineCount:y.length,exampleLine:y[0]?.rawLine??null}}):d.length>0&&t.push({checkId:"XPORT-012",name:"SSE data prefix compliance",category:"transport",level:"pass",description:'All SSE data payloads have the required "data:" prefix',specVersion:Q,specReference:"MCP spec \xA72 (Transports) \u2014 Streamable HTTP / SSE",confidence:"high",details:{dataLineCount:d.length}})}let u=[];for(let[d,m]of Object.entries(o)){let f=m["access-control-allow-origin"]??m["Access-Control-Allow-Origin"];f!==void 0&&u.push(`${d}: Access-Control-Allow-Origin: ${f}`)}return t.push({checkId:"XPORT-013",name:"CORS headers present",category:"transport",level:u.length>0?"pass":"info",description:u.length>0?`CORS headers observed on ${u.length} endpoint(s)`:"No CORS headers observed \u2014 may be an issue if the server is accessed from a browser context",specVersion:Q,specReference:"MCP spec \xA72 (Transports) \u2014 Streamable HTTP",confidence:"deterministic",details:{corsEntries:u,corsCount:u.length}}),t}var B="2024-11-05";function gt(n,e){let t=[],r=n.unknownMethodProbeResponse;if(r===null)t.push({checkId:"ERRH-001",name:"Unknown method probe response",category:"error-handling",level:"failure",description:"No response received for unknown-method probe \u2014 server must respond to unknown methods with JSON-RPC error -32601 (Method Not Found)",specVersion:B,specReference:"JSON-RPC 2.0 \xA75.1 / MCP spec \xA73 (Error Handling)",confidence:"deterministic"});else if(!("error"in r)||r.error===void 0)t.push({checkId:"ERRH-001",name:"Unknown method probe response",category:"error-handling",level:"failure",description:"Unknown-method probe returned a successful result instead of an error \u2014 server must return -32601 (Method Not Found) for unknown methods",specVersion:B,specReference:"JSON-RPC 2.0 \xA75.1 / MCP spec \xA73 (Error Handling)",confidence:"deterministic",details:{hasResult:"result"in r}});else{let i=r.error.code,c=i===-32601;t.push({checkId:"ERRH-001",name:"Unknown method probe response",category:"error-handling",level:c?"pass":"failure",description:c?"Unknown-method probe correctly returned error code -32601 (Method Not Found)":`Unknown-method probe returned error code ${i} \u2014 expected -32601 (Method Not Found)`,specVersion:B,specReference:"JSON-RPC 2.0 \xA75.1 / MCP spec \xA73 (Error Handling)",confidence:"deterministic",field:"error.code",details:{receivedCode:i,expectedCode:-32601}})}let o=n.malformedJsonProbeResponse;if(o===null)t.push({checkId:"ERRH-002",name:"Malformed JSON probe response",category:"error-handling",level:"failure",description:"No response received for malformed-JSON probe \u2014 server must respond to malformed JSON with JSON-RPC error -32700 (Parse Error)",specVersion:B,specReference:"JSON-RPC 2.0 \xA75.1 / MCP spec \xA73 (Error Handling)",confidence:"deterministic"});else if(!("error"in o)||o.error===void 0)t.push({checkId:"ERRH-002",name:"Malformed JSON probe response",category:"error-handling",level:"failure",description:"Malformed-JSON probe returned a successful result instead of an error \u2014 server must return -32700 (Parse Error) for malformed JSON",specVersion:B,specReference:"JSON-RPC 2.0 \xA75.1 / MCP spec \xA73 (Error Handling)",confidence:"deterministic",details:{hasResult:"result"in o}});else{let i=o.error.code,c=i===-32700;t.push({checkId:"ERRH-002",name:"Malformed JSON probe response",category:"error-handling",level:c?"pass":"failure",description:c?"Malformed-JSON probe correctly returned error code -32700 (Parse Error)":`Malformed-JSON probe returned error code ${i} \u2014 expected -32700 (Parse Error)`,specVersion:B,specReference:"JSON-RPC 2.0 \xA75.1 / MCP spec \xA73 (Error Handling)",confidence:"deterministic",field:"error.code",details:{receivedCode:i,expectedCode:-32700}})}let s=t.filter(i=>i.level==="failure").length;return t.push({checkId:"ERRH-003",name:"Error handling conformance summary",category:"error-handling",level:s===0?"pass":"info",description:s===0?"Server correctly handles both unknown-method and malformed-JSON error probes":`${s} error handling probe(s) failed \u2014 server error handling is not fully conformant`,specVersion:B,specReference:"JSON-RPC 2.0 \xA75.1 / MCP spec \xA73 (Error Handling)",confidence:"deterministic",details:{probeFailureCount:s}}),t}var yt=[st,it,at,lt,dt,mt,ht,gt];function vt(n,e){let t=[];for(let r of yt)try{let o=r(n,e);t.push(...o)}catch(o){t.push({checkId:"RUNNER-ERROR",name:"Validator runtime error",category:"jsonrpc-base",level:"info",description:`A validator threw an unexpected error: ${o instanceof Error?o.message:String(o)}`,specVersion:"2024-11-05",specReference:"N/A",confidence:"deterministic"})}return t}var bt={"jsonrpc-base":.2,initialization:.25,tools:.25,resources:.1,prompts:.1,transport:.1,"error-handling":0},Ct=15,Rt=7;var Hn=["jsonrpc-base","initialization","tools","resources","prompts","transport"],hr=[...Hn,"error-handling"];function Ln(n){return n.some(e=>e.checkId==="INIT-001"&&e.level==="failure")}function St(n,e,t){let r=new Map;for(let a of hr)r.set(a,[]);for(let a of n){let l=r.get(a.category);l!==void 0&&l.push(a)}let o=[];for(let a of hr){let l=r.get(a)??[],p=l.filter(y=>y.level==="failure").length,u=l.filter(y=>y.level==="warning").length,d=l.filter(y=>y.level==="pass").length,m=l.length,f=100-p*Ct-u*Rt,h=Math.max(0,f);o.push({category:a,score:h,weight:bt[a],totalChecks:m,passCount:d,failCount:p,warnCount:u})}if(Ln(n))return{overallScore:0,categoryScores:o,exitCode:0,pass:!1};let s=0,i=0;for(let a of o)a.weight>0&&(s+=a.score*a.weight,i+=a.weight);let c=i>0?s/i:0;return{overallScore:Math.round(c*10)/10,categoryScores:o,exitCode:0,pass:!0}}var gr=["info","low","medium","high","critical"];function yr(n){return gr.indexOf(n)}function Dn(n){return n==="none"?gr.length:yr(n)}function wt(n,e,t){let r=n.overallScore<t.conformanceThreshold,o=Dn(t.failOnSeverity),s=e.some(i=>!i.suppressed&&yr(i.severity)>=o);return r||s?1:0}var vr="command-injection";var Fn=/^(command|cmd|exec|shell|script|args|argv|path|file|filename|dir|directory)$/i,Jn=/\b(execute|run\s+command|shell|script|path\s+to)\b/i;function qn(n){return!!(typeof n.pattern=="string"&&n.pattern.length>0||Array.isArray(n.enum)&&n.enum.length>0)}function zn(n){return n.type==="string"||n.type===void 0}function Wn(n,e){let t=[],r=n.inputSchema?.properties;if(!r||typeof r!="object")return t;for(let[o,s]of Object.entries(r)){if(typeof s!="object"||s===null||!zn(s)||qn(s))continue;let i=s,c=Fn.test(o),a=typeof i.description=="string"&&Jn.test(i.description);if(c||a){e.count++;let l=c?`parameter name "${o}" matches shell execution pattern`:"parameter description contains execution keywords";t.push({id:`SEC-${String(e.count).padStart(3,"0")}`,checkId:vr,severity:"high",cvssScore:8.1,component:`tool "${n.name}" / param "${o}"`,title:"Command Injection Susceptibility",description:`Tool "${n.name}" has an unconstrained string parameter "${o}" \u2014 ${l}. Without a \`pattern\` or \`enum\` constraint, this parameter could be used to inject shell commands.`,remediation:`Add a \`pattern\` constraint (e.g., "^[a-zA-Z0-9_-]+$") or \`enum\` constraint to the "${o}" parameter in tool "${n.name}".`,confidence:"heuristic",evidence:{toolName:n.name,paramName:o,paramType:i.type??"string (implicit)",matchedOn:c?"parameterName":"description"},suppressed:!1})}}return t}var kt={id:vr,name:"Command Injection Susceptibility Detection",check(n){let e=n.exchange.tools;if(!Array.isArray(e)||e.length===0)return[];let t=[],r={count:0};for(let o of e){if(typeof o!="object"||o===null)continue;let s=Wn(o,r);t.push(...s)}return t}};var br="cors-wildcard";var xt={id:br,name:"CORS Wildcard Policy Detection",check(n){if(n.exchange.transportMetadata.type==="stdio")return[];let e=[],t=n.exchange.transportMetadata.httpHeaders,r=0;if(!t||typeof t!="object")return[];for(let[o,s]of Object.entries(t)){if(!s||typeof s!="object")continue;Un(s,"access-control-allow-origin")==="*"&&(r++,e.push({id:`SEC-${String(r).padStart(3,"0")}`,checkId:br,severity:"high",cvssScore:7.5,component:o,title:"CORS Wildcard Policy",description:`Endpoint "${o}" returns Access-Control-Allow-Origin: * which permits cross-origin requests from any web origin. This allows any website to invoke MCP tools on this server.`,remediation:'Restrict the Access-Control-Allow-Origin header to specific trusted origins instead of using the wildcard "*".',confidence:"deterministic",evidence:{endpoint:o,header:"Access-Control-Allow-Origin",value:"*"},suppressed:!1}))}return e}};function Un(n,e){let t=e.toLowerCase();for(let[r,o]of Object.entries(n))if(r.toLowerCase()===t)return o}var Cr="auth-gap";var Bn=new Set(["localhost","127.0.0.1","::1","[::1]"]),Gn=[/^10\./,/^172\.(1[6-9]|2\d|3[01])\./,/^192\.168\./,/^fd[0-9a-f]{2}:/i];function Yn(n){return Bn.has(n.toLowerCase())}function Kn(n){return Gn.some(e=>e.test(n))}function Xn(n){let e=new Map(Object.entries(n).map(([t,r])=>[t.toLowerCase(),r]));return e.has("www-authenticate")||e.has("authorization")}var Pt={id:Cr,name:"Authentication Gap Detection",check(n){if(n.exchange.transportMetadata.type==="stdio")return[];let e=n.exchange.transportMetadata,t=e.target,r;try{r=new URL(t).hostname}catch{return[]}if(Yn(r))return[];let o=e.httpHeaders,s=!1;if(o&&typeof o=="object"){for(let d of Object.values(o))if(d&&typeof d=="object"&&Xn(d)){s=!0;break}}if(s)return[];let i=e.resolvedAddress??r,c=e.addressType??(Kn(i)?"private":"public"),a=c==="public",l=a?"critical":"medium",p=a?9.8:6.5,u=a?"public internet":"private network";return[{id:"SEC-001",checkId:Cr,severity:l,cvssScore:p,component:t,title:"Authentication Gap",description:`MCP server at "${t}" (${u}, resolved: ${i}) responds to initialize without requiring authentication. Any client on the ${u} can invoke tools on this server.`,remediation:"Add authentication to the MCP server. Recommended approaches: Bearer token authentication, OAuth 2.0 client credentials, or mutual TLS for machine-to-machine communication.",confidence:"heuristic",evidence:{host:r,resolvedAddress:i,addressType:c,authHeaderPresent:!1,wwwAuthenticatePresent:!1},suppressed:!1}]}};var Rr="tool-poisoning";var Zn=[{pattern:/IGNORE\s+PREVIOUS/i,label:"IGNORE PREVIOUS"},{pattern:/\[SYSTEM\]/i,label:"[SYSTEM]"},{pattern:/<system>/i,label:"<system>"},{pattern:/\bDO\s+NOT\b(?=.*\b(?:tell|reveal|mention|show|share|disclose)\b)/i,label:"DO NOT (directive)"},{pattern:/\byou\s+must\b/i,label:"you must"},{pattern:/\byou\s+are\s+now\b/i,label:"you are now"},{pattern:/\bforget\s+(?:all|your|previous|everything)\b/i,label:"forget instructions"},{pattern:/\bpretend\s+(?:to\s+be|you\s+are)\b/i,label:"pretend to be"},{pattern:/\bact\s+as\s+(?:a|an|if)\b/i,label:"act as"},{pattern:/\bnew\s+instructions?\b/i,label:"new instructions"}],Qn=/<\/?(?:system|prompt|instruction|role|context|message)\b[^>]*>/i,eo=/^[A-Za-z0-9+/]{20,}={0,2}$/,to=/%[0-9A-Fa-f]{2}/,Ot={id:Rr,name:"Tool Poisoning Pattern Detection",check(n){let e=n.exchange.tools;if(!Array.isArray(e)||e.length===0)return[];let t=[],r=0;for(let o of e){if(typeof o!="object"||o===null)continue;let s=o;if(typeof s.name!="string"||(to.test(s.name)&&(r++,t.push(ce(r,s.name,"URL-encoded characters in tool name",`Tool name "${s.name}" contains URL-encoded substrings`))),eo.test(s.name)&&(r++,t.push(ce(r,s.name,"Base64-encoded tool name",`Tool name "${s.name}" appears to be Base64-encoded`))),typeof s.description!="string"))continue;let i=s.description.slice(0,1e4);i.length>2e3&&(r++,t.push(ce(r,s.name,"Suspiciously long tool description",`Tool "${s.name}" has a description of ${s.description.length} characters (threshold: 2000). Long descriptions may contain hidden instructions.`)));for(let{pattern:c,label:a}of Zn)if(c.test(i)){r++,t.push(ce(r,s.name,`Prompt injection pattern: "${a}"`,`Tool "${s.name}" description contains the pattern "${a}" which is commonly used in prompt injection attacks to hijack model behavior.`));break}Qn.test(i)&&(r++,t.push(ce(r,s.name,"XML/HTML system tags in description",`Tool "${s.name}" description contains XML/HTML tags that appear to embed system-prompt instructions.`)))}return t}};function ce(n,e,t,r){return{id:`SEC-${String(n).padStart(3,"0")}`,checkId:Rr,severity:"critical",cvssScore:8.8,component:`tool "${e}"`,title:t,description:r,remediation:`Review and sanitize the tool metadata for "${e}". Remove any instruction-like text, encoded strings, or system prompt patterns from tool names and descriptions.`,confidence:"heuristic",evidence:{toolName:e},suppressed:!1}}var Sr="info-leakage";var ro=[{pattern:/at\s+\S+\s+\([^)]+:\d+:\d+\)/,label:"Node.js stack trace"},{pattern:/at\s+Object\.<anonymous>/,label:"Node.js anonymous stack frame"},{pattern:/at\s+Function\./,label:"Node.js Function stack frame"},{pattern:/at\s+Module\._compile/,label:"Node.js module stack frame"},{pattern:/Traceback \(most recent call last\)/,label:"Python traceback"},{pattern:/File "[^"]+", line \d+/,label:"Python file reference"},{pattern:/at\s+\w+\.\w+\([^)]*\)\s+in\s+/,label:".NET stack trace"}],no=[{pattern:/\/home\/\w+/,label:"Unix home directory"},{pattern:/\/var\/\w+/,label:"Unix /var path"},{pattern:/\/usr\/\w+/,label:"Unix /usr path"},{pattern:/\/etc\/\w+/,label:"Unix /etc path"},{pattern:/\/tmp\/\w+/,label:"Unix /tmp path"},{pattern:/[A-Z]:\\Users\\/i,label:"Windows Users path"},{pattern:/[A-Z]:\\Program Files/i,label:"Windows Program Files path"}],oo=[{pattern:/process\.env\.\w+/,label:"Node.js process.env reference"},{pattern:/ENV\[\s*['"][^'"]+['"]\s*\]/,label:"ENV[] reference"},{pattern:/\$ENV_\w+/,label:"$ENV_ variable"},{pattern:/\bexport\s+\w+=/,label:"shell export statement"},{pattern:/os\.environ\b/,label:"Python os.environ reference"}];function so(n){let e=[];if(!n||typeof n!="object")return e;let t=n;if(t.error&&typeof t.error=="object"){let r=t.error;if(typeof r.message=="string"&&e.push(r.message.slice(0,1e4)),typeof r.data=="string"&&e.push(r.data.slice(0,1e4)),r.data&&typeof r.data=="object"){let o=r.data;typeof o.message=="string"&&e.push(o.message.slice(0,1e4)),typeof o.stack=="string"&&e.push(o.stack.slice(0,1e4))}}return e}function io(n){let e=/^(Method not found|Internal error|Invalid params|Parse error|Invalid request|Server error)$/i;return n.length<100&&e.test(n.trim())}var $t={id:Sr,name:"Information Leakage Detection",check(n){let e=[],t=0,r=[n.exchange.unknownMethodProbeResponse,n.exchange.malformedJsonProbeResponse];for(let o of r){if(!o)continue;let s=so(o);for(let i of s)if(!io(i)){for(let{pattern:c,label:a}of ro)if(c.test(i)){t++,e.push(Et(t,a,`Error response contains ${a} indicating verbose error output. Stack traces reveal internal code structure and file locations.`,Tt(i,c)));break}for(let{pattern:c,label:a}of no)if(c.test(i)){t++,e.push(Et(t,a,`Error response contains ${a} exposing internal server filesystem structure.`,Tt(i,c)));break}for(let{pattern:c,label:a}of oo)if(c.test(i)){t++,e.push(Et(t,a,`Error response contains ${a} exposing server environment configuration.`,Tt(i,c)));break}}}return e}};function Et(n,e,t,r){return{id:`SEC-${String(n).padStart(3,"0")}`,checkId:Sr,severity:"medium",cvssScore:5.3,component:"error response",title:`Information Leakage: ${e}`,description:t,remediation:"Return generic error messages in production. Avoid including stack traces, file paths, or environment variable names in error responses.",confidence:"deterministic",evidence:{matchType:e,snippet:r},suppressed:!1}}function Tt(n,e){let t=n.match(e);if(!t||t.index===void 0)return"[redacted]";let r=Math.max(0,t.index-15),o=Math.min(n.length,t.index+t[0].length+15),s=n.slice(r,o);return r>0&&(s="..."+s),o<n.length&&(s=s+"..."),s}var ao=[kt,xt,Pt,Ot,$t];function _t(n,e){let t={exchange:n,config:e},r=[],o=0;for(let s of ao){let i=s.check(t);for(let c of i){if(o++,c.id=`SEC-${String(o).padStart(3,"0")}`,e.skip.includes(c.checkId)){c.suppressed=!0;let a=e.skipJustifications[c.checkId];a!==void 0&&(c.justification=a)}r.push(c)}}return r}Se();var le=class{config;constructor(e){this.config=e}format(e){let t={schemaVersion:"1.0",meta:{toolVersion:e.meta.toolVersion,specVersion:e.meta.specVersion,timestamp:e.meta.timestamp,target:e.meta.target,transport:e.meta.transport,durationMs:e.meta.durationMs,checkMode:this.config.checkMode,thresholds:{conformanceThreshold:this.config.conformanceThreshold,failOnSeverity:this.config.failOnSeverity}},conformance:{score:e.conformance.score,breakdown:e.conformance.breakdown,violations:e.conformance.violations},security:{findings:e.security.findings,suppressed:e.security.suppressed},summary:{pass:e.summary.pass,exitCode:e.summary.exitCode,blockerCount:e.summary.blockerCount}};return JSON.stringify(t,null,2)}};var Er={"jsonrpc-base":"JSON-RPC Base",initialization:"Initialization",tools:"Tools",resources:"Resources",prompts:"Prompts",transport:"Transport","error-handling":"Error Handling"},Co=["jsonrpc-base","initialization","tools","resources","prompts","transport"],we=["jsonrpc-base","initialization","tools","resources","prompts","transport","error-handling"];function Ro(n){return n==="http"?"HTTP+SSE":"stdio"}function So(n){return n<1e3?`${n}ms`:`${(n/1e3).toFixed(1)}s`}function ke(n,e){let t=n.length,r=n.map(a=>a.length);for(let a of e)for(let l=0;l<t;l++){let p=a[l]??"";p.length>(r[l]??0)&&(r[l]=p.length)}function o(a,l){return a.padEnd(r[l]??a.length," ")}let s="| "+n.map((a,l)=>o(a,l)).join(" | ")+" |",i="| "+r.map(a=>"-".repeat(Math.max(a,1))).join(" | ")+" |",c=e.map(a=>"| "+a.map((l,p)=>o(l,p)).join(" | ")+" |");return[s,i,...c].join(`
|
|
29
|
+
`)}function wo(n){let{meta:e}=n,t=[["Target",e.target],["Transport",Ro(e.transport)],["Tool Version",e.toolVersion],["Spec Version",`MCP ${e.specVersion}`],["Timestamp",e.timestamp],["Duration",So(e.durationMs)],["Check Mode",e.checkMode]];return ke(["Field","Value"],t)}function ko(n){let{conformance:e,security:t,summary:r}=n,o=t.findings,s=0,i=0,c=0,a=0;for(let u of o)switch(u.severity){case"critical":s++;break;case"high":i++;break;case"medium":c++;break;case"low":a++;break;default:break}let l=r.pass?"PASS":"FAIL",p=[["Conformance Score",`${e.score}/100`],["Critical Findings",String(s)],["High Findings",String(i)],["Medium Findings",String(c)],["Low Findings",String(a)],["**Verdict**",`**${l}**`]];return ke(["Metric","Value"],p)}function xo(n){let e=new Map;for(let t of we)e.set(t,{totalChecks:0,failures:0,warnings:0});for(let t of n){let r=e.get(t.category);r!==void 0&&(r.totalChecks++,t.level==="failure"&&r.failures++,t.level==="warning"&&r.warnings++)}return e}function Po(n){let{conformance:e}=n,t=xo(e.violations),r=[];for(let o of we){let s=Er[o],i=t.get(o)??{totalChecks:0,failures:0,warnings:0},c=Co.includes(o)?String(e.breakdown[o]??0):"N/A";r.push([s,c,String(i.totalChecks),String(i.failures),String(i.warnings)])}return ke(["Category","Score","Checks","Failures","Warnings"],r)}function Oo(n){let{conformance:e}=n,t=[],r=new Map;for(let o of we)r.set(o,[]);for(let o of e.violations){let s=r.get(o.category);s!==void 0&&s.push(o)}for(let o of we){let s=Er[o];t.push(`### ${s}`);let c=(r.get(o)??[]).filter(a=>a.level!=="pass");if(c.length===0)t.push("- [x] All checks passed");else for(let a of c){let l=a.level==="failure"?"[FAIL]":a.level==="warning"?"[WARN]":"[INFO]",p=a.field!==void 0?` (field: \`${a.field}\`)`:"";t.push(`- [ ] **${l}** ${a.description}${p} (${a.checkId})`)}t.push("")}return t.length>0&&t[t.length-1]===""&&t.pop(),t.join(`
|
|
30
|
+
`)}function Eo(n){let{security:e}=n,t=e.findings;if(t.length===0)return"_No active security findings._";let r=[];for(let o of t)r.push(`### ${o.checkId}: ${o.title}`),r.push(`- **Severity:** ${o.severity.charAt(0).toUpperCase()}${o.severity.slice(1)} | **CVSS:** ${o.cvssScore} | **Confidence:** ${o.confidence}`),r.push(`- **Component:** ${o.component}`),r.push(`- **Description:** ${o.description}`),r.push(`- **Remediation:** ${o.remediation}`),r.push("");return r.length>0&&r[r.length-1]===""&&r.pop(),r.join(`
|
|
31
|
+
`)}function To(n){let{suppressed:e}=n.security;if(e.length===0)return"_No suppressed findings._";let t=e.map(r=>[`${r.title} (${r.checkId})`,r.severity.charAt(0).toUpperCase()+r.severity.slice(1),r.justification??"_No justification provided_"]);return ke(["Finding","Severity","Justification"],t)}var pe=class{format(e){let{meta:t}=e,r=[];return r.push("# MCP Verify Report"),r.push(""),r.push(wo(e)),r.push(""),r.push("## Summary"),r.push(""),r.push(ko(e)),r.push(""),r.push("## Conformance Score"),r.push(""),r.push(Po(e)),r.push(""),r.push("## Conformance Violations"),r.push(""),r.push(Oo(e)),r.push(""),r.push("## Security Findings"),r.push(""),r.push(Eo(e)),r.push(""),r.push("## Suppressed Findings"),r.push(""),r.push(To(e)),r.push(""),r.push("---"),r.push(`*Generated by mcp-verify ${t.toolVersion} | MCP spec ${t.specVersion} | ${t.timestamp}*`),r.join(`
|
|
32
|
+
`)}};Se();function It(n){switch(n.format){case"terminal":return new re(n.noColor);case"json":return new le(n);case"markdown":return new pe;case"sarif":throw new Error(`${n.format} reporter not yet implemented (Sprint 3)`);default:throw new Error(`Unknown format: ${n.format}`)}}var ue=require("fs"),Nt=require("path"),$o=["mcp-verify.json",".mcp-verify.json"];function _o(n,e){let t;try{t=JSON.parse(n)}catch(r){let o=r instanceof Error?r.message:String(r);process.stderr.write(`Error: Config file "${e}" contains invalid JSON: ${o}
|
|
33
|
+
`),process.exit(2)}return(typeof t!="object"||t===null||Array.isArray(t))&&(process.stderr.write(`Error: Config file "${e}" must be a JSON object at the top level.
|
|
34
|
+
`),process.exit(2)),t}function Tr(n){let e=(0,ue.readFileSync)(n,"utf-8");return _o(e,n)}function xe(n,e=process.cwd()){if(n!==void 0){let t=(0,Nt.resolve)(e,n);return(0,ue.existsSync)(t)||(process.stderr.write(`Error: Config file not found: "${t}"
|
|
35
|
+
`),process.exit(2)),Tr(t)}for(let t of $o){let r=(0,Nt.resolve)(e,t);if((0,ue.existsSync)(r))return Tr(r)}return null}function Pe(n,e,t){let r=n.skip!==void 0?n.skip:e?.skip!==void 0?e.skip.map(s=>s.checkId):k.skip,o=n.skipJustifications!==void 0?n.skipJustifications:e?.skip!==void 0?Object.fromEntries(e.skip.filter(s=>s.justification!==void 0).map(s=>[s.checkId,s.justification])):k.skipJustifications;return{target:t,timeout:n.timeout!==void 0?n.timeout:e?.timeout!==void 0?e.timeout:k.timeout,format:n.format!==void 0?n.format:e?.format!==void 0?e.format:k.format,transport:n.transport!==void 0?n.transport:e?.transport!==void 0?e.transport:k.transport,failOnSeverity:n.failOnSeverity!==void 0?n.failOnSeverity:e?.failOnSeverity!==void 0?e.failOnSeverity:k.failOnSeverity,conformanceThreshold:n.conformanceThreshold!==void 0?n.conformanceThreshold:e?.conformanceThreshold!==void 0?e.conformanceThreshold:k.conformanceThreshold,skip:r,skipJustifications:o,checkMode:n.checkMode!==void 0?n.checkMode:e?.checkMode!==void 0?e.checkMode:k.checkMode,noColor:n.noColor!==void 0?n.noColor:k.noColor,verbose:n.verbose!==void 0?n.verbose:e?.verbose!==void 0?e.verbose:k.verbose,output:n.output!==void 0?n.output:e?.output!==void 0?e.output:k.output,noHistory:n.noHistory!==void 0?n.noHistory:k.noHistory}}var j=require("fs"),Vt=require("path"),$r=require("os");function ne(n){process.env.DEBUG&&process.stderr.write(`[mcp-verify:history] ${n}
|
|
36
|
+
`)}var N=class{getHistoryDir(){let e=(0,Vt.join)((0,$r.homedir)(),".mcp-verify","history");if(!(0,j.existsSync)(e))try{(0,j.mkdirSync)(e,{recursive:!0})}catch(t){return ne(`Could not create history directory "${e}": ${t instanceof Error?t.message:String(t)}`),null}return e}encodeTarget(e){return encodeURIComponent(e).replace(/%/g,"_")}targetFilePath(e,t){return(0,Vt.join)(e,`${this.encodeTarget(t)}.jsonl`)}appendRun(e,t){let r=this.getHistoryDir();if(r===null){ne(`Skipping history append for target "${e}" \u2014 directory unavailable`);return}let o=this.targetFilePath(r,e),s=JSON.stringify(t)+`
|
|
37
|
+
`;try{(0,j.appendFileSync)(o,s,"utf-8")}catch(i){ne(`Could not append history for target "${e}" at "${o}": ${i instanceof Error?i.message:String(i)}`)}}getHistory(e){let t=this.getHistoryDir();if(t===null)return[];let r=this.targetFilePath(t,e);if(!(0,j.existsSync)(r))return[];let o;try{o=(0,j.readFileSync)(r,"utf-8")}catch(i){return ne(`Could not read history for target "${e}" at "${r}": ${i instanceof Error?i.message:String(i)}`),[]}let s=[];for(let i of o.split(`
|
|
38
|
+
`)){let c=i.trim();if(c.length!==0)try{s.push(JSON.parse(c))}catch{ne(`Skipping malformed JSONL line in "${r}": ${c}`)}}return s}getLatestRun(e){let t=this.getHistory(e);return t.length>0?t[t.length-1]??null:null}getAllTargets(){let e=this.getHistoryDir();if(e===null)return[];let t;try{t=(0,j.readdirSync)(e)}catch(r){return ne(`Could not list history directory "${e}": ${r instanceof Error?r.message:String(r)}`),[]}return t.filter(r=>r.endsWith(".jsonl")).map(r=>{let o=r.slice(0,-6);try{return decodeURIComponent(o.replace(/_/g,"%"))}catch{return o}})}};function _r(n){return`${n.checkId}::${n.title}`}function Ar(n){return n.description.trim().length>0?n.description:n.title}function jt(n,e,t=[],r=[]){let o=n.conformanceScore,s=e.conformanceScore,i=s-o,c=new Map;for(let u of t)u.suppressed||c.set(_r(u),Ar(u));let a=new Map;for(let u of r)u.suppressed||a.set(_r(u),Ar(u));let l=[];for(let[u,d]of a)c.has(u)||l.push(d);let p=[];for(let[u,d]of c)a.has(u)||p.push(d);return{previousScore:o,currentScore:s,scoreDelta:i,previousFindingsCount:n.securityFindingsCount,currentFindingsCount:e.securityFindingsCount,newFindings:l,resolvedFindings:p,isRegression:i<0}}var F=require("fs"),de=require("path"),Ir=require("os");var Nr=new N;function Vr(n){process.env.DEBUG&&process.stderr.write(`[mcp-verify:baseline] ${n}
|
|
39
|
+
`)}function Mt(n){let e=n!==void 0?(0,de.join)(n,".mcp-verify","baselines"):(0,de.join)((0,Ir.homedir)(),".mcp-verify","baselines");if(!(0,F.existsSync)(e))try{(0,F.mkdirSync)(e,{recursive:!0})}catch(t){return Vr(`Could not create baselines directory "${e}": ${t instanceof Error?t.message:String(t)}`),null}return e}function Oe(n,e,t){let r=Mt(t);if(r===null)throw new Error(`Cannot save baseline for "${n}": baseline directory is not writable`);let o=Nr.encodeTarget(n),s=(0,de.join)(r,`${o}.json`);try{(0,F.writeFileSync)(s,JSON.stringify(e,null,2)+`
|
|
40
|
+
`,"utf-8")}catch(i){throw new Error(`Cannot save baseline for "${n}" at "${s}": ${i instanceof Error?i.message:String(i)}`)}}function Ht(n,e){let t=Mt(e);if(t===null)return null;let r=Nr.encodeTarget(n),o=(0,de.join)(t,`${r}.json`);if(!(0,F.existsSync)(o))return null;let s;try{s=(0,F.readFileSync)(o,"utf-8")}catch(i){return Vr(`Could not read baseline for "${n}" at "${o}": ${i instanceof Error?i.message:String(i)}`),null}try{return JSON.parse(s)}catch(i){throw new Error(`Baseline file for "${n}" at "${o}" contains invalid JSON: ${i instanceof Error?i.message:String(i)}`)}}var jr=require("http");var Lt=`<!DOCTYPE html>
|
|
41
|
+
<html lang="en">
|
|
42
|
+
<head>
|
|
43
|
+
<meta charset="UTF-8" />
|
|
44
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
45
|
+
<meta http-equiv="Content-Security-Policy"
|
|
46
|
+
content="default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'" />
|
|
47
|
+
<title>MCP Verify Dashboard</title>
|
|
48
|
+
<style>
|
|
49
|
+
/* ------------------------------------------------------------------ */
|
|
50
|
+
/* Reset & base */
|
|
51
|
+
/* ------------------------------------------------------------------ */
|
|
52
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
53
|
+
|
|
54
|
+
:root {
|
|
55
|
+
--bg: #0d1117;
|
|
56
|
+
--surface: #161b22;
|
|
57
|
+
--border: #30363d;
|
|
58
|
+
--text: #c9d1d9;
|
|
59
|
+
--text-dim: #8b949e;
|
|
60
|
+
--accent: #58a6ff;
|
|
61
|
+
--green: #3fb950;
|
|
62
|
+
--yellow: #d29922;
|
|
63
|
+
--red: #f85149;
|
|
64
|
+
--orange: #e3935a;
|
|
65
|
+
--blue: #58a6ff;
|
|
66
|
+
--font: 'Courier New', Courier, monospace;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
html, body {
|
|
70
|
+
background: var(--bg);
|
|
71
|
+
color: var(--text);
|
|
72
|
+
font-family: var(--font);
|
|
73
|
+
font-size: 14px;
|
|
74
|
+
min-height: 100vh;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
a { color: var(--accent); text-decoration: none; }
|
|
78
|
+
a:hover { text-decoration: underline; }
|
|
79
|
+
|
|
80
|
+
/* ------------------------------------------------------------------ */
|
|
81
|
+
/* Header */
|
|
82
|
+
/* ------------------------------------------------------------------ */
|
|
83
|
+
header {
|
|
84
|
+
background: var(--surface);
|
|
85
|
+
border-bottom: 1px solid var(--border);
|
|
86
|
+
padding: 12px 24px;
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
gap: 16px;
|
|
90
|
+
}
|
|
91
|
+
header h1 {
|
|
92
|
+
font-size: 16px;
|
|
93
|
+
font-weight: bold;
|
|
94
|
+
color: var(--accent);
|
|
95
|
+
letter-spacing: 0.05em;
|
|
96
|
+
}
|
|
97
|
+
#back-link { display: none; font-size: 13px; }
|
|
98
|
+
#back-link.visible { display: inline; }
|
|
99
|
+
|
|
100
|
+
/* ------------------------------------------------------------------ */
|
|
101
|
+
/* Main layout */
|
|
102
|
+
/* ------------------------------------------------------------------ */
|
|
103
|
+
main { padding: 24px; max-width: 1200px; margin: 0 auto; }
|
|
104
|
+
|
|
105
|
+
/* ------------------------------------------------------------------ */
|
|
106
|
+
/* Views */
|
|
107
|
+
/* ------------------------------------------------------------------ */
|
|
108
|
+
.view { display: none; }
|
|
109
|
+
.view.active { display: block; }
|
|
110
|
+
|
|
111
|
+
/* ------------------------------------------------------------------ */
|
|
112
|
+
/* Portfolio table */
|
|
113
|
+
/* ------------------------------------------------------------------ */
|
|
114
|
+
#portfolio h2 {
|
|
115
|
+
font-size: 15px;
|
|
116
|
+
margin-bottom: 16px;
|
|
117
|
+
color: var(--text-dim);
|
|
118
|
+
text-transform: uppercase;
|
|
119
|
+
letter-spacing: 0.08em;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.table-wrap { overflow-x: auto; }
|
|
123
|
+
|
|
124
|
+
table {
|
|
125
|
+
width: 100%;
|
|
126
|
+
border-collapse: collapse;
|
|
127
|
+
font-size: 13px;
|
|
128
|
+
}
|
|
129
|
+
th {
|
|
130
|
+
background: var(--surface);
|
|
131
|
+
border: 1px solid var(--border);
|
|
132
|
+
padding: 8px 12px;
|
|
133
|
+
text-align: left;
|
|
134
|
+
color: var(--text-dim);
|
|
135
|
+
text-transform: uppercase;
|
|
136
|
+
letter-spacing: 0.06em;
|
|
137
|
+
cursor: pointer;
|
|
138
|
+
user-select: none;
|
|
139
|
+
white-space: nowrap;
|
|
140
|
+
}
|
|
141
|
+
th:hover { color: var(--text); }
|
|
142
|
+
th.sort-asc::after { content: ' \u25B2'; }
|
|
143
|
+
th.sort-desc::after { content: ' \u25BC'; }
|
|
144
|
+
|
|
145
|
+
td {
|
|
146
|
+
border: 1px solid var(--border);
|
|
147
|
+
padding: 8px 12px;
|
|
148
|
+
white-space: nowrap;
|
|
149
|
+
}
|
|
150
|
+
tr:hover td { background: var(--surface); }
|
|
151
|
+
|
|
152
|
+
.score-green { color: var(--green); font-weight: bold; }
|
|
153
|
+
.score-yellow { color: var(--yellow); font-weight: bold; }
|
|
154
|
+
.score-red { color: var(--red); font-weight: bold; }
|
|
155
|
+
|
|
156
|
+
.trend-up { color: var(--green); }
|
|
157
|
+
.trend-down { color: var(--red); }
|
|
158
|
+
.trend-stable { color: var(--text-dim); }
|
|
159
|
+
|
|
160
|
+
.server-link { cursor: pointer; color: var(--accent); }
|
|
161
|
+
.server-link:hover { text-decoration: underline; }
|
|
162
|
+
|
|
163
|
+
.empty-state {
|
|
164
|
+
padding: 40px;
|
|
165
|
+
text-align: center;
|
|
166
|
+
color: var(--text-dim);
|
|
167
|
+
border: 1px dashed var(--border);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* ------------------------------------------------------------------ */
|
|
171
|
+
/* Detail view */
|
|
172
|
+
/* ------------------------------------------------------------------ */
|
|
173
|
+
#detail h2 {
|
|
174
|
+
font-size: 15px;
|
|
175
|
+
margin-bottom: 4px;
|
|
176
|
+
color: var(--text);
|
|
177
|
+
word-break: break-all;
|
|
178
|
+
}
|
|
179
|
+
#detail-subtitle {
|
|
180
|
+
font-size: 12px;
|
|
181
|
+
color: var(--text-dim);
|
|
182
|
+
margin-bottom: 24px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.chart-section {
|
|
186
|
+
margin-bottom: 32px;
|
|
187
|
+
}
|
|
188
|
+
.chart-section h3 {
|
|
189
|
+
font-size: 13px;
|
|
190
|
+
color: var(--text-dim);
|
|
191
|
+
text-transform: uppercase;
|
|
192
|
+
letter-spacing: 0.06em;
|
|
193
|
+
margin-bottom: 12px;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.chart-container {
|
|
197
|
+
background: var(--surface);
|
|
198
|
+
border: 1px solid var(--border);
|
|
199
|
+
border-radius: 4px;
|
|
200
|
+
padding: 16px;
|
|
201
|
+
overflow-x: auto;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
svg.chart {
|
|
205
|
+
display: block;
|
|
206
|
+
overflow: visible;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* Chart legend */
|
|
210
|
+
.legend {
|
|
211
|
+
display: flex;
|
|
212
|
+
flex-wrap: wrap;
|
|
213
|
+
gap: 12px;
|
|
214
|
+
margin-top: 10px;
|
|
215
|
+
font-size: 12px;
|
|
216
|
+
}
|
|
217
|
+
.legend-item {
|
|
218
|
+
display: flex;
|
|
219
|
+
align-items: center;
|
|
220
|
+
gap: 6px;
|
|
221
|
+
cursor: pointer;
|
|
222
|
+
opacity: 1;
|
|
223
|
+
transition: opacity 0.15s;
|
|
224
|
+
}
|
|
225
|
+
.legend-item.hidden { opacity: 0.35; }
|
|
226
|
+
.legend-swatch {
|
|
227
|
+
width: 12px;
|
|
228
|
+
height: 12px;
|
|
229
|
+
border-radius: 2px;
|
|
230
|
+
flex-shrink: 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* Category toggle buttons */
|
|
234
|
+
.category-toggles {
|
|
235
|
+
display: flex;
|
|
236
|
+
flex-wrap: wrap;
|
|
237
|
+
gap: 8px;
|
|
238
|
+
margin-bottom: 10px;
|
|
239
|
+
}
|
|
240
|
+
.cat-toggle {
|
|
241
|
+
background: var(--bg);
|
|
242
|
+
border: 1px solid var(--border);
|
|
243
|
+
border-radius: 3px;
|
|
244
|
+
padding: 3px 8px;
|
|
245
|
+
font-size: 11px;
|
|
246
|
+
font-family: var(--font);
|
|
247
|
+
color: var(--text-dim);
|
|
248
|
+
cursor: pointer;
|
|
249
|
+
}
|
|
250
|
+
.cat-toggle.active {
|
|
251
|
+
color: var(--text);
|
|
252
|
+
border-color: var(--accent);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* ------------------------------------------------------------------ */
|
|
256
|
+
/* Loading / error states */
|
|
257
|
+
/* ------------------------------------------------------------------ */
|
|
258
|
+
.loading {
|
|
259
|
+
padding: 32px;
|
|
260
|
+
text-align: center;
|
|
261
|
+
color: var(--text-dim);
|
|
262
|
+
}
|
|
263
|
+
.error-msg {
|
|
264
|
+
padding: 16px;
|
|
265
|
+
background: #2d1a1a;
|
|
266
|
+
border: 1px solid var(--red);
|
|
267
|
+
border-radius: 4px;
|
|
268
|
+
color: var(--red);
|
|
269
|
+
margin-bottom: 16px;
|
|
270
|
+
}
|
|
271
|
+
</style>
|
|
272
|
+
</head>
|
|
273
|
+
<body>
|
|
274
|
+
<header>
|
|
275
|
+
<h1>MCP Verify Dashboard</h1>
|
|
276
|
+
<a id="back-link" href="#" onclick="showPortfolio(); return false;">← All Servers</a>
|
|
277
|
+
</header>
|
|
278
|
+
|
|
279
|
+
<main>
|
|
280
|
+
<!-- ---------------------------------------------------------------- -->
|
|
281
|
+
<!-- Portfolio view -->
|
|
282
|
+
<!-- ---------------------------------------------------------------- -->
|
|
283
|
+
<section id="portfolio" class="view active">
|
|
284
|
+
<h2>Tracked Servers</h2>
|
|
285
|
+
<div id="portfolio-content"><div class="loading">Loading...</div></div>
|
|
286
|
+
</section>
|
|
287
|
+
|
|
288
|
+
<!-- ---------------------------------------------------------------- -->
|
|
289
|
+
<!-- Detail view -->
|
|
290
|
+
<!-- ---------------------------------------------------------------- -->
|
|
291
|
+
<section id="detail" class="view">
|
|
292
|
+
<h2 id="detail-title"></h2>
|
|
293
|
+
<p id="detail-subtitle"></p>
|
|
294
|
+
|
|
295
|
+
<div id="detail-content"></div>
|
|
296
|
+
</section>
|
|
297
|
+
</main>
|
|
298
|
+
|
|
299
|
+
<script>
|
|
300
|
+
/* ==================================================================
|
|
301
|
+
State
|
|
302
|
+
================================================================== */
|
|
303
|
+
let portfolioData = [];
|
|
304
|
+
let sortKey = 'latestScore';
|
|
305
|
+
let sortDir = 'desc';
|
|
306
|
+
let currentTarget = null;
|
|
307
|
+
let activeCategories = new Set();
|
|
308
|
+
|
|
309
|
+
/* ==================================================================
|
|
310
|
+
Navigation
|
|
311
|
+
================================================================== */
|
|
312
|
+
function showPortfolio() {
|
|
313
|
+
document.getElementById('portfolio').classList.add('active');
|
|
314
|
+
document.getElementById('detail').classList.remove('active');
|
|
315
|
+
document.getElementById('back-link').classList.remove('visible');
|
|
316
|
+
currentTarget = null;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function showDetail(target) {
|
|
320
|
+
currentTarget = target;
|
|
321
|
+
document.getElementById('portfolio').classList.remove('active');
|
|
322
|
+
document.getElementById('detail').classList.add('active');
|
|
323
|
+
document.getElementById('back-link').classList.add('visible');
|
|
324
|
+
document.getElementById('detail-title').textContent = target;
|
|
325
|
+
document.getElementById('detail-subtitle').textContent = 'Loading history...';
|
|
326
|
+
document.getElementById('detail-content').innerHTML = '<div class="loading">Loading...</div>';
|
|
327
|
+
loadDetail(target);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/* ==================================================================
|
|
331
|
+
Portfolio
|
|
332
|
+
================================================================== */
|
|
333
|
+
async function loadPortfolio() {
|
|
334
|
+
try {
|
|
335
|
+
const resp = await fetch('/api/targets');
|
|
336
|
+
if (!resp.ok) throw new Error('HTTP ' + resp.status);
|
|
337
|
+
portfolioData = await resp.json();
|
|
338
|
+
renderPortfolio();
|
|
339
|
+
} catch (err) {
|
|
340
|
+
document.getElementById('portfolio-content').innerHTML =
|
|
341
|
+
'<div class="error-msg">Failed to load portfolio: ' + escHtml(String(err)) + '</div>';
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function renderPortfolio() {
|
|
346
|
+
const container = document.getElementById('portfolio-content');
|
|
347
|
+
if (!portfolioData.length) {
|
|
348
|
+
container.innerHTML = '<div class="empty-state">No verification runs recorded yet.<br>Run <code>mcp-verify <target></code> to get started.</div>';
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const sorted = [...portfolioData].sort((a, b) => {
|
|
353
|
+
let av = a[sortKey];
|
|
354
|
+
let bv = b[sortKey];
|
|
355
|
+
if (typeof av === 'string') av = av.toLowerCase();
|
|
356
|
+
if (typeof bv === 'string') bv = bv.toLowerCase();
|
|
357
|
+
if (av < bv) return sortDir === 'asc' ? -1 : 1;
|
|
358
|
+
if (av > bv) return sortDir === 'asc' ? 1 : -1;
|
|
359
|
+
return 0;
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
const cols = [
|
|
363
|
+
{ key: 'target', label: 'Server URL' },
|
|
364
|
+
{ key: 'latestScore', label: 'Latest Score' },
|
|
365
|
+
{ key: 'findingsCount', label: 'Findings' },
|
|
366
|
+
{ key: 'trend', label: 'Trend' },
|
|
367
|
+
{ key: 'lastRun', label: 'Last Run' },
|
|
368
|
+
];
|
|
369
|
+
|
|
370
|
+
let html = '<div class="table-wrap"><table><thead><tr>';
|
|
371
|
+
for (const col of cols) {
|
|
372
|
+
let cls = '';
|
|
373
|
+
if (sortKey === col.key) cls = sortDir === 'asc' ? 'sort-asc' : 'sort-desc';
|
|
374
|
+
html += '<th class="' + cls + '" data-key="' + col.key + '">' + col.label + '</th>';
|
|
375
|
+
}
|
|
376
|
+
html += '</tr></thead><tbody>';
|
|
377
|
+
|
|
378
|
+
for (const row of sorted) {
|
|
379
|
+
const scoreCls = row.latestScore >= 80 ? 'score-green' : row.latestScore >= 60 ? 'score-yellow' : 'score-red';
|
|
380
|
+
const trendCls = row.trend === 'up' ? 'trend-up' : row.trend === 'down' ? 'trend-down' : 'trend-stable';
|
|
381
|
+
const trendSym = row.trend === 'up' ? '\u2191' : row.trend === 'down' ? '\u2193' : '\u2014';
|
|
382
|
+
const dateStr = row.lastRun ? new Date(row.lastRun).toLocaleString() : 'N/A';
|
|
383
|
+
|
|
384
|
+
html += '<tr>';
|
|
385
|
+
html += '<td><span class="server-link" data-target="' + escAttr(row.target) + '">' + escHtml(row.target) + '</span></td>';
|
|
386
|
+
html += '<td class="' + scoreCls + '">' + row.latestScore + '</td>';
|
|
387
|
+
html += '<td>' + row.findingsCount + '</td>';
|
|
388
|
+
html += '<td class="' + trendCls + '">' + trendSym + '</td>';
|
|
389
|
+
html += '<td>' + escHtml(dateStr) + '</td>';
|
|
390
|
+
html += '</tr>';
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
html += '</tbody></table></div>';
|
|
394
|
+
container.innerHTML = html;
|
|
395
|
+
|
|
396
|
+
// Column sort handlers
|
|
397
|
+
container.querySelectorAll('th[data-key]').forEach(function(th) {
|
|
398
|
+
th.addEventListener('click', function() {
|
|
399
|
+
const key = this.getAttribute('data-key');
|
|
400
|
+
if (sortKey === key) {
|
|
401
|
+
sortDir = sortDir === 'asc' ? 'desc' : 'asc';
|
|
402
|
+
} else {
|
|
403
|
+
sortKey = key;
|
|
404
|
+
sortDir = key === 'lastRun' ? 'desc' : (key === 'latestScore' ? 'desc' : 'asc');
|
|
405
|
+
}
|
|
406
|
+
renderPortfolio();
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
// Row click \u2192 detail
|
|
411
|
+
container.querySelectorAll('.server-link').forEach(function(el) {
|
|
412
|
+
el.addEventListener('click', function() {
|
|
413
|
+
showDetail(this.getAttribute('data-target'));
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/* ==================================================================
|
|
419
|
+
Detail
|
|
420
|
+
================================================================== */
|
|
421
|
+
async function loadDetail(target) {
|
|
422
|
+
try {
|
|
423
|
+
const resp = await fetch('/api/history/' + encodeURIComponent(target));
|
|
424
|
+
if (!resp.ok) throw new Error('HTTP ' + resp.status);
|
|
425
|
+
const history = await resp.json();
|
|
426
|
+
renderDetail(target, history);
|
|
427
|
+
} catch (err) {
|
|
428
|
+
document.getElementById('detail-content').innerHTML =
|
|
429
|
+
'<div class="error-msg">Failed to load history: ' + escHtml(String(err)) + '</div>';
|
|
430
|
+
document.getElementById('detail-subtitle').textContent = '';
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function renderDetail(target, history) {
|
|
435
|
+
if (!history.length) {
|
|
436
|
+
document.getElementById('detail-subtitle').textContent = 'No runs recorded.';
|
|
437
|
+
document.getElementById('detail-content').innerHTML = '<div class="empty-state">No history available for this target.</div>';
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const latest = history[history.length - 1];
|
|
442
|
+
document.getElementById('detail-subtitle').textContent =
|
|
443
|
+
history.length + ' run' + (history.length !== 1 ? 's' : '') +
|
|
444
|
+
' \u2022 Latest: ' + new Date(latest.timestamp).toLocaleString();
|
|
445
|
+
|
|
446
|
+
// Collect all category names
|
|
447
|
+
const catSet = new Set();
|
|
448
|
+
for (const r of history) {
|
|
449
|
+
for (const k of Object.keys(r.breakdown || {})) catSet.add(k);
|
|
450
|
+
}
|
|
451
|
+
const categories = Array.from(catSet);
|
|
452
|
+
|
|
453
|
+
// Default active: all
|
|
454
|
+
if (activeCategories.size === 0) {
|
|
455
|
+
for (const c of categories) activeCategories.add(c);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
let html = '';
|
|
459
|
+
|
|
460
|
+
// -- Score over time chart --
|
|
461
|
+
html += '<div class="chart-section">';
|
|
462
|
+
html += '<h3>Conformance Score Over Time</h3>';
|
|
463
|
+
html += '<div class="chart-container">';
|
|
464
|
+
|
|
465
|
+
if (categories.length > 0) {
|
|
466
|
+
html += '<div class="category-toggles" id="cat-toggles">';
|
|
467
|
+
for (const cat of categories) {
|
|
468
|
+
const isActive = activeCategories.has(cat);
|
|
469
|
+
html += '<button class="cat-toggle ' + (isActive ? 'active' : '') + '" data-cat="' + escAttr(cat) + '">' + escHtml(cat) + '</button>';
|
|
470
|
+
}
|
|
471
|
+
html += '</div>';
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
html += buildScoreChart(history, categories);
|
|
475
|
+
html += '</div></div>';
|
|
476
|
+
|
|
477
|
+
// -- Security findings stacked bar chart --
|
|
478
|
+
html += '<div class="chart-section">';
|
|
479
|
+
html += '<h3>Security Findings by Severity</h3>';
|
|
480
|
+
html += '<div class="chart-container">';
|
|
481
|
+
html += buildFindingsChart(history);
|
|
482
|
+
html += '</div></div>';
|
|
483
|
+
|
|
484
|
+
document.getElementById('detail-content').innerHTML = html;
|
|
485
|
+
|
|
486
|
+
// Category toggle handlers
|
|
487
|
+
document.querySelectorAll('#cat-toggles .cat-toggle').forEach(function(btn) {
|
|
488
|
+
btn.addEventListener('click', function() {
|
|
489
|
+
const cat = this.getAttribute('data-cat');
|
|
490
|
+
if (activeCategories.has(cat)) {
|
|
491
|
+
activeCategories.delete(cat);
|
|
492
|
+
this.classList.remove('active');
|
|
493
|
+
} else {
|
|
494
|
+
activeCategories.add(cat);
|
|
495
|
+
this.classList.add('active');
|
|
496
|
+
}
|
|
497
|
+
// Re-render just the score chart SVG
|
|
498
|
+
const chartContainer = this.closest('.chart-container');
|
|
499
|
+
const oldSvg = chartContainer.querySelector('svg.chart');
|
|
500
|
+
const newSvg = svgElementFromString(buildScoreChart(history, categories));
|
|
501
|
+
if (oldSvg && newSvg) chartContainer.replaceChild(newSvg, oldSvg);
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/* ==================================================================
|
|
507
|
+
Score line chart (SVG)
|
|
508
|
+
================================================================== */
|
|
509
|
+
function buildScoreChart(history, categories) {
|
|
510
|
+
const W = 720, H = 220;
|
|
511
|
+
const PAD = { top: 16, right: 20, bottom: 40, left: 44 };
|
|
512
|
+
const innerW = W - PAD.left - PAD.right;
|
|
513
|
+
const innerH = H - PAD.top - PAD.bottom;
|
|
514
|
+
const n = history.length;
|
|
515
|
+
|
|
516
|
+
function xPos(i) { return n <= 1 ? PAD.left + innerW / 2 : PAD.left + (i / (n - 1)) * innerW; }
|
|
517
|
+
function yPos(v) { return PAD.top + innerH - (Math.max(0, Math.min(100, v)) / 100) * innerH; }
|
|
518
|
+
|
|
519
|
+
let svg = '<svg class="chart" width="' + W + '" height="' + H + '" viewBox="0 0 ' + W + ' ' + H + '" aria-label="Conformance score over time">';
|
|
520
|
+
|
|
521
|
+
// Grid lines at 0, 25, 50, 75, 100
|
|
522
|
+
for (const gv of [0, 25, 50, 75, 100]) {
|
|
523
|
+
const gy = yPos(gv);
|
|
524
|
+
svg += '<line x1="' + PAD.left + '" y1="' + gy + '" x2="' + (PAD.left + innerW) + '" y2="' + gy + '" stroke="#30363d" stroke-width="1" />';
|
|
525
|
+
svg += '<text x="' + (PAD.left - 6) + '" y="' + (gy + 4) + '" fill="#8b949e" font-size="11" text-anchor="end" font-family="monospace">' + gv + '</text>';
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// X-axis date labels (up to 6 labels)
|
|
529
|
+
const labelStep = Math.max(1, Math.floor(n / 6));
|
|
530
|
+
for (let i = 0; i < n; i += labelStep) {
|
|
531
|
+
const rec = history[i];
|
|
532
|
+
const lx = xPos(i);
|
|
533
|
+
const label = rec ? new Date(rec.timestamp).toLocaleDateString() : '';
|
|
534
|
+
svg += '<text x="' + lx + '" y="' + (H - 6) + '" fill="#8b949e" font-size="10" text-anchor="middle" font-family="monospace">' + escHtml(label) + '</text>';
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// Regression markers \u2014 red dots when score drops >5 from previous run
|
|
538
|
+
const regressionPoints = [];
|
|
539
|
+
for (let i = 1; i < n; i++) {
|
|
540
|
+
const prev = history[i - 1];
|
|
541
|
+
const curr = history[i];
|
|
542
|
+
if (prev && curr && (prev.conformanceScore - curr.conformanceScore) > 5) {
|
|
543
|
+
regressionPoints.push({ x: xPos(i), y: yPos(curr.conformanceScore), score: curr.conformanceScore });
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Category overlay lines
|
|
548
|
+
const catColors = ['#58a6ff', '#3fb950', '#d29922', '#e3935a', '#bc8cff', '#79c0ff', '#56d364'];
|
|
549
|
+
for (let ci = 0; ci < categories.length; ci++) {
|
|
550
|
+
const cat = categories[ci];
|
|
551
|
+
if (!activeCategories.has(cat)) continue;
|
|
552
|
+
const color = catColors[ci % catColors.length];
|
|
553
|
+
const points = history.map(function(r, i) {
|
|
554
|
+
const v = (r.breakdown && r.breakdown[cat] !== undefined) ? r.breakdown[cat] : null;
|
|
555
|
+
if (v === null) return null;
|
|
556
|
+
return xPos(i) + ',' + yPos(v);
|
|
557
|
+
}).filter(Boolean);
|
|
558
|
+
if (points.length >= 2) {
|
|
559
|
+
svg += '<polyline points="' + points.join(' ') + '" fill="none" stroke="' + color + '" stroke-width="1.5" stroke-dasharray="4,3" opacity="0.7" />';
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// Overall score line
|
|
564
|
+
const scorePoints = history.map(function(r, i) { return xPos(i) + ',' + yPos(r.conformanceScore); }).join(' ');
|
|
565
|
+
if (n >= 2) {
|
|
566
|
+
svg += '<polyline points="' + scorePoints + '" fill="none" stroke="#58a6ff" stroke-width="2.5" />';
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// Score dots
|
|
570
|
+
for (let i = 0; i < n; i++) {
|
|
571
|
+
const r = history[i];
|
|
572
|
+
const cx = xPos(i);
|
|
573
|
+
const cy = yPos(r.conformanceScore);
|
|
574
|
+
svg += '<circle cx="' + cx + '" cy="' + cy + '" r="4" fill="#58a6ff" />';
|
|
575
|
+
// Tooltip via title
|
|
576
|
+
svg += '<circle cx="' + cx + '" cy="' + cy + '" r="8" fill="transparent"><title>' + escHtml(new Date(r.timestamp).toLocaleString()) + ': ' + r.conformanceScore + '</title></circle>';
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// Regression markers (red dots, drawn on top)
|
|
580
|
+
for (const pt of regressionPoints) {
|
|
581
|
+
svg += '<circle cx="' + pt.x + '" cy="' + pt.y + '" r="6" fill="#f85149" stroke="#0d1117" stroke-width="1.5">';
|
|
582
|
+
svg += '<title>Regression: score ' + pt.score + '</title>';
|
|
583
|
+
svg += '</circle>';
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
svg += '</svg>';
|
|
587
|
+
|
|
588
|
+
// Legend
|
|
589
|
+
svg += '<div class="legend">';
|
|
590
|
+
svg += '<div class="legend-item"><div class="legend-swatch" style="background:#58a6ff"></div><span>Overall Score</span></div>';
|
|
591
|
+
for (let ci = 0; ci < categories.length; ci++) {
|
|
592
|
+
const cat = categories[ci];
|
|
593
|
+
const color = catColors[ci % catColors.length];
|
|
594
|
+
const hiddenCls = activeCategories.has(cat) ? '' : ' hidden';
|
|
595
|
+
svg += '<div class="legend-item' + hiddenCls + '"><div class="legend-swatch" style="background:' + color + ';opacity:0.7"></div><span>' + escHtml(cat) + '</span></div>';
|
|
596
|
+
}
|
|
597
|
+
if (regressionPoints.length > 0) {
|
|
598
|
+
svg += '<div class="legend-item"><div class="legend-swatch" style="background:#f85149;border-radius:50%"></div><span>Regression (>5pt drop)</span></div>';
|
|
599
|
+
}
|
|
600
|
+
svg += '</div>';
|
|
601
|
+
|
|
602
|
+
return svg;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/* ==================================================================
|
|
606
|
+
Findings stacked bar chart (SVG)
|
|
607
|
+
================================================================== */
|
|
608
|
+
function buildFindingsChart(history) {
|
|
609
|
+
const W = 720, H = 180;
|
|
610
|
+
const PAD = { top: 16, right: 120, bottom: 40, left: 44 };
|
|
611
|
+
const innerW = W - PAD.left - PAD.right;
|
|
612
|
+
const innerH = H - PAD.top - PAD.bottom;
|
|
613
|
+
const n = history.length;
|
|
614
|
+
|
|
615
|
+
const severities = [
|
|
616
|
+
{ key: 'critical', color: '#f85149', label: 'Critical' },
|
|
617
|
+
{ key: 'high', color: '#e3935a', label: 'High' },
|
|
618
|
+
{ key: 'medium', color: '#d29922', label: 'Medium' },
|
|
619
|
+
{ key: 'low', color: '#58a6ff', label: 'Low' },
|
|
620
|
+
];
|
|
621
|
+
|
|
622
|
+
// Get per-run severity counts from securityFindingsCount (total only available)
|
|
623
|
+
// We show securityFindingsCount as a single bar since severity breakdown isn't stored per-run
|
|
624
|
+
// Use available breakdown data: securityFindingsCount is the total
|
|
625
|
+
const maxFindings = Math.max(1, ...history.map(function(r) { return r.securityFindingsCount || 0; }));
|
|
626
|
+
|
|
627
|
+
const barW = Math.max(4, Math.min(40, (innerW / n) - 4));
|
|
628
|
+
|
|
629
|
+
let svg = '<svg class="chart" width="' + W + '" height="' + H + '" viewBox="0 0 ' + W + ' ' + H + '" aria-label="Security findings per run">';
|
|
630
|
+
|
|
631
|
+
// Grid lines
|
|
632
|
+
const maxGrid = Math.ceil(maxFindings / 5) * 5 || 5;
|
|
633
|
+
for (let gv = 0; gv <= maxGrid; gv += Math.ceil(maxGrid / 4)) {
|
|
634
|
+
const gy = PAD.top + innerH - (gv / maxGrid) * innerH;
|
|
635
|
+
svg += '<line x1="' + PAD.left + '" y1="' + gy + '" x2="' + (PAD.left + innerW) + '" y2="' + gy + '" stroke="#30363d" stroke-width="1" />';
|
|
636
|
+
svg += '<text x="' + (PAD.left - 6) + '" y="' + (gy + 4) + '" fill="#8b949e" font-size="11" text-anchor="end" font-family="monospace">' + gv + '</text>';
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Bars
|
|
640
|
+
for (let i = 0; i < n; i++) {
|
|
641
|
+
const r = history[i];
|
|
642
|
+
const total = r.securityFindingsCount || 0;
|
|
643
|
+
const bx = n <= 1
|
|
644
|
+
? PAD.left + innerW / 2 - barW / 2
|
|
645
|
+
: PAD.left + (i / (n - 1)) * innerW - barW / 2;
|
|
646
|
+
|
|
647
|
+
if (total === 0) {
|
|
648
|
+
// Empty bar placeholder
|
|
649
|
+
const barH = 2;
|
|
650
|
+
svg += '<rect x="' + bx + '" y="' + (PAD.top + innerH - barH) + '" width="' + barW + '" height="' + barH + '" fill="#30363d" />';
|
|
651
|
+
} else {
|
|
652
|
+
const barH = (total / maxGrid) * innerH;
|
|
653
|
+
const by = PAD.top + innerH - barH;
|
|
654
|
+
// Single-color bar (total findings, no severity breakdown stored per-run)
|
|
655
|
+
svg += '<rect x="' + bx + '" y="' + by + '" width="' + barW + '" height="' + barH + '" fill="#e3935a">';
|
|
656
|
+
svg += '<title>' + escHtml(new Date(r.timestamp).toLocaleDateString()) + ': ' + total + ' finding' + (total !== 1 ? 's' : '') + '</title>';
|
|
657
|
+
svg += '</rect>';
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// X label
|
|
661
|
+
if (n <= 12 || i % Math.max(1, Math.floor(n / 6)) === 0) {
|
|
662
|
+
const lx = bx + barW / 2;
|
|
663
|
+
svg += '<text x="' + lx + '" y="' + (H - 6) + '" fill="#8b949e" font-size="10" text-anchor="middle" font-family="monospace">' + escHtml(new Date(r.timestamp).toLocaleDateString()) + '</text>';
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
svg += '</svg>';
|
|
668
|
+
|
|
669
|
+
// Legend
|
|
670
|
+
svg += '<div class="legend">';
|
|
671
|
+
svg += '<div class="legend-item"><div class="legend-swatch" style="background:#e3935a"></div><span>Security Findings (total)</span></div>';
|
|
672
|
+
svg += '</div>';
|
|
673
|
+
|
|
674
|
+
return svg;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/* ==================================================================
|
|
678
|
+
Utilities
|
|
679
|
+
================================================================== */
|
|
680
|
+
function escHtml(str) {
|
|
681
|
+
return String(str)
|
|
682
|
+
.replace(/&/g, '&')
|
|
683
|
+
.replace(/</g, '<')
|
|
684
|
+
.replace(/>/g, '>')
|
|
685
|
+
.replace(/"/g, '"')
|
|
686
|
+
.replace(/'/g, ''');
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
function escAttr(str) {
|
|
690
|
+
return String(str).replace(/"/g, '"').replace(/'/g, ''');
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
function svgElementFromString(htmlStr) {
|
|
694
|
+
const div = document.createElement('div');
|
|
695
|
+
div.innerHTML = htmlStr;
|
|
696
|
+
return div.querySelector('svg.chart');
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/* ==================================================================
|
|
700
|
+
Bootstrap
|
|
701
|
+
================================================================== */
|
|
702
|
+
loadPortfolio();
|
|
703
|
+
</script>
|
|
704
|
+
</body>
|
|
705
|
+
</html>`;var Mr="default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'";function Ao(n){if(n.length<2)return"stable";let e=n.slice(-3),t=e[0]??0,o=(e[e.length-1]??0)-t;return o>2?"up":o<-2?"down":"stable"}function M(n,e,t){let r=JSON.stringify(t);n.writeHead(e,{"Content-Type":"application/json","Content-Security-Policy":Mr,"Cache-Control":"no-store"}),n.end(r)}function Io(n,e,t){n.writeHead(e,{"Content-Type":"text/html; charset=utf-8","Content-Security-Policy":Mr,"Cache-Control":"no-store"}),n.end(t)}function No(n){let e=n.url??"/",t=e.indexOf("?");return t===-1?e:e.slice(0,t)}function Vo(n){return function(t,r){let o=No(t);if(o==="/api/targets"){if(t.method!=="GET"){M(r,405,{error:"Method Not Allowed"});return}let a=n.getAllTargets().map(l=>{let p=n.getHistory(l),u=p[p.length-1],d=p.map(m=>m.conformanceScore);return{target:l,latestScore:u?.conformanceScore??0,findingsCount:u?.securityFindingsCount??0,trend:Ao(d),lastRun:u?.timestamp??null}});M(r,200,a);return}let s=/^\/api\/history\/(.+)$/.exec(o);if(s){if(t.method!=="GET"){M(r,405,{error:"Method Not Allowed"});return}let c=s[1]??"",a;try{a=decodeURIComponent(c)}catch{M(r,400,{error:"Invalid target encoding"});return}let l=n.getHistory(a);M(r,200,l);return}let i=/^\/api\/baselines\/(.+)$/.exec(o);if(i){if(t.method!=="GET"){M(r,405,{error:"Method Not Allowed"});return}let c=i[1]??"",a;try{a=decodeURIComponent(c)}catch{M(r,400,{error:"Invalid target encoding"});return}let l=n.getLatestRun(a);if(l===null){M(r,404,{error:"No baseline found for target"});return}M(r,200,{target:a,baseline:l});return}if(o==="/"||o==="/index.html"){if(t.method!=="GET"){M(r,405,{error:"Method Not Allowed"});return}Io(r,200,Lt);return}M(r,404,{error:"Not Found"})}}var Ee=class{server;storage;port;constructor(e){this.port=e.port,this.storage=e.storage??new N,this.server=(0,jr.createServer)(Vo(this.storage))}start(){return new Promise((e,t)=>{this.server.once("error",r=>{r.code==="EADDRINUSE"?t(new Error(`Port ${this.port} is already in use. Try a different port with --port <number>.`)):t(r)}),this.server.listen(this.port,"127.0.0.1",()=>{let r=this.server.address(),o=r!==null&&typeof r=="object"?r.port:this.port;e(o)})})}stop(){return new Promise((e,t)=>{this.server.close(r=>{r?t(r):e()})})}};async function Dt(n){let e=new Ee({port:n}),t=await e.start();return process.stdout.write(`Dashboard available at http://localhost:${t}
|
|
706
|
+
`),process.on("SIGINT",()=>{e.stop().finally(()=>{process.exit(0)})}),e}var Lr=(r=>(r[r.PASS=0]="PASS",r[r.FAIL=1]="FAIL",r[r.ERROR=2]="ERROR",r))(Lr||{});function Y(n,e=!1,t){process.stderr.write(`Error: ${n}
|
|
707
|
+
`),e&&t instanceof Error&&t.stack&&process.stderr.write(`${t.stack}
|
|
708
|
+
`),process.exit(2)}function jo(n){let e={critical:0,high:0,medium:0,low:0};for(let t of n)if(!t.suppressed){let r=e[t.severity];r!==void 0&&(e[t.severity]=r+1)}return e}function Mo(n){let e=[];e.push(""),e.push("=== Comparison with Previous Run ==="),e.push("");let t=n.scoreDelta>0?"+":"";if(e.push(` Score: ${n.previousScore} -> ${n.currentScore} (${t}${n.scoreDelta})`),e.push(` Findings: ${n.previousFindingsCount} -> ${n.currentFindingsCount}`),n.isRegression?e.push(" Status: REGRESSION"):n.scoreDelta>0?e.push(" Status: IMPROVEMENT"):e.push(" Status: NO CHANGE"),n.newFindings.length>0){e.push(""),e.push(` New findings (${n.newFindings.length}):`);for(let r of n.newFindings)e.push(` + ${r}`)}if(n.resolvedFindings.length>0){e.push(""),e.push(` Resolved findings (${n.resolvedFindings.length}):`);for(let r of n.resolvedFindings)e.push(` - ${r}`)}return e.push(""),e.join(`
|
|
709
|
+
`)}async function Hr(n,e={}){let t=Date.now(),r;try{r=Ge(n.target,n)}catch(o){Y(o instanceof Error?o.message:String(o),n.verbose,o)}try{let o=await ot(r,n),s=vt(o,n),i=_t(o,n),c=St(s,i,n),a=wt(c,i,n),l={meta:{toolVersion:"1.1.0",specVersion:"2024-11-05",timestamp:new Date().toISOString(),target:n.target,transport:o.transportMetadata.type,durationMs:Date.now()-t,checkMode:n.checkMode},conformance:{score:c.overallScore,breakdown:Object.fromEntries(c.categoryScores.map(f=>[f.category,f.score])),violations:s.filter(f=>f.level!=="pass")},security:{findings:i.filter(f=>!f.suppressed),suppressed:i.filter(f=>f.suppressed)},summary:{pass:a===0,exitCode:a,blockerCount:jo(i)}},p={timestamp:l.meta.timestamp,target:n.target,conformanceScore:l.conformance.score,securityFindingsCount:l.security.findings.length,breakdown:l.conformance.breakdown,toolVersion:l.meta.toolVersion,specVersion:l.meta.specVersion},u=null,d=e.compareLast===!0||e.comparePrevious===!0;if(d){let f=new N,h=null;e.comparePrevious===!0?h=f.getLatestRun(n.target):h=Ht(n.target)??f.getLatestRun(n.target),h!==null&&(u=jt(h,p,[],l.security.findings))}let m=It(n);if(n.output!==null){let f;if(n.format==="json"&&u!==null&&e.compareLast===!0){let h=JSON.parse(m.format(l));h.comparison=u,f=JSON.stringify(h,null,2)}else f=m.format(l);try{(0,Ut.writeFileSync)(n.output,f,"utf-8")}catch(h){Y(`Failed to write output file "${n.output}": ${h instanceof Error?h.message:String(h)}`,n.verbose,h)}if(n.format!=="terminal"){let{TerminalReporter:h}=await Promise.resolve().then(()=>(Se(),Or)),y=new h(n.noColor);process.stdout.write(y.format(l)+`
|
|
710
|
+
`)}}else{let f=m.format(l);process.stdout.write(f+`
|
|
711
|
+
`)}d&&(u!==null?process.stdout.write(Mo(u)):process.stdout.write(`
|
|
712
|
+
No previous run found for ${n.target}
|
|
713
|
+
`)),n.noHistory||new N().appendRun(n.target,p),e.saveAsBaseline===!0&&Oe(n.target,p),process.exit(a)}finally{await r.close()}}function Ft(n){let e=Number(n);if(!Number.isInteger(e)||e<=0)throw new W(`--timeout must be a positive integer (got: ${n})`);return e}function Jt(n){let e=["terminal","json","markdown","sarif"];if(!e.includes(n))throw new W(`--format must be one of: ${e.join(", ")} (got: ${n})`);return n}function qt(n){let e=["http","stdio"];if(!e.includes(n))throw new W(`--transport must be one of: ${e.join(", ")} (got: ${n})`);return n}function zt(n){let e=["critical","high","medium","low","none"];if(!e.includes(n))throw new W(`--fail-on-severity must be one of: ${e.join(", ")} (got: ${n})`);return n}function Wt(n){let e=Number(n);if(!Number.isInteger(e)||e<0||e>100)throw new W(`--conformance-threshold must be an integer between 0 and 100 (got: ${n})`);return e}function Dr(n){let e=Number(n);if(!Number.isInteger(e)||e<1||e>65535)throw new W(`--port must be an integer between 1 and 65535 (got: ${n})`);return e}function oe(n){n.configureOutput({writeErr:()=>{}}),n.exitOverride(e=>{(e.code==="commander.helpDisplayed"||e.code==="commander.version")&&process.exit(0);let t=e.message.replace(/^error:\s*/i,"");process.stderr.write(`Error: ${t}
|
|
714
|
+
`),process.exit(2)})}function Fr(){let n=new cr;n.name("mcp-verify").description("Verify MCP servers for spec conformance, security vulnerabilities, and health metrics").version("mcp-verify 1.1.0 (validates MCP spec 2024-11-05)","-V, --version","Output the version number").addHelpText("after",`
|
|
715
|
+
Examples:
|
|
716
|
+
mcp-verify https://example.com/mcp
|
|
717
|
+
mcp-verify verify https://example.com/mcp --format json
|
|
718
|
+
mcp-verify verify ./my-server --timeout 30000
|
|
719
|
+
`),oe(n);let e=n.command("verify <target>",{isDefault:!0}).description("Verify an MCP server at <target> (URL or stdio command)").option("--timeout <ms>","Connection and response timeout in milliseconds",Ft,k.timeout).option("--no-color","Disable colored output").option("--format <type>","Output format: terminal | json | markdown | sarif",Jt,k.format).option("--config <path>","Path to config file (default: auto-discover mcp-verify.json or .mcp-verify.json)").option("--strict","Set check mode to strict").option("--lenient","Set check mode to lenient").option("--verbose","Enable verbose output").option("--output <path>","Write formatted report to file instead of stdout").option("--transport <type>","Force transport type: http | stdio",qt).option("--fail-on-severity <level>","Minimum severity level to fail on: critical | high | medium | low | none",zt,k.failOnSeverity).option("--conformance-threshold <score>","Minimum conformance score (0\u2013100)",Wt,k.conformanceThreshold).option("--no-history","Skip saving this run to history storage").option("--compare-last","After verification, compare with baseline (if set) or the previous run").option("--compare-previous","After verification, compare with immediately previous run (bypasses baseline)").addHelpText("after",`
|
|
720
|
+
Examples:
|
|
721
|
+
mcp-verify https://example.com/mcp
|
|
722
|
+
mcp-verify verify https://example.com/mcp --format json
|
|
723
|
+
mcp-verify verify ./my-server --timeout 30000
|
|
724
|
+
mcp-verify verify https://example.com/mcp --no-color --format sarif
|
|
725
|
+
mcp-verify verify https://example.com/mcp --compare-last
|
|
726
|
+
mcp-verify verify https://example.com/mcp --compare-previous
|
|
727
|
+
`);oe(e),e.action(async(i,c)=>{c.strict&&c.lenient&&(process.stderr.write(`Error: --strict and --lenient are mutually exclusive
|
|
728
|
+
`),process.exit(2));let a;c.strict?a="strict":c.lenient&&(a="lenient");let l=xe(c.config),p={timeout:c.timeout,noColor:!c.color,format:c.format,failOnSeverity:c.failOnSeverity,conformanceThreshold:c.conformanceThreshold,noHistory:!c.history};a!==void 0&&(p.checkMode=a),c.verbose===!0&&(p.verbose=!0),c.output!==void 0&&(p.output=c.output),c.transport!==void 0&&(p.transport=c.transport);let u=Pe(p,l,i);try{await Hr(u,{compareLast:c.compareLast===!0,comparePrevious:c.comparePrevious===!0})}catch(d){Y(d instanceof Error?d.message:String(d),u.verbose,d)}});let t=n.command("baseline <target>").description("Run verification and store the result as a baseline for <target>").option("--existing","Promote the most recent history entry as baseline without running verification").option("--timeout <ms>","Connection and response timeout in milliseconds",Ft,k.timeout).option("--no-color","Disable colored output").option("--format <type>","Output format: terminal | json | markdown | sarif",Jt,k.format).option("--config <path>","Path to config file (default: auto-discover mcp-verify.json or .mcp-verify.json)").option("--strict","Set check mode to strict").option("--lenient","Set check mode to lenient").option("--verbose","Enable verbose output").option("--output <path>","Write formatted report to file instead of stdout").option("--transport <type>","Force transport type: http | stdio",qt).option("--fail-on-severity <level>","Minimum severity level to fail on: critical | high | medium | low | none",zt,k.failOnSeverity).option("--conformance-threshold <score>","Minimum conformance score (0\u2013100)",Wt,k.conformanceThreshold).addHelpText("after",`
|
|
729
|
+
Examples:
|
|
730
|
+
mcp-verify baseline https://example.com/mcp
|
|
731
|
+
mcp-verify baseline --existing https://example.com/mcp
|
|
732
|
+
`);oe(t),t.action(async(i,c)=>{if(c.existing===!0){let m=new N().getLatestRun(i);m===null&&(process.stderr.write(`Error: No history found for "${i}". Run a verification first.
|
|
733
|
+
`),process.exit(2));try{Oe(i,m)}catch(f){Y(f instanceof Error?f.message:String(f),c.verbose===!0,f)}process.stdout.write(`Baseline saved for "${i}" (score: ${m.conformanceScore}, timestamp: ${m.timestamp})
|
|
734
|
+
`),process.exit(0)}c.strict&&c.lenient&&(process.stderr.write(`Error: --strict and --lenient are mutually exclusive
|
|
735
|
+
`),process.exit(2));let a;c.strict?a="strict":c.lenient&&(a="lenient");let l=xe(c.config),p={timeout:c.timeout,noColor:!c.color,format:c.format,failOnSeverity:c.failOnSeverity,conformanceThreshold:c.conformanceThreshold};a!==void 0&&(p.checkMode=a),c.verbose===!0&&(p.verbose=!0),c.output!==void 0&&(p.output=c.output),c.transport!==void 0&&(p.transport=c.transport);let u=Pe(p,l,i);try{await Hr(u,{saveAsBaseline:!0})}catch(d){Y(d instanceof Error?d.message:String(d),u.verbose,d)}});let r=n.command("history").description("Manage run history");oe(r);let o=r.command("export [target]").description("Export run history as JSON").option("--all","Export history for all tracked targets").option("--output <path>","Write exported history to a file instead of stdout").addHelpText("after",`
|
|
736
|
+
Examples:
|
|
737
|
+
mcp-verify history export https://example.com/mcp --output history.json
|
|
738
|
+
mcp-verify history export --all --output all-history.json
|
|
739
|
+
`);oe(o),o.action((i,c)=>{let a=new N;c.all!==!0&&(i===void 0||i.trim()==="")&&(process.stderr.write(`Error: Provide a <target> argument or use --all to export all targets
|
|
740
|
+
`),process.exit(2));let l,p;if(c.all===!0)p=a.getAllTargets(),l=p.flatMap(m=>a.getHistory(m));else{let m=i;p=[m],l=a.getHistory(m)}let u={exportedAt:new Date().toISOString(),toolVersion:"1.1.0",targets:p,runs:l},d=JSON.stringify(u,null,2)+`
|
|
741
|
+
`;if(c.output!==void 0){try{(0,Ut.writeFileSync)(c.output,d,"utf-8")}catch(m){Y(`Failed to write output file "${c.output}": ${m instanceof Error?m.message:String(m)}`)}process.stdout.write(`History exported to "${c.output}"
|
|
742
|
+
`)}else process.stdout.write(d);process.exit(0)});let s=n.command("serve").description("Start the local web dashboard").option("--port <number>","Port to listen on (default: 4000)",Dr,4e3).addHelpText("after",`
|
|
743
|
+
Examples:
|
|
744
|
+
mcp-verify serve
|
|
745
|
+
mcp-verify serve --port 8080
|
|
746
|
+
`);return oe(s),s.action(async i=>{try{await Dt(i.port),await new Promise(()=>{})}catch(c){let a=c instanceof Error?c.message:String(c);process.stderr.write(`Error: ${a}
|
|
747
|
+
`),process.exit(2)}}),n}async function Jr(n){let e=Fr();n.slice(2).length===0&&(e.outputHelp(),process.exit(2)),await e.parseAsync(n)}var Ho=process.argv[1]!==void 0&&(process.argv[1].endsWith("cli.js")||process.argv[1].endsWith("cli.cjs"));Ho&&Jr(process.argv).catch(n=>{let e=n instanceof Error?n.message:String(n);process.stderr.write(`Error: ${e}
|
|
748
|
+
`),process.exit(2)});0&&(module.exports={ExitCode,buildProgram,exitWithError,main,parseConformanceThreshold,parseFailOnSeverity,parseFormat,parsePort,parseTimeout,parseTransport});
|