@shiplightai/mcp 0.1.68 → 0.1.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +4 -4
  2. package/package.json +16 -16
package/dist/index.js CHANGED
@@ -6405,13 +6405,13 @@ ${i?`
6405
6405
  });
6406
6406
  </script>
6407
6407
  </body>
6408
- </html>`,le=mo.dirname(m);return await Cr.promises.mkdir(le,{recursive:!0}),await Cr.promises.writeFile(m,fe,"utf8"),JSON.stringify({success:!0,file_path:m})}static uploadReportTool={name:"upload_html_report",description:"Upload a generated HTML report to Shiplight cloud for sharing. Optionally includes video recording and Playwright trace. Returns a permanent shareable URL. Requires SHIPLIGHT_API_TOKEN. Call this after generate_html_report to get a link you can attach to PRs or share with the team. Note: the local report HTML file is modified in-place to replace local file paths with cloud URLs.",inputSchema:Ud(at.object({report_path:at.string().describe("Path to the HTML report file (returned by generate_html_report)"),local_video_path:at.string().optional().describe("Path to the .webm video recording (returned by close_session)"),local_trace_path:at.string().optional().describe("Path to the .zip trace file (returned by close_session)")}),{$refStrategy:"none"})};async uploadReport(t){let{report_path:r,local_video_path:n,local_trace_path:i}=at.object({report_path:at.string(),local_video_path:at.string().optional(),local_trace_path:at.string().optional()}).parse(t),s=this.requireApi("upload_html_report");if(!s.getReportUploadUrls)throw new Error("Report upload is not supported by this API client");if(!Cr.existsSync(r))throw new Error(`Report file not found: ${r}`);let o=n&&Cr.existsSync(n),a=i&&Cr.existsSync(i),l=await s.getReportUploadUrls({videoFilename:o?mo.basename(n):void 0,traceFilename:a?mo.basename(i):void 0,reportFilename:"report.html"}),u=300*1e3,d=[];o&&l.video&&d.push(Aw.put(l.video.uploadUrl,Cr.createReadStream(n),{headers:{"Content-Type":"video/webm","Content-Length":Cr.statSync(n).size},maxBodyLength:1/0,maxContentLength:1/0,timeout:u}).then(()=>{te.info("[upload_html_report] Video uploaded")}).catch(h=>{throw new Error(`Failed to upload video: ${h.message}`)})),a&&l.trace&&d.push(Aw.put(l.trace.uploadUrl,Cr.createReadStream(i),{headers:{"Content-Type":"application/zip","Content-Length":Cr.statSync(i).size},maxBodyLength:1/0,maxContentLength:1/0,timeout:u}).then(()=>{te.info("[upload_html_report] Trace uploaded")}).catch(h=>{throw new Error(`Failed to upload trace: ${h.message}`)})),await Promise.all(d);let p=await Cr.promises.readFile(r,"utf8");if(o&&l.video){let h=p.replace(/src="file:\/\/[^"]*\.webm"/g,`src="${l.video.url}"`);h===p&&te.warn("[upload_html_report] No file:// video src found in report HTML to patch"),p=h}if(a&&l.trace){let h=encodeURIComponent(l.trace.url),m='<p class="no-trace">Trace will be available after uploading.</p>';p.includes(m)||te.warn("[upload_html_report] No trace placeholder found in report HTML to patch"),p=p.replace(m,`<a class="trace-btn" href="https://trace.playwright.dev/?trace=${h}" target="_blank" rel="noopener noreferrer">Open Trace Viewer \u2192</a>`)}return await Cr.promises.writeFile(r,p,"utf8"),await Aw.put(l.report.uploadUrl,Buffer.from(p,"utf8"),{headers:{"Content-Type":"text/html"},maxBodyLength:1/0,maxContentLength:1/0,timeout:u}).catch(h=>{throw new Error(`Failed to upload report: ${h.message}`)}),te.info("[upload_html_report] Report uploaded"),JSON.stringify({success:!0,report_url:l.report.url,video_url:l.video?.url??null,trace_url:l.trace?.url??null})}static toolDefinitions=[Hd.scaffoldProjectTool,Hd.validateTestYamlTool,Hd.generateHtmlReportTool];static cloudToolDefinitions=[Hd.uploadReportTool]}});var nL={};Mi(nL,{ACT_SUPPORTED_ACTIONS:()=>nl,ActionEntitySchema:()=>Dd,BrowserTools:()=>JR,DataTools:()=>XR,DebugTools:()=>YR,ExtensionRelayServer:()=>fR,LocalTestTools:()=>tL,PROMPTS:()=>pm,RESOURCES:()=>dw,RelayElectionCoordinator:()=>mR,RelayTools:()=>KR,SessionManager:()=>hR,SessionTools:()=>zR,StatementSchema:()=>In,TestCaseTools:()=>qd,TestFlowSchema:()=>ea,TestResultTools:()=>QR,TokenApiClient:()=>um,ToolRegistry:()=>dm,WebAgent:()=>tl,actHandler:()=>Dw,actSchema:()=>Ow,clearExecutionHistoryHandler:()=>Fw,clearExecutionHistorySchema:()=>Nm,clearExecutionHistoryToolMeta:()=>Mw,getActSchema:()=>Gw,getActToolDefinition:()=>Ww,getActToolMeta:()=>Nw,getActionEntitySchemaResource:()=>fw,getLocatorsHandler:()=>qw,getLocatorsSchema:()=>Lm,getLocatorsToolMeta:()=>Hw,getPageInfoHandler:()=>$w,getPageInfoSchema:()=>Dm,getPageInfoToolMeta:()=>Bw,getPrompt:()=>hm,getResource:()=>ym,getTestFlowJsonSchemaResource:()=>pw,getTestFlowYamlSchemaResource:()=>hw,inspectPageHandler:()=>Uw,inspectPageSchema:()=>Rm,inspectPageToolMeta:()=>jw,listPrompts:()=>fm,listResources:()=>gm,missingApiTokenError:()=>jc,navigateHandler:()=>Pw,navigateSchema:()=>Pm,navigateToolMeta:()=>Iw,scaffoldProject:()=>bm,updateVariablesHandler:()=>Lw,updateVariablesSchema:()=>Om,updateVariablesToolMeta:()=>Rw});var Vw=mt(()=>{"use strict";gR();tm();yR();bR();_R();rL();mw();rm();mm()});var zw,jne,go,Kw=mt(()=>{"use strict";zw=class e{static _instance;_logLevel;constructor(){switch(process.env.LOG_LEVEL?.toUpperCase()){case"ERROR":this._logLevel=1;break;case"WARN":this._logLevel=2;break;case"INFO":this._logLevel=3;break;case"DEBUG":this._logLevel=4;break;default:this._logLevel=3}}static getInstance(){return e._instance||(e._instance=new e),e._instance}setLevel(t){this._logLevel=t}debug(...t){this._logLevel>=4&&console.error("[DEBUG]",...t)}info(...t){this._logLevel>=3&&console.error("[INFO]",...t)}warn(...t){this._logLevel>=2&&console.error("[WARN]",...t)}error(...t){this._logLevel>=1&&console.error("[ERROR]",...t)}log(...t){this.info(...t)}},jne=zw.getInstance(),go=jne});import{createHash as Une}from"node:crypto";import{hostname as Hne,userInfo as qne,platform as sL,arch as Gne}from"node:os";import{PostHog as Wne}from"posthog-node";function Jne(){return Kne?null:(Jw||(Jw=new Wne(Vne,{host:zne,flushAt:1,flushInterval:3e4})),Jw)}function Yne(){let e=`${Hne()}:${qne().username}:${sL()}:${Gne()}`;return Une("sha256").update(e).digest("hex")}function oL(e,t){let r=Jne();if(r){iL||(go.info("Anonymous usage telemetry enabled. Set SHIPLIGHT_TELEMETRY=0 to disable."),iL=!0);try{r.capture({distinctId:Yne(),event:"mcp_new_session",properties:{product:"mcp-server",version:e,platform:sL(),nodeVersion:process.version,cloudMode:t,$geoip_disable:!0,$ip:null}}),r.flush().catch(()=>{})}catch{}}}var Vne,zne,Kne,Jw,iL,aL=mt(()=>{"use strict";Kw();Vne="phc_5Va2dHamGwJWX9qZqyRka5Lann5ATsg3LL4uyU63qin",zne="https://us.i.posthog.com",Kne=process.env.SHIPLIGHT_TELEMETRY==="0"||process.env.DO_NOT_TRACK==="1",Jw=null,iL=!1});var dL={};Mi(dL,{startServer:()=>aie});import{Server as Xne}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Zne}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as Qne,ListToolsRequestSchema as eie,ListResourcesRequestSchema as tie,ReadResourceRequestSchema as rie,ListPromptsRequestSchema as nie,GetPromptRequestSchema as iie,ErrorCode as Yw,McpError as Xw}from"@modelcontextprotocol/sdk/types.js";import cL from"axios";import sie from"dotenv";function Uc(e){return typeof e=="object"&&e!==null&&"code"in e&&e.code==="EPIPE"}function Hc(){lL||(lL=!0,process.exit(0))}function Fm(e){if(!process.stderr.destroyed){if(process.stderr.errored){Uc(process.stderr.errored)&&Hc();return}try{process.stderr.write(e)}catch(t){Uc(t)&&Hc()}}}function Bm(e){return e instanceof Error?e.stack||`${e.name}: ${e.message}`:String(e)}async function Zw(){let{SessionTools:e,RelayTools:t,BrowserTools:r,DebugTools:n,LocalTestTools:i,SessionManager:s,ExtensionRelayServer:o,RelayElectionCoordinator:a}=await Promise.resolve().then(()=>(Vw(),nL));return{SessionTools:e,RelayTools:t,BrowserTools:r,DebugTools:n,LocalTestTools:i,SessionManager:s,ExtensionRelayServer:o,RelayElectionCoordinator:a}}function uL(){return process.env[oie]||null}async function aie(){let e=process.argv.includes("--debug"),t=process.env.SHIPLIGHT_RELAY_PORT&&parseInt(process.env.SHIPLIGHT_RELAY_PORT,10)||null;await new Qw(e,t).run()}var lL,ev,oie,Qw,pL=mt(()=>{"use strict";ED();Vw();Yn();Kw();aL();process.env.PWDEBUG="console";lL=!1;process.stdout.on("error",e=>{if(Uc(e)){Hc();return}Fm(`[MCP] stdout error: ${Bm(e)}
6408
+ </html>`,le=mo.dirname(m);return await Cr.promises.mkdir(le,{recursive:!0}),await Cr.promises.writeFile(m,fe,"utf8"),JSON.stringify({success:!0,file_path:m})}static uploadReportTool={name:"upload_html_report",description:"Upload a generated HTML report to Shiplight cloud for sharing. Optionally includes video recording and Playwright trace. Returns a permanent shareable URL. Requires SHIPLIGHT_API_TOKEN. Call this after generate_html_report to get a link you can attach to PRs or share with the team. Note: the local report HTML file is modified in-place to replace local file paths with cloud URLs.",inputSchema:Ud(at.object({report_path:at.string().describe("Path to the HTML report file (returned by generate_html_report)"),local_video_path:at.string().optional().describe("Path to the .webm video recording (returned by close_session)"),local_trace_path:at.string().optional().describe("Path to the .zip trace file (returned by close_session)")}),{$refStrategy:"none"})};async uploadReport(t){let{report_path:r,local_video_path:n,local_trace_path:i}=at.object({report_path:at.string(),local_video_path:at.string().optional(),local_trace_path:at.string().optional()}).parse(t),s=this.requireApi("upload_html_report");if(!s.getReportUploadUrls)throw new Error("Report upload is not supported by this API client");if(!Cr.existsSync(r))throw new Error(`Report file not found: ${r}`);let o=n&&Cr.existsSync(n),a=i&&Cr.existsSync(i),l=await s.getReportUploadUrls({videoFilename:o?mo.basename(n):void 0,traceFilename:a?mo.basename(i):void 0,reportFilename:"report.html"}),u=300*1e3,d=[];o&&l.video&&d.push(Aw.put(l.video.uploadUrl,Cr.createReadStream(n),{headers:{"Content-Type":"video/webm","Content-Length":Cr.statSync(n).size},maxBodyLength:1/0,maxContentLength:1/0,timeout:u}).then(()=>{te.info("[upload_html_report] Video uploaded")}).catch(h=>{throw new Error(`Failed to upload video: ${h.message}`)})),a&&l.trace&&d.push(Aw.put(l.trace.uploadUrl,Cr.createReadStream(i),{headers:{"Content-Type":"application/zip","Content-Length":Cr.statSync(i).size},maxBodyLength:1/0,maxContentLength:1/0,timeout:u}).then(()=>{te.info("[upload_html_report] Trace uploaded")}).catch(h=>{throw new Error(`Failed to upload trace: ${h.message}`)})),await Promise.all(d);let p=await Cr.promises.readFile(r,"utf8");if(o&&l.video){let h=p.replace(/src="file:\/\/[^"]*\.webm"/g,`src="${l.video.url}"`);h===p&&te.warn("[upload_html_report] No file:// video src found in report HTML to patch"),p=h}if(a&&l.trace){let h=encodeURIComponent(l.trace.url),m='<p class="no-trace">Trace will be available after uploading.</p>';p.includes(m)||te.warn("[upload_html_report] No trace placeholder found in report HTML to patch"),p=p.replace(m,`<a class="trace-btn" href="https://trace.playwright.dev/?trace=${h}" target="_blank" rel="noopener noreferrer">Open Trace Viewer \u2192</a>`)}return await Cr.promises.writeFile(r,p,"utf8"),await Aw.put(l.report.uploadUrl,Buffer.from(p,"utf8"),{headers:{"Content-Type":"text/html"},maxBodyLength:1/0,maxContentLength:1/0,timeout:u}).catch(h=>{throw new Error(`Failed to upload report: ${h.message}`)}),te.info("[upload_html_report] Report uploaded"),JSON.stringify({success:!0,report_url:l.report.url,video_url:l.video?.url??null,trace_url:l.trace?.url??null})}static toolDefinitions=[Hd.scaffoldProjectTool,Hd.validateTestYamlTool,Hd.generateHtmlReportTool];static cloudToolDefinitions=[Hd.uploadReportTool]}});var nL={};Mi(nL,{ACT_SUPPORTED_ACTIONS:()=>nl,ActionEntitySchema:()=>Dd,BrowserTools:()=>JR,DataTools:()=>XR,DebugTools:()=>YR,ExtensionRelayServer:()=>fR,LocalTestTools:()=>tL,PROMPTS:()=>pm,RESOURCES:()=>dw,RelayElectionCoordinator:()=>mR,RelayTools:()=>KR,SessionManager:()=>hR,SessionTools:()=>zR,StatementSchema:()=>In,TestCaseTools:()=>qd,TestFlowSchema:()=>ea,TestResultTools:()=>QR,TokenApiClient:()=>um,ToolRegistry:()=>dm,WebAgent:()=>tl,actHandler:()=>Dw,actSchema:()=>Ow,clearExecutionHistoryHandler:()=>Fw,clearExecutionHistorySchema:()=>Nm,clearExecutionHistoryToolMeta:()=>Mw,getActSchema:()=>Gw,getActToolDefinition:()=>Ww,getActToolMeta:()=>Nw,getActionEntitySchemaResource:()=>fw,getLocatorsHandler:()=>qw,getLocatorsSchema:()=>Lm,getLocatorsToolMeta:()=>Hw,getPageInfoHandler:()=>$w,getPageInfoSchema:()=>Dm,getPageInfoToolMeta:()=>Bw,getPrompt:()=>hm,getResource:()=>ym,getTestFlowJsonSchemaResource:()=>pw,getTestFlowYamlSchemaResource:()=>hw,inspectPageHandler:()=>Uw,inspectPageSchema:()=>Rm,inspectPageToolMeta:()=>jw,listPrompts:()=>fm,listResources:()=>gm,missingApiTokenError:()=>jc,navigateHandler:()=>Pw,navigateSchema:()=>Pm,navigateToolMeta:()=>Iw,scaffoldProject:()=>bm,updateVariablesHandler:()=>Lw,updateVariablesSchema:()=>Om,updateVariablesToolMeta:()=>Rw});var Vw=mt(()=>{"use strict";gR();tm();yR();bR();_R();rL();mw();rm();mm()});var zw,jne,go,Kw=mt(()=>{"use strict";zw=class e{static _instance;_logLevel;constructor(){switch(process.env.LOG_LEVEL?.toUpperCase()){case"ERROR":this._logLevel=1;break;case"WARN":this._logLevel=2;break;case"INFO":this._logLevel=3;break;case"DEBUG":this._logLevel=4;break;default:this._logLevel=3}}static getInstance(){return e._instance||(e._instance=new e),e._instance}setLevel(t){this._logLevel=t}debug(...t){this._logLevel>=4&&console.error("[DEBUG]",...t)}info(...t){this._logLevel>=3&&console.error("[INFO]",...t)}warn(...t){this._logLevel>=2&&console.error("[WARN]",...t)}error(...t){this._logLevel>=1&&console.error("[ERROR]",...t)}log(...t){this.info(...t)}},jne=zw.getInstance(),go=jne});import{createHash as Une}from"node:crypto";import{hostname as Hne,userInfo as qne,platform as sL,arch as Gne}from"node:os";import{PostHog as Wne}from"posthog-node";function Jne(){return Kne?null:(Jw||(Jw=new Wne(Vne,{host:zne,flushAt:1,flushInterval:3e4})),Jw)}function Yne(){let e=`${Hne()}:${qne().username}:${sL()}:${Gne()}`;return Une("sha256").update(e).digest("hex")}function oL(e,t){let r=Jne();if(r){iL||(go.info("Anonymous usage telemetry enabled. Set SHIPLIGHT_TELEMETRY=0 to disable."),iL=!0);try{r.capture({distinctId:Yne(),event:"mcp_new_session",properties:{product:"mcp-server",version:e,platform:sL(),nodeVersion:process.version,cloudMode:t,$geoip_disable:!0,$ip:null}}),r.flush().catch(()=>{})}catch{}}}var Vne,zne,Kne,Jw,iL,aL=mt(()=>{"use strict";Kw();Vne="phc_5Va2dHamGwJWX9qZqyRka5Lann5ATsg3LL4uyU63qin",zne="https://us.i.posthog.com",Kne=process.env.SHIPLIGHT_TELEMETRY==="0"||process.env.DO_NOT_TRACK==="1",Jw=null,iL=!1});var dL={};Mi(dL,{startServer:()=>aie});import{Server as Xne}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Zne}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as Qne,ListToolsRequestSchema as eie,ListResourcesRequestSchema as tie,ReadResourceRequestSchema as rie,ListPromptsRequestSchema as nie,GetPromptRequestSchema as iie,ErrorCode as Yw,McpError as Xw}from"@modelcontextprotocol/sdk/types.js";import cL from"axios";import sie from"dotenv";function Uc(e){return typeof e=="object"&&e!==null&&"code"in e&&e.code==="EPIPE"}function Hc(){lL||(lL=!0,process.exit(0))}function Fm(e){if(!process.stderr.destroyed){if(process.stderr.errored){Uc(process.stderr.errored)&&Hc();return}try{process.stderr.write(e)}catch(t){Uc(t)&&Hc()}}}function Bm(e){if(e instanceof Error)return e.stack||`${e.name}: ${e.message}`;if(typeof e=="object"&&e!==null)try{return JSON.stringify(e)}catch{return String(e)}return String(e)}async function Zw(){let{SessionTools:e,RelayTools:t,BrowserTools:r,DebugTools:n,LocalTestTools:i,SessionManager:s,ExtensionRelayServer:o,RelayElectionCoordinator:a}=await Promise.resolve().then(()=>(Vw(),nL));return{SessionTools:e,RelayTools:t,BrowserTools:r,DebugTools:n,LocalTestTools:i,SessionManager:s,ExtensionRelayServer:o,RelayElectionCoordinator:a}}function uL(){return process.env[oie]||null}async function aie(){let e=process.argv.includes("--debug"),t=process.env.SHIPLIGHT_RELAY_PORT&&parseInt(process.env.SHIPLIGHT_RELAY_PORT,10)||null;await new Qw(e,t).run()}var lL,ev,oie,Qw,pL=mt(()=>{"use strict";ED();Vw();Yn();Kw();aL();process.env.PWDEBUG="console";lL=!1;process.stdout.on("error",e=>{if(Uc(e)){Hc();return}Fm(`[MCP] stdout error: ${Bm(e)}
6409
6409
  `)});process.stderr.on("error",e=>{Uc(e)&&Hc()});ev=(...e)=>{Fm(`${e.map(Bm).join(" ")}
6410
- `)};console.log=ev;console.info=ev;console.debug=ev;process.on("uncaughtException",e=>{if(Uc(e)){Hc();return}Fm(`[MCP] Uncaught exception:
6410
+ `)};console.log=ev;console.info=ev;console.debug=ev;process.on("uncaughtException",e=>{if(Uc(e)){Hc();return}Fm(`[MCP] Uncaught exception (non-fatal):
6411
6411
  ${Bm(e)}
6412
- `),process.exit(1)});process.on("unhandledRejection",e=>{if(Uc(e)){Hc();return}Fm(`[MCP] Unhandled rejection:
6412
+ `)});process.on("unhandledRejection",e=>{if(Uc(e)){Hc();return}Fm(`[MCP] Unhandled rejection (non-fatal):
6413
6413
  ${Bm(e)}
6414
- `),process.exit(1)});sie.config({override:!1});oie="SHIPLIGHT_API_TOKEN";Qw=class{constructor(t=!1,r=null){this.debugMode=t;this.relayPort=r;Ep({stderrOnly:!0});let n=process.env.SHIPLIGHT_API_URL||"https://api.shiplight.ai";this.server=new Xne({name:"shiplight-mcp",version:"1.0.0"},{capabilities:{tools:{},resources:{},prompts:{}}}),this.registry=new dm;let i=uL();if(this.apiClient=i?new um({apiBaseUrl:n,getApiToken:()=>uL()}):null,this.apiClient){let s=new qd(this.apiClient);this.testCaseTools=s,this.registry.registerTools(qd,s,["getTestCase","getTemplate","getFunction","saveTestCase","saveTestAccount","saveTemplate","saveFunction"])}}server;registry;sessionBackend=null;apiClient;sessionTools=null;browserTools=null;debugTools=null;testCaseTools=null;localTestTools=null;relayTools=null;relayServer=null;relayCoordinator=null;async initBrowserTools(){let t=process.env.TERMINATION_TIMEOUT?parseInt(process.env.TERMINATION_TIMEOUT,10):null,{SessionTools:r,BrowserTools:n,DebugTools:i,LocalTestTools:s,SessionManager:o}=await Zw();this.sessionBackend=new o({terminationTimeout:t,onBeforeAction:process.env.SHIPLIGHT_ACTION_INDICATORS==="1"?xD:void 0}),this.sessionTools=new r(this.sessionBackend,this.apiClient),this.browserTools=new n(this.sessionBackend),this.debugTools=new i(this.sessionBackend),this.localTestTools=new s(this.sessionBackend,this.apiClient);let{RelayTools:a}=await Zw();this.relayTools=new a(this.sessionBackend),this.registry.registerAll(r,this.sessionTools).registerAll(n,this.browserTools).registerAll(i,this.debugTools).registerAll(s,this.localTestTools).registerAll(a,this.relayTools),this.apiClient&&this.registry.registerAll({toolDefinitions:s.cloudToolDefinitions},this.localTestTools)}async startRelayServer(){if(this.relayPort===null)return!1;let t=this.relayPort,{RelayTools:r,ExtensionRelayServer:n,RelayElectionCoordinator:i}=await Zw();if(!this.sessionBackend||!this.relayTools)return go.error("[MCP] Cannot start relay server: session backend not initialized"),!1;let s=`ws://127.0.0.1:${t}/cdp`,o=new i({port:t,onPromoted:async()=>{this.relayServer=new n,await this.relayServer.start(t),this.relayTools.setRelayServer(this.relayServer),this.debugMode&&this.registry.registerAll({toolDefinitions:r.debugToolDefinitions},this.relayTools),go.info(`[MCP] Promoted to relay master on port ${t}`)},onDemoted:async()=>{this.relayServer&&(await this.relayServer.stop(),this.relayServer=null),this.relayTools.setRemoteRelayUrl(s),go.info("[MCP] Demoted from relay master")}});return this.relayCoordinator=o,await o.start()==="master"?go.info(`[MCP] Relay master on port ${t}`):(this.relayTools.setRemoteRelayUrl(o.getCdpUrl()),go.info(`[MCP] Relay follower, master on port ${t}`)),!0}setupHandlers(){let{tools:t,handleToolCall:r}=this.registry.build();this.server.setRequestHandler(eie,async()=>({tools:t})),this.server.setRequestHandler(Qne,async n=>{try{let{name:i,arguments:s}=n.params,o=await r(i,s);return i==="new_session"&&oL("0.1.68",!!this.apiClient),{content:[{type:"text",text:o}]}}catch(i){let s=i instanceof Error?i.message:String(i);if(cL.isAxiosError(i)){let o=i.config?.url,a=i.config?.baseURL,l=i.response?.status;s=`${i.code||"AxiosError"}: ${i.message}`,(a||o)&&(s+=` (${a||""}${o||""})`),l&&(s+=` [${l}]`),console.error(`[MCP] API error: ${s}`)}throw cL.isAxiosError(i)&&i.response?.status===401&&(s="Authentication required. Contact info@shiplight.ai to get access to cloud services and advanced features."),new Xw(Yw.InternalError,s)}}),this.server.setRequestHandler(tie,async()=>({resources:gm()})),this.server.setRequestHandler(rie,async n=>{let{uri:i}=n.params,s=await ym(i);if(!s)throw new Xw(Yw.InvalidRequest,`Unknown resource: ${i}`);return{contents:[{uri:i,mimeType:"text/markdown",text:s}]}}),this.server.setRequestHandler(nie,async()=>({prompts:fm().map(i=>({name:i.name,description:i.description}))})),this.server.setRequestHandler(iie,async n=>{let{name:i}=n.params,s=hm(i);if(!s)throw new Xw(Yw.InvalidRequest,`Unknown prompt: ${i}`);return{messages:[{role:"user",content:{type:"text",text:s}}]}})}async run(){await this.initBrowserTools(),await this.startRelayServer(),this.setupHandlers();let t=new Zne;await this.server.connect(t),go.info("Shiplight MCP Server running on stdio")}}});var $m="0.1.68",hL=process.argv[2];if(process.argv.includes("--version")||process.argv.includes("-v")||hL==="version"){let e=$m==="unknown"||process.argv[1]?.includes("/monots");process.stdout.write(`shiplight-mcp ${e?`${$m}-local`:$m}
6414
+ `)});sie.config({override:!1});oie="SHIPLIGHT_API_TOKEN";Qw=class{constructor(t=!1,r=null){this.debugMode=t;this.relayPort=r;Ep({stderrOnly:!0});let n=process.env.SHIPLIGHT_API_URL||"https://api.shiplight.ai";this.server=new Xne({name:"shiplight-mcp",version:"1.0.0"},{capabilities:{tools:{},resources:{},prompts:{}}}),this.registry=new dm;let i=uL();if(this.apiClient=i?new um({apiBaseUrl:n,getApiToken:()=>uL()}):null,this.apiClient){let s=new qd(this.apiClient);this.testCaseTools=s,this.registry.registerTools(qd,s,["getTestCase","getTemplate","getFunction","saveTestCase","saveTestAccount","saveTemplate","saveFunction"])}}server;registry;sessionBackend=null;apiClient;sessionTools=null;browserTools=null;debugTools=null;testCaseTools=null;localTestTools=null;relayTools=null;relayServer=null;relayCoordinator=null;async initBrowserTools(){let t=process.env.TERMINATION_TIMEOUT?parseInt(process.env.TERMINATION_TIMEOUT,10):null,{SessionTools:r,BrowserTools:n,DebugTools:i,LocalTestTools:s,SessionManager:o}=await Zw();this.sessionBackend=new o({terminationTimeout:t,onBeforeAction:process.env.SHIPLIGHT_ACTION_INDICATORS==="1"?xD:void 0}),this.sessionTools=new r(this.sessionBackend,this.apiClient),this.browserTools=new n(this.sessionBackend),this.debugTools=new i(this.sessionBackend),this.localTestTools=new s(this.sessionBackend,this.apiClient);let{RelayTools:a}=await Zw();this.relayTools=new a(this.sessionBackend),this.registry.registerAll(r,this.sessionTools).registerAll(n,this.browserTools).registerAll(i,this.debugTools).registerAll(s,this.localTestTools).registerAll(a,this.relayTools),this.apiClient&&this.registry.registerAll({toolDefinitions:s.cloudToolDefinitions},this.localTestTools)}async startRelayServer(){if(this.relayPort===null)return!1;let t=this.relayPort,{RelayTools:r,ExtensionRelayServer:n,RelayElectionCoordinator:i}=await Zw();if(!this.sessionBackend||!this.relayTools)return go.error("[MCP] Cannot start relay server: session backend not initialized"),!1;let s=`ws://127.0.0.1:${t}/cdp`,o=new i({port:t,onPromoted:async()=>{this.relayServer=new n,await this.relayServer.start(t),this.relayTools.setRelayServer(this.relayServer),this.debugMode&&this.registry.registerAll({toolDefinitions:r.debugToolDefinitions},this.relayTools),go.info(`[MCP] Promoted to relay master on port ${t}`)},onDemoted:async()=>{this.relayServer&&(await this.relayServer.stop(),this.relayServer=null),this.relayTools.setRemoteRelayUrl(s),go.info("[MCP] Demoted from relay master")}});return this.relayCoordinator=o,await o.start()==="master"?go.info(`[MCP] Relay master on port ${t}`):(this.relayTools.setRemoteRelayUrl(o.getCdpUrl()),go.info(`[MCP] Relay follower, master on port ${t}`)),!0}setupHandlers(){let{tools:t,handleToolCall:r}=this.registry.build();this.server.setRequestHandler(eie,async()=>({tools:t})),this.server.setRequestHandler(Qne,async n=>{try{let{name:i,arguments:s}=n.params,o=await r(i,s);return i==="new_session"&&oL("0.1.69",!!this.apiClient),{content:[{type:"text",text:o}]}}catch(i){let s=i instanceof Error?i.message:String(i);if(cL.isAxiosError(i)){let o=i.config?.url,a=i.config?.baseURL,l=i.response?.status;s=`${i.code||"AxiosError"}: ${i.message}`,(a||o)&&(s+=` (${a||""}${o||""})`),l&&(s+=` [${l}]`),console.error(`[MCP] API error: ${s}`)}throw cL.isAxiosError(i)&&i.response?.status===401&&(s="Authentication required. Contact info@shiplight.ai to get access to cloud services and advanced features."),new Xw(Yw.InternalError,s)}}),this.server.setRequestHandler(tie,async()=>({resources:gm()})),this.server.setRequestHandler(rie,async n=>{let{uri:i}=n.params,s=await ym(i);if(!s)throw new Xw(Yw.InvalidRequest,`Unknown resource: ${i}`);return{contents:[{uri:i,mimeType:"text/markdown",text:s}]}}),this.server.setRequestHandler(nie,async()=>({prompts:fm().map(i=>({name:i.name,description:i.description}))})),this.server.setRequestHandler(iie,async n=>{let{name:i}=n.params,s=hm(i);if(!s)throw new Xw(Yw.InvalidRequest,`Unknown prompt: ${i}`);return{messages:[{role:"user",content:{type:"text",text:s}}]}})}async run(){await this.initBrowserTools(),await this.startRelayServer(),this.setupHandlers();let t=new Zne;await this.server.connect(t),go.info("Shiplight MCP Server running on stdio")}}});var $m="0.1.69",hL=process.argv[2];if(process.argv.includes("--version")||process.argv.includes("-v")||hL==="version"){let e=$m==="unknown"||process.argv[1]?.includes("/monots");process.stdout.write(`shiplight-mcp ${e?`${$m}-local`:$m}
6415
6415
  `),process.exit(0)}if(process.argv.includes("--chrome-extension-path")){let e=new URL("../chrome-extension",import.meta.url).pathname;process.stdout.write(e+`
6416
6416
  `),process.exit(0)}(process.argv.includes("--help")||process.argv.includes("-h")||hL==="help")&&(process.stdout.write(`shiplight-mcp ${$m}
6417
6417
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shiplightai/mcp",
3
- "version": "0.1.68",
3
+ "version": "0.1.69",
4
4
  "type": "module",
5
5
  "description": "Shiplight MCP server for AI-powered test automation",
6
6
  "main": "dist/index.js",
@@ -16,14 +16,6 @@
16
16
  "registry": "https://registry.npmjs.org",
17
17
  "access": "public"
18
18
  },
19
- "scripts": {
20
- "build": "tsup && rm -rf ./chrome-extension && cp -r ../../packages/mcp-tools/chrome-extension ./chrome-extension",
21
- "build:deps": "turbo run build --filter=@shiplightai/mcp",
22
- "clean": "rm -rf dist chrome-extension",
23
- "dev": "tsup --watch",
24
- "start": "node dist/index.js",
25
- "typecheck": "tsc --noEmit"
26
- },
27
19
  "dependencies": {
28
20
  "@ai-sdk/anthropic": "^3.0.1",
29
21
  "@ai-sdk/google": "^3.0.1",
@@ -61,14 +53,22 @@
61
53
  },
62
54
  "devDependencies": {
63
55
  "@types/node": "^24.0.0",
64
- "mcp-tools": "workspace:*",
65
- "sdk-core": "workspace:*",
66
- "sdk-internal": "workspace:*",
67
- "shiplight-tools": "workspace:*",
68
- "shiplight-types": "workspace:*",
69
- "tsup": "^8.3.5"
56
+ "tsup": "^8.3.5",
57
+ "mcp-tools": "1.0.0",
58
+ "sdk-internal": "0.1.1",
59
+ "shiplight-types": "0.1.0",
60
+ "sdk-core": "0.1.0",
61
+ "shiplight-tools": "1.0.0"
70
62
  },
71
63
  "engines": {
72
64
  "node": ">=22.0.0"
65
+ },
66
+ "scripts": {
67
+ "build": "tsup && rm -rf ./chrome-extension && cp -r ../../packages/mcp-tools/chrome-extension ./chrome-extension",
68
+ "build:deps": "turbo run build --filter=@shiplightai/mcp",
69
+ "clean": "rm -rf dist chrome-extension",
70
+ "dev": "tsup --watch",
71
+ "start": "node dist/index.js",
72
+ "typecheck": "tsc --noEmit"
73
73
  }
74
- }
74
+ }