@shiplightai/mcp 0.1.64 → 0.1.65
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/dist/index.js +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -6401,7 +6401,7 @@ ${i?`
|
|
|
6401
6401
|
});
|
|
6402
6402
|
</script>
|
|
6403
6403
|
</body>
|
|
6404
|
-
</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:$d(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(bw.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(bw.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 bw.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=[jd.scaffoldProjectTool,jd.validateTestYamlTool,jd.generateHtmlReportTool];static cloudToolDefinitions=[jd.uploadReportTool]}});var KR={};Li(KR,{ACT_SUPPORTED_ACTIONS:()=>nl,ActionEntitySchema:()=>Od,BrowserTools:()=>jR,DataTools:()=>HR,DebugTools:()=>UR,ExtensionRelayServer:()=>sR,LocalTestTools:()=>VR,PROMPTS:()=>cm,RESOURCES:()=>iw,RelayElectionCoordinator:()=>oR,RelayTools:()=>$R,SessionManager:()=>iR,SessionTools:()=>BR,StatementSchema:()=>In,TestCaseTools:()=>Ud,TestFlowSchema:()=>ea,TestResultTools:()=>GR,TokenApiClient:()=>lm,ToolRegistry:()=>pm,WebAgent:()=>tl,actHandler:()=>Tw,actSchema:()=>Sw,clearExecutionHistoryHandler:()=>Pw,clearExecutionHistorySchema:()=>Pm,clearExecutionHistoryToolMeta:()=>Iw,getActSchema:()=>Fw,getActToolDefinition:()=>Bw,getActToolMeta:()=>Aw,getActionEntitySchemaResource:()=>aw,getLocatorsHandler:()=>Lw,getLocatorsSchema:()=>Dm,getLocatorsToolMeta:()=>Mw,getPageInfoHandler:()=>Nw,getPageInfoSchema:()=>Om,getPageInfoToolMeta:()=>Ow,getPrompt:()=>um,getResource:()=>mm,getTestFlowJsonSchemaResource:()=>sw,getTestFlowYamlSchemaResource:()=>ow,inspectPageHandler:()=>Rw,inspectPageSchema:()=>Nm,inspectPageToolMeta:()=>Dw,listPrompts:()=>dm,listResources:()=>fm,missingApiTokenError:()=>$c,navigateHandler:()=>Ew,navigateSchema:()=>km,navigateToolMeta:()=>xw,scaffoldProject:()=>gm,updateVariablesHandler:()=>kw,updateVariablesSchema:()=>Im,updateVariablesToolMeta:()=>Cw});var $w=mt(()=>{"use strict";aR();Qf();lR();cR();uR();zR();lw();em();hm()});var jw,yne,go,Uw=mt(()=>{"use strict";jw=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)}},yne=jw.getInstance(),go=yne});import{createHash as bne}from"node:crypto";import{hostname as _ne,userInfo as wne,platform as YR,arch as vne}from"node:os";import{PostHog as xne}from"posthog-node";function Tne(){return Ane?null:(Hw||(Hw=new xne(Ene,{host:Sne,flushAt:1,flushInterval:3e4})),Hw)}function Cne(){let e=`${_ne()}:${wne().username}:${YR()}:${vne()}`;return bne("sha256").update(e).digest("hex")}function XR(e,t){let r=Tne();if(r){JR||(go.info("Anonymous usage telemetry enabled. Set SHIPLIGHT_TELEMETRY=0 to disable."),JR=!0);try{r.capture({distinctId:Cne(),event:"mcp_new_session",properties:{product:"mcp-server",version:e,platform:YR(),nodeVersion:process.version,cloudMode:t,$geoip_disable:!0,$ip:null}}),r.flush().catch(()=>{})}catch{}}}var Ene,Sne,Ane,Hw,JR,ZR=mt(()=>{"use strict";Uw();Ene="phc_5Va2dHamGwJWX9qZqyRka5Lann5ATsg3LL4uyU63qin",Sne="https://us.i.posthog.com",Ane=process.env.SHIPLIGHT_TELEMETRY==="0"||process.env.DO_NOT_TRACK==="1",Hw=null,JR=!1});var tM={};Li(tM,{startServer:()=>Bne});import{Server as kne}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Ine}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as Pne,ListToolsRequestSchema as One,ListResourcesRequestSchema as Nne,ReadResourceRequestSchema as Dne,ListPromptsRequestSchema as Rne,GetPromptRequestSchema as Mne,ErrorCode as qw,McpError as Gw}from"@modelcontextprotocol/sdk/types.js";import QR from"axios";import Lne from"dotenv";async function Ww(){let{SessionTools:e,RelayTools:t,BrowserTools:r,DebugTools:n,LocalTestTools:i,SessionManager:s,ExtensionRelayServer:o,RelayElectionCoordinator:a}=await Promise.resolve().then(()=>($w(),KR));return{SessionTools:e,RelayTools:t,BrowserTools:r,DebugTools:n,LocalTestTools:i,SessionManager:s,ExtensionRelayServer:o,RelayElectionCoordinator:a}}function eM(){return process.env[Fne]||null}async function Bne(){let e=process.argv.includes("--debug"),t=process.env.SHIPLIGHT_RELAY_PORT&&parseInt(process.env.SHIPLIGHT_RELAY_PORT,10)||null;await new Vw(e,t).run()}var zw,Fne,Vw,rM=mt(()=>{"use strict";fD();$w();Yn();Uw();ZR();process.env.PWDEBUG="console";zw=(...e)=>console.error(...e);console.log=zw;console.info=zw;console.debug=zw;process.on("uncaughtException",e=>{console.error("[MCP] Uncaught exception (non-fatal):",e)});process.on("unhandledRejection",e=>{console.error("[MCP] Unhandled rejection (non-fatal):",e)});Lne.config({override:!1});Fne="SHIPLIGHT_API_TOKEN";Vw=class{constructor(t=!1,r=null){this.debugMode=t;this.relayPort=r;vp({stderrOnly:!0});let n=process.env.SHIPLIGHT_API_URL||"https://api.shiplight.ai";this.server=new kne({name:"shiplight-mcp",version:"1.0.0"},{capabilities:{tools:{},resources:{},prompts:{}}}),this.registry=new pm;let i=eM();if(this.apiClient=i?new lm({apiBaseUrl:n,getApiToken:()=>eM()}):null,this.apiClient){let s=new Ud(this.apiClient);this.testCaseTools=s,this.registry.registerTools(Ud,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 Ww();this.sessionBackend=new o({terminationTimeout:t,onBeforeAction:process.env.SHIPLIGHT_ACTION_INDICATORS==="1"?hD: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 Ww();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 Ww();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(One,async()=>({tools:t})),this.server.setRequestHandler(Pne,async n=>{try{let{name:i,arguments:s}=n.params,o=await r(i,s);return i==="new_session"&&XR("0.1.64",!!this.apiClient),{content:[{type:"text",text:o}]}}catch(i){let s=i instanceof Error?i.message:String(i);if(QR.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 QR.isAxiosError(i)&&i.response?.status===401&&(s="Authentication required. Contact info@shiplight.ai to get access to cloud services and advanced features."),new Gw(qw.InternalError,s)}}),this.server.setRequestHandler(Nne,async()=>({resources:fm()})),this.server.setRequestHandler(Dne,async n=>{let{uri:i}=n.params,s=await mm(i);if(!s)throw new Gw(qw.InvalidRequest,`Unknown resource: ${i}`);return{contents:[{uri:i,mimeType:"text/markdown",text:s}]}}),this.server.setRequestHandler(Rne,async()=>({prompts:dm().map(i=>({name:i.name,description:i.description}))})),this.server.setRequestHandler(Mne,async n=>{let{name:i}=n.params,s=um(i);if(!s)throw new Gw(qw.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 Ine;await this.server.connect(t),go.info("Shiplight MCP Server running on stdio")}}});var Mm="0.1.64",nM=process.argv[2];if(process.argv.includes("--version")||process.argv.includes("-v")||nM==="version"){let e=Mm==="unknown"||process.argv[1]?.includes("/monots");process.stdout.write(`shiplight-mcp ${e?`${Mm}-local`:Mm}
|
|
6404
|
+
</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:$d(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(bw.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(bw.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 bw.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=[jd.scaffoldProjectTool,jd.validateTestYamlTool,jd.generateHtmlReportTool];static cloudToolDefinitions=[jd.uploadReportTool]}});var KR={};Li(KR,{ACT_SUPPORTED_ACTIONS:()=>nl,ActionEntitySchema:()=>Od,BrowserTools:()=>jR,DataTools:()=>HR,DebugTools:()=>UR,ExtensionRelayServer:()=>sR,LocalTestTools:()=>VR,PROMPTS:()=>cm,RESOURCES:()=>iw,RelayElectionCoordinator:()=>oR,RelayTools:()=>$R,SessionManager:()=>iR,SessionTools:()=>BR,StatementSchema:()=>In,TestCaseTools:()=>Ud,TestFlowSchema:()=>ea,TestResultTools:()=>GR,TokenApiClient:()=>lm,ToolRegistry:()=>pm,WebAgent:()=>tl,actHandler:()=>Tw,actSchema:()=>Sw,clearExecutionHistoryHandler:()=>Pw,clearExecutionHistorySchema:()=>Pm,clearExecutionHistoryToolMeta:()=>Iw,getActSchema:()=>Fw,getActToolDefinition:()=>Bw,getActToolMeta:()=>Aw,getActionEntitySchemaResource:()=>aw,getLocatorsHandler:()=>Lw,getLocatorsSchema:()=>Dm,getLocatorsToolMeta:()=>Mw,getPageInfoHandler:()=>Nw,getPageInfoSchema:()=>Om,getPageInfoToolMeta:()=>Ow,getPrompt:()=>um,getResource:()=>mm,getTestFlowJsonSchemaResource:()=>sw,getTestFlowYamlSchemaResource:()=>ow,inspectPageHandler:()=>Rw,inspectPageSchema:()=>Nm,inspectPageToolMeta:()=>Dw,listPrompts:()=>dm,listResources:()=>fm,missingApiTokenError:()=>$c,navigateHandler:()=>Ew,navigateSchema:()=>km,navigateToolMeta:()=>xw,scaffoldProject:()=>gm,updateVariablesHandler:()=>kw,updateVariablesSchema:()=>Im,updateVariablesToolMeta:()=>Cw});var $w=mt(()=>{"use strict";aR();Qf();lR();cR();uR();zR();lw();em();hm()});var jw,yne,go,Uw=mt(()=>{"use strict";jw=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)}},yne=jw.getInstance(),go=yne});import{createHash as bne}from"node:crypto";import{hostname as _ne,userInfo as wne,platform as YR,arch as vne}from"node:os";import{PostHog as xne}from"posthog-node";function Tne(){return Ane?null:(Hw||(Hw=new xne(Ene,{host:Sne,flushAt:1,flushInterval:3e4})),Hw)}function Cne(){let e=`${_ne()}:${wne().username}:${YR()}:${vne()}`;return bne("sha256").update(e).digest("hex")}function XR(e,t){let r=Tne();if(r){JR||(go.info("Anonymous usage telemetry enabled. Set SHIPLIGHT_TELEMETRY=0 to disable."),JR=!0);try{r.capture({distinctId:Cne(),event:"mcp_new_session",properties:{product:"mcp-server",version:e,platform:YR(),nodeVersion:process.version,cloudMode:t,$geoip_disable:!0,$ip:null}}),r.flush().catch(()=>{})}catch{}}}var Ene,Sne,Ane,Hw,JR,ZR=mt(()=>{"use strict";Uw();Ene="phc_5Va2dHamGwJWX9qZqyRka5Lann5ATsg3LL4uyU63qin",Sne="https://us.i.posthog.com",Ane=process.env.SHIPLIGHT_TELEMETRY==="0"||process.env.DO_NOT_TRACK==="1",Hw=null,JR=!1});var tM={};Li(tM,{startServer:()=>Bne});import{Server as kne}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Ine}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as Pne,ListToolsRequestSchema as One,ListResourcesRequestSchema as Nne,ReadResourceRequestSchema as Dne,ListPromptsRequestSchema as Rne,GetPromptRequestSchema as Mne,ErrorCode as qw,McpError as Gw}from"@modelcontextprotocol/sdk/types.js";import QR from"axios";import Lne from"dotenv";async function Ww(){let{SessionTools:e,RelayTools:t,BrowserTools:r,DebugTools:n,LocalTestTools:i,SessionManager:s,ExtensionRelayServer:o,RelayElectionCoordinator:a}=await Promise.resolve().then(()=>($w(),KR));return{SessionTools:e,RelayTools:t,BrowserTools:r,DebugTools:n,LocalTestTools:i,SessionManager:s,ExtensionRelayServer:o,RelayElectionCoordinator:a}}function eM(){return process.env[Fne]||null}async function Bne(){let e=process.argv.includes("--debug"),t=process.env.SHIPLIGHT_RELAY_PORT&&parseInt(process.env.SHIPLIGHT_RELAY_PORT,10)||null;await new Vw(e,t).run()}var zw,Fne,Vw,rM=mt(()=>{"use strict";fD();$w();Yn();Uw();ZR();process.env.PWDEBUG="console";zw=(...e)=>console.error(...e);console.log=zw;console.info=zw;console.debug=zw;process.on("uncaughtException",e=>{console.error("[MCP] Uncaught exception (non-fatal):",e)});process.on("unhandledRejection",e=>{console.error("[MCP] Unhandled rejection (non-fatal):",e)});Lne.config({override:!1});Fne="SHIPLIGHT_API_TOKEN";Vw=class{constructor(t=!1,r=null){this.debugMode=t;this.relayPort=r;vp({stderrOnly:!0});let n=process.env.SHIPLIGHT_API_URL||"https://api.shiplight.ai";this.server=new kne({name:"shiplight-mcp",version:"1.0.0"},{capabilities:{tools:{},resources:{},prompts:{}}}),this.registry=new pm;let i=eM();if(this.apiClient=i?new lm({apiBaseUrl:n,getApiToken:()=>eM()}):null,this.apiClient){let s=new Ud(this.apiClient);this.testCaseTools=s,this.registry.registerTools(Ud,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 Ww();this.sessionBackend=new o({terminationTimeout:t,onBeforeAction:process.env.SHIPLIGHT_ACTION_INDICATORS==="1"?hD: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 Ww();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 Ww();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(One,async()=>({tools:t})),this.server.setRequestHandler(Pne,async n=>{try{let{name:i,arguments:s}=n.params,o=await r(i,s);return i==="new_session"&&XR("0.1.65",!!this.apiClient),{content:[{type:"text",text:o}]}}catch(i){let s=i instanceof Error?i.message:String(i);if(QR.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 QR.isAxiosError(i)&&i.response?.status===401&&(s="Authentication required. Contact info@shiplight.ai to get access to cloud services and advanced features."),new Gw(qw.InternalError,s)}}),this.server.setRequestHandler(Nne,async()=>({resources:fm()})),this.server.setRequestHandler(Dne,async n=>{let{uri:i}=n.params,s=await mm(i);if(!s)throw new Gw(qw.InvalidRequest,`Unknown resource: ${i}`);return{contents:[{uri:i,mimeType:"text/markdown",text:s}]}}),this.server.setRequestHandler(Rne,async()=>({prompts:dm().map(i=>({name:i.name,description:i.description}))})),this.server.setRequestHandler(Mne,async n=>{let{name:i}=n.params,s=um(i);if(!s)throw new Gw(qw.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 Ine;await this.server.connect(t),go.info("Shiplight MCP Server running on stdio")}}});var Mm="0.1.65",nM=process.argv[2];if(process.argv.includes("--version")||process.argv.includes("-v")||nM==="version"){let e=Mm==="unknown"||process.argv[1]?.includes("/monots");process.stdout.write(`shiplight-mcp ${e?`${Mm}-local`:Mm}
|
|
6405
6405
|
`),process.exit(0)}if(process.argv.includes("--chrome-extension-path")){let e=new URL("../chrome-extension",import.meta.url).pathname;process.stdout.write(e+`
|
|
6406
6406
|
`),process.exit(0)}(process.argv.includes("--help")||process.argv.includes("-h")||nM==="help")&&(process.stdout.write(`shiplight-mcp ${Mm}
|
|
6407
6407
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shiplightai/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.65",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Shiplight MCP server for AI-powered test automation",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -54,11 +54,11 @@
|
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/node": "^24.0.0",
|
|
56
56
|
"tsup": "^8.3.5",
|
|
57
|
-
"sdk-core": "0.1.0",
|
|
58
57
|
"mcp-tools": "1.0.0",
|
|
59
58
|
"sdk-internal": "0.1.1",
|
|
60
|
-
"
|
|
61
|
-
"shiplight-tools": "1.0.0"
|
|
59
|
+
"sdk-core": "0.1.0",
|
|
60
|
+
"shiplight-tools": "1.0.0",
|
|
61
|
+
"shiplight-types": "0.1.0"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|
|
64
64
|
"node": ">=22.0.0"
|