@stophy/mcp 2.0.0 → 2.0.1
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 +10 -2
- package/dist/index.js +1 -1
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Stophy MCP
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://smithery.ai/servers/stophy/mcp)
|
|
4
|
+
|
|
5
|
+
Live data from 40+ sites for AI agents over MCP: web search, YouTube, Reddit, Google Maps, Amazon, jobs, real estate, ads, stocks and crypto. Your agent reaches every Stophy endpoint through three MCP tools.
|
|
6
|
+
|
|
7
|
+
[](https://cursor.com/en/install-mcp?name=stophy&config=eyJ1cmwiOiJodHRwczovL2FwaS5zdG9waHkuZGV2L21jcC1vYXV0aCJ9)
|
|
4
8
|
|
|
5
9
|
## Connect to the hosted server
|
|
6
10
|
|
|
@@ -14,6 +18,10 @@ Most apps can connect to the hosted server directly. There is nothing to install
|
|
|
14
18
|
|
|
15
19
|
Get an API key at [stophy.dev/signup](https://stophy.dev/signup).
|
|
16
20
|
|
|
21
|
+
### Claude
|
|
22
|
+
|
|
23
|
+
In Claude on the web, Desktop or mobile, open [Customize > Connectors](https://claude.ai/customize/connectors), choose **Add custom connector**, and paste `https://api.stophy.dev/mcp-oauth`. Sign in when Claude asks.
|
|
24
|
+
|
|
17
25
|
### Claude Code
|
|
18
26
|
|
|
19
27
|
To sign in with your browser, add the server, then run `/mcp` and choose **Authenticate**:
|
|
@@ -51,7 +59,7 @@ codex mcp login stophy
|
|
|
51
59
|
|
|
52
60
|
### Cursor
|
|
53
61
|
|
|
54
|
-
Add this to `.cursor/mcp.json
|
|
62
|
+
Use the **Add to Cursor** button above to sign in with your browser, or add this to `.cursor/mcp.json` to use a key:
|
|
55
63
|
|
|
56
64
|
```json
|
|
57
65
|
{
|
package/dist/index.js
CHANGED
|
@@ -42,5 +42,5 @@ ${_e}`,d++}else Fh(y,x,G)?f=y.slice(y.charCodeAt(x+6)===wt?x+7:x+6,j)||void 0:v(
|
|
|
42
42
|
${ia}`,d++;return}if(Fh(y,x,G)){f=y.slice(y.charCodeAt(x+6)===wt?x+7:x+6,j)||void 0;return}if(G===105&&y.charCodeAt(x+1)===100&&y.charCodeAt(x+2)===58){let Ke=y.slice(y.charCodeAt(x+3)===wt?x+4:x+3,j);c=Ke.includes("\x00")?void 0:Ke;return}if(G===58){if(n){let Ke=y.slice(x,j);n(Ke.slice(y.charCodeAt(x+1)===wt?2:1))}return}let te=y.slice(x,j),_e=te.indexOf(":");if(_e===-1){k(te,"",te);return}let Gt=te.slice(0,_e),Vr=te.charCodeAt(_e+1)===wt?2:1,Fr=te.slice(_e+Vr);k(Gt,Fr,te)}function k(y,x,j){switch(y){case"event":f=x||void 0;break;case"data":l=d===0?x:`${l}
|
|
43
43
|
${x}`,d++;break;case"id":c=x.includes("\x00")?void 0:x;break;case"retry":/^\d+$/.test(x)?o(parseInt(x,10)):r(new kn(`Invalid \`retry\` value: "${x}"`,{type:"invalid-retry",value:x,line:j}));break;default:r(new kn(`Unknown field "${y.length>20?`${y.slice(0,20)}…`:y}"`,{type:"unknown-field",field:y,value:x,line:j}));break}}function b(){d>0&&t({id:c,event:f,data:l}),c=void 0,l="",d=0,f=void 0}function C(y={}){if(y.consume&&i.length>0){let x=i.join("");v(x,0,x.length)}u=!0,c=void 0,l="",d=0,f=void 0,i.length=0,a=0,m=!1}return{feed:h,reset:C}}function Vh(e,t,r){return r===100&&e.charCodeAt(t+1)===97&&e.charCodeAt(t+2)===116&&e.charCodeAt(t+3)===97&&e.charCodeAt(t+4)===58}function Fh(e,t,r){return r===101&&e.charCodeAt(t+1)===118&&e.charCodeAt(t+2)===101&&e.charCodeAt(t+3)===110&&e.charCodeAt(t+4)===116&&e.charCodeAt(t+5)===58}class Xi extends TransformStream{constructor({onError:e,onRetry:t,onComment:r,maxBufferSize:o}={}){let n;super({start(s){n=Hh({onEvent:(i)=>{s.enqueue(i)},onError(i){typeof e=="function"&&e(i),(e==="terminate"||i.type==="max-buffer-size-exceeded")&&s.error(i)},onRetry:t,onComment:r,maxBufferSize:o})},transform(s){n.feed(s)}})}}var AS={initialReconnectionDelay:1000,maxReconnectionDelay:30000,reconnectionDelayGrowFactor:1.5,maxRetries:2};class xt extends Error{constructor(e,t){super(`Streamable HTTP error: ${t}`);this.code=e}}class ea{constructor(e,t){this._hasCompletedAuthFlow=!1,this._url=e,this._resourceMetadataUrl=void 0,this._scope=void 0,this._requestInit=t?.requestInit,this._authProvider=t?.authProvider,this._fetch=t?.fetch,this._fetchWithInit=Ph(t?.fetch,t?.requestInit),this._sessionId=t?.sessionId,this._reconnectionOptions=t?.reconnectionOptions??AS}async _authThenStart(){if(!this._authProvider)throw new ut("No auth provider");let e;try{e=await Ur(this._authProvider,{serverUrl:this._url,resourceMetadataUrl:this._resourceMetadataUrl,scope:this._scope,fetchFn:this._fetchWithInit})}catch(t){throw this.onerror?.(t),t}if(e!=="AUTHORIZED")throw new ut;return await this._startOrAuthSse({resumptionToken:void 0})}async _commonHeaders(){let e={};if(this._authProvider){let r=await this._authProvider.tokens();if(r)e.Authorization=`Bearer ${r.access_token}`}if(this._sessionId)e["mcp-session-id"]=this._sessionId;if(this._protocolVersion)e["mcp-protocol-version"]=this._protocolVersion;let t=fn(this._requestInit?.headers);return new Headers({...e,...t})}async _startOrAuthSse(e){let{resumptionToken:t}=e;try{let r=await this._commonHeaders();if(r.set("Accept","text/event-stream"),t)r.set("last-event-id",t);let o=await(this._fetch??fetch)(this._url,{method:"GET",headers:r,signal:this._abortController?.signal});if(!o.ok){if(await o.body?.cancel(),o.status===401&&this._authProvider)return await this._authThenStart();if(o.status===405)return;throw new xt(o.status,`Failed to open SSE stream: ${o.statusText}`)}this._handleSseStream(o.body,e,!0)}catch(r){throw this.onerror?.(r),r}}_getNextReconnectionDelay(e){if(this._serverRetryMs!==void 0)return this._serverRetryMs;let t=this._reconnectionOptions.initialReconnectionDelay,r=this._reconnectionOptions.reconnectionDelayGrowFactor,o=this._reconnectionOptions.maxReconnectionDelay;return Math.min(t*Math.pow(r,e),o)}_scheduleReconnection(e,t=0){let r=this._reconnectionOptions.maxRetries;if(t>=r){this.onerror?.(Error(`Maximum reconnection attempts (${r}) exceeded.`));return}let o=this._getNextReconnectionDelay(t);this._reconnectionTimeout=setTimeout(()=>{this._startOrAuthSse(e).catch((n)=>{this.onerror?.(Error(`Failed to reconnect SSE stream: ${n instanceof Error?n.message:String(n)}`)),this._scheduleReconnection(e,t+1)})},o)}_handleSseStream(e,t,r){if(!e)return;let{onresumptiontoken:o,replayMessageId:n}=t,s,i=!1,a=!1;(async()=>{try{let c=e.pipeThrough(new TextDecoderStream).pipeThrough(new Xi({onRetry:(f)=>{this._serverRetryMs=f}})).getReader();while(!0){let{value:f,done:m}=await c.read();if(m)break;if(f.id)s=f.id,i=!0,o?.(f.id);if(!f.data)continue;if(!f.event||f.event==="message")try{let h=It.parse(JSON.parse(f.data));if(pt(h)){if(a=!0,n!==void 0)h.id=n}this.onmessage?.(h)}catch(h){this.onerror?.(h)}}if((r||i)&&!a&&this._abortController&&!this._abortController.signal.aborted)this._scheduleReconnection({resumptionToken:s,onresumptiontoken:o,replayMessageId:n},0)}catch(c){if(this.onerror?.(Error(`SSE stream disconnected: ${c}`)),(r||i)&&!a&&this._abortController&&!this._abortController.signal.aborted)try{this._scheduleReconnection({resumptionToken:s,onresumptiontoken:o,replayMessageId:n},0)}catch(f){this.onerror?.(Error(`Failed to reconnect: ${f instanceof Error?f.message:String(f)}`))}}})()}async start(){if(this._abortController)throw Error("StreamableHTTPClientTransport already started! If using Client class, note that connect() calls start() automatically.");this._abortController=new AbortController}async finishAuth(e){if(!this._authProvider)throw new ut("No auth provider");if(await Ur(this._authProvider,{serverUrl:this._url,authorizationCode:e,resourceMetadataUrl:this._resourceMetadataUrl,scope:this._scope,fetchFn:this._fetchWithInit})!=="AUTHORIZED")throw new ut("Failed to authorize")}async close(){if(this._reconnectionTimeout)clearTimeout(this._reconnectionTimeout),this._reconnectionTimeout=void 0;this._abortController?.abort(),this.onclose?.()}async send(e,t){try{let{resumptionToken:r,onresumptiontoken:o}=t||{};if(r){this._startOrAuthSse({resumptionToken:r,replayMessageId:sr(e)?e.id:void 0}).catch((d)=>this.onerror?.(d));return}let n=await this._commonHeaders();n.set("content-type","application/json"),n.set("accept","application/json, text/event-stream");let s={...this._requestInit,method:"POST",headers:n,body:JSON.stringify(e),signal:this._abortController?.signal},i=await(this._fetch??fetch)(this._url,s),a=i.headers.get("mcp-session-id");if(a)this._sessionId=a;if(!i.ok){let d=await i.text().catch(()=>null);if(i.status===401&&this._authProvider){if(this._hasCompletedAuthFlow)throw new xt(401,"Server returned 401 after successful authentication");let{resourceMetadataUrl:f,scope:m}=Gi(i);if(this._resourceMetadataUrl=f,this._scope=m,await Ur(this._authProvider,{serverUrl:this._url,resourceMetadataUrl:this._resourceMetadataUrl,scope:this._scope,fetchFn:this._fetchWithInit})!=="AUTHORIZED")throw new ut;return this._hasCompletedAuthFlow=!0,this.send(e)}if(i.status===403&&this._authProvider){let{resourceMetadataUrl:f,scope:m,error:h}=Gi(i);if(h==="insufficient_scope"){let _=i.headers.get("WWW-Authenticate");if(this._lastUpscopingHeader===_)throw new xt(403,"Server returned 403 after trying upscoping");if(m)this._scope=m;if(f)this._resourceMetadataUrl=f;if(this._lastUpscopingHeader=_??void 0,await Ur(this._authProvider,{serverUrl:this._url,resourceMetadataUrl:this._resourceMetadataUrl,scope:this._scope,fetchFn:this._fetch})!=="AUTHORIZED")throw new ut;return this.send(e)}}throw new xt(i.status,`Error POSTing to endpoint: ${d}`)}if(this._hasCompletedAuthFlow=!1,this._lastUpscopingHeader=void 0,i.status===202){if(await i.body?.cancel(),Ol(e))this._startOrAuthSse({resumptionToken:void 0}).catch((d)=>this.onerror?.(d));return}let c=(Array.isArray(e)?e:[e]).filter((d)=>("method"in d)&&("id"in d)&&d.id!==void 0).length>0,l=i.headers.get("content-type");if(c)if(l?.includes("text/event-stream"))this._handleSseStream(i.body,{onresumptiontoken:o},!1);else if(l?.includes("application/json")){let d=await i.json(),f=Array.isArray(d)?d.map((m)=>It.parse(m)):[It.parse(d)];for(let m of f)this.onmessage?.(m)}else throw await i.body?.cancel(),new xt(-1,`Unexpected content type: ${l}`);else await i.body?.cancel()}catch(r){throw this.onerror?.(r),r}}get sessionId(){return this._sessionId}async terminateSession(){if(!this._sessionId)return;try{let e=await this._commonHeaders(),t={...this._requestInit,method:"DELETE",headers:e,signal:this._abortController?.signal},r=await(this._fetch??fetch)(this._url,t);if(await r.body?.cancel(),!r.ok&&r.status!==405)throw new xt(r.status,`Failed to terminate session: ${r.statusText}`);this._sessionId=void 0}catch(e){throw this.onerror?.(e),e}}setProtocolVersion(e){this._protocolVersion=e}get protocolVersion(){return this._protocolVersion}async resumeStream(e,t){await this._startOrAuthSse({resumptionToken:e,onresumptiontoken:t?.onresumptiontoken})}}class ta{constructor(e){this._server=e}requestStream(e,t,r){return this._server.requestStream(e,t,r)}createMessageStream(e,t){let r=this._server.getClientCapabilities();if((e.tools||e.toolChoice)&&!r?.sampling?.tools)throw Error("Client does not support sampling tools capability.");if(e.messages.length>0){let o=e.messages[e.messages.length-1],n=Array.isArray(o.content)?o.content:[o.content],s=n.some((c)=>c.type==="tool_result"),i=e.messages.length>1?e.messages[e.messages.length-2]:void 0,a=i?Array.isArray(i.content)?i.content:[i.content]:[],u=a.some((c)=>c.type==="tool_use");if(s){if(n.some((c)=>c.type!=="tool_result"))throw Error("The last message must contain only tool_result content if any is present");if(!u)throw Error("tool_result blocks are not matching any tool_use from the previous message")}if(u){let c=new Set(a.filter((d)=>d.type==="tool_use").map((d)=>d.id)),l=new Set(n.filter((d)=>d.type==="tool_result").map((d)=>d.toolUseId));if(c.size!==l.size||![...c].every((d)=>l.has(d)))throw Error("ids of tool_result blocks and tool_use blocks from previous message do not match")}}return this.requestStream({method:"sampling/createMessage",params:e},ft,t)}elicitInputStream(e,t){let r=this._server.getClientCapabilities(),o=e.mode??"form";switch(o){case"url":{if(!r?.elicitation?.url)throw Error("Client does not support url elicitation.");break}case"form":{if(!r?.elicitation?.form)throw Error("Client does not support form elicitation.");break}}let n=o==="form"&&e.mode===void 0?{...e,mode:"form"}:e;return this.requestStream({method:"elicitation/create",params:n},Xe,t)}async getTask(e,t){return this._server.getTask({taskId:e},t)}async getTaskResult(e,t,r){return this._server.getTaskResult({taskId:e},t,r)}async listTasks(e,t){return this._server.listTasks(e?{cursor:e}:void 0,t)}async cancelTask(e,t){return this._server.cancelTask({taskId:e},t)}}class ra extends gr{constructor(e,t){super(t);if(this._serverInfo=e,this._loggingLevels=new Map,this.LOG_LEVEL_SEVERITY=new Map(mr.options.map((r,o)=>[r,o])),this.isMessageIgnored=(r,o)=>{let n=this._loggingLevels.get(o);return n?this.LOG_LEVEL_SEVERITY.get(r)<this.LOG_LEVEL_SEVERITY.get(n):!1},this._capabilities=t?.capabilities??{},this._instructions=t?.instructions,this._jsonSchemaValidator=t?.jsonSchemaValidator??new Lr,this.setRequestHandler(fs,(r)=>this._oninitialize(r)),this.setNotificationHandler(go,()=>this.oninitialized?.()),this._capabilities.logging)this.setRequestHandler(Rs,async(r,o)=>{let n=o.sessionId||o.requestInfo?.headers["mcp-session-id"]||void 0,{level:s}=r.params,i=mr.safeParse(s);if(i.success)this._loggingLevels.set(n,i.data);return{}})}get experimental(){if(!this._experimental)this._experimental={tasks:new ta(this)};return this._experimental}registerCapabilities(e){if(this.transport)throw Error("Cannot register capabilities after connecting to transport");this._capabilities=ko(this._capabilities,e)}setRequestHandler(e,t){let o=Et(e)?.method;if(!o)throw Error("Schema is missing a method literal");let n;if(Je(o)){let i=o;n=i._zod?.def?.value??i.value}else{let i=o;n=i._def?.value??i.value}if(typeof n!=="string")throw Error("Schema method literal must be a string");if(n==="tools/call"){let i=async(a,u)=>{let c=fe(pr,a);if(!c.success){let m=c.error instanceof Error?c.error.message:String(c.error);throw new R(O.InvalidParams,`Invalid tools/call request: ${m}`)}let{params:l}=c.data,d=await Promise.resolve(t(a,u));if(l.task){let m=fe(De,d);if(!m.success){let h=m.error instanceof Error?m.error.message:String(m.error);throw new R(O.InvalidParams,`Invalid task creation result: ${h}`)}return m.data}let f=fe(Qe,d);if(!f.success){let m=f.error instanceof Error?f.error.message:String(f.error);throw new R(O.InvalidParams,`Invalid tools/call result: ${m}`)}return f.data};return super.setRequestHandler(e,i)}return super.setRequestHandler(e,t)}assertCapabilityForMethod(e){switch(e){case"sampling/createMessage":if(!this._clientCapabilities?.sampling)throw Error(`Client does not support sampling (required for ${e})`);break;case"elicitation/create":if(!this._clientCapabilities?.elicitation)throw Error(`Client does not support elicitation (required for ${e})`);break;case"roots/list":if(!this._clientCapabilities?.roots)throw Error(`Client does not support listing roots (required for ${e})`);break;case"ping":break}}assertNotificationCapability(e){switch(e){case"notifications/message":if(!this._capabilities.logging)throw Error(`Server does not support logging (required for ${e})`);break;case"notifications/resources/updated":case"notifications/resources/list_changed":if(!this._capabilities.resources)throw Error(`Server does not support notifying about resources (required for ${e})`);break;case"notifications/tools/list_changed":if(!this._capabilities.tools)throw Error(`Server does not support notifying of tool list changes (required for ${e})`);break;case"notifications/prompts/list_changed":if(!this._capabilities.prompts)throw Error(`Server does not support notifying of prompt list changes (required for ${e})`);break;case"notifications/elicitation/complete":if(!this._clientCapabilities?.elicitation?.url)throw Error(`Client does not support URL elicitation (required for ${e})`);break;case"notifications/cancelled":break;case"notifications/progress":break}}assertRequestHandlerCapability(e){if(!this._capabilities)return;switch(e){case"completion/complete":if(!this._capabilities.completions)throw Error(`Server does not support completions (required for ${e})`);break;case"logging/setLevel":if(!this._capabilities.logging)throw Error(`Server does not support logging (required for ${e})`);break;case"prompts/get":case"prompts/list":if(!this._capabilities.prompts)throw Error(`Server does not support prompts (required for ${e})`);break;case"resources/list":case"resources/templates/list":case"resources/read":if(!this._capabilities.resources)throw Error(`Server does not support resources (required for ${e})`);break;case"tools/call":case"tools/list":if(!this._capabilities.tools)throw Error(`Server does not support tools (required for ${e})`);break;case"tasks/get":case"tasks/list":case"tasks/result":case"tasks/cancel":if(!this._capabilities.tasks)throw Error(`Server does not support tasks capability (required for ${e})`);break;case"ping":case"initialize":break}}assertTaskCapability(e){dn(this._clientCapabilities?.tasks?.requests,e,"Client")}assertTaskHandlerCapability(e){if(!this._capabilities)return;ln(this._capabilities.tasks?.requests,e,"Server")}async _oninitialize(e){let t=e.params.protocolVersion;return this._clientCapabilities=e.params.capabilities,this._clientVersion=e.params.clientInfo,{protocolVersion:fo.includes(t)?t:Ge,capabilities:this.getCapabilities(),serverInfo:this._serverInfo,...this._instructions&&{instructions:this._instructions}}}getClientCapabilities(){return this._clientCapabilities}getClientVersion(){return this._clientVersion}getCapabilities(){return this._capabilities}async ping(){return this.request({method:"ping"},Me)}async createMessage(e,t){if(e.tools||e.toolChoice){if(!this._clientCapabilities?.sampling?.tools)throw Error("Client does not support sampling tools capability.")}if(e.messages.length>0){let r=e.messages[e.messages.length-1],o=Array.isArray(r.content)?r.content:[r.content],n=o.some((u)=>u.type==="tool_result"),s=e.messages.length>1?e.messages[e.messages.length-2]:void 0,i=s?Array.isArray(s.content)?s.content:[s.content]:[],a=i.some((u)=>u.type==="tool_use");if(n){if(o.some((u)=>u.type!=="tool_result"))throw Error("The last message must contain only tool_result content if any is present");if(!a)throw Error("tool_result blocks are not matching any tool_use from the previous message")}if(a){let u=new Set(i.filter((l)=>l.type==="tool_use").map((l)=>l.id)),c=new Set(o.filter((l)=>l.type==="tool_result").map((l)=>l.toolUseId));if(u.size!==c.size||![...u].every((l)=>c.has(l)))throw Error("ids of tool_result blocks and tool_use blocks from previous message do not match")}}if(e.tools)return this.request({method:"sampling/createMessage",params:e},hr,t);return this.request({method:"sampling/createMessage",params:e},ft,t)}async elicitInput(e,t){switch(e.mode??"form"){case"url":{if(!this._clientCapabilities?.elicitation?.url)throw Error("Client does not support url elicitation.");let o=e;return this.request({method:"elicitation/create",params:o},Xe,t)}case"form":{if(!this._clientCapabilities?.elicitation?.form)throw Error("Client does not support form elicitation.");let o=e.mode==="form"?e:{...e,mode:"form"},n=await this.request({method:"elicitation/create",params:o},Xe,t);if(n.action==="accept"&&n.content&&o.requestedSchema)try{let i=this._jsonSchemaValidator.getValidator(o.requestedSchema)(n.content);if(!i.valid)throw new R(O.InvalidParams,`Elicitation response content does not match requested schema: ${i.errorMessage}`)}catch(s){if(s instanceof R)throw s;throw new R(O.InternalError,`Error validating elicitation response: ${s instanceof Error?s.message:String(s)}`)}return n}}}createElicitationCompletionNotifier(e,t){if(!this._clientCapabilities?.elicitation?.url)throw Error("Client does not support URL elicitation (required for notifications/elicitation/complete)");return()=>this.notification({method:"notifications/elicitation/complete",params:{elicitationId:e}},t)}async listRoots(e,t){return this.request({method:"roots/list",params:e},js,t)}async sendLoggingMessage(e,t){if(this._capabilities.logging){if(!this.isMessageIgnored(e.level,t))return this.notification({method:"notifications/message",params:e})}}async sendResourceUpdated(e){return this.notification({method:"notifications/resources/updated",params:e})}async sendResourceListChanged(){return this.notification({method:"notifications/resources/list_changed"})}async sendToolListChanged(){return this.notification({method:"notifications/tools/list_changed"})}async sendPromptListChanged(){return this.notification({method:"notifications/prompts/list_changed"})}}import Bh from"node:process";class oa{append(e){this._buffer=this._buffer?Buffer.concat([this._buffer,e]):e}readMessage(){if(!this._buffer)return null;let e=this._buffer.indexOf(`
|
|
44
44
|
`);if(e===-1)return null;let t=this._buffer.toString("utf8",0,e).replace(/\r$/,"");return this._buffer=this._buffer.subarray(e+1),ZS(t)}clear(){this._buffer=void 0}}function ZS(e){return It.parse(JSON.parse(e))}function Kh(e){return JSON.stringify(e)+`
|
|
45
|
-
`}class na{constructor(e=Bh.stdin,t=Bh.stdout){this._stdin=e,this._stdout=t,this._readBuffer=new oa,this._started=!1,this._ondata=(r)=>{this._readBuffer.append(r),this.processReadBuffer()},this._onerror=(r)=>{this.onerror?.(r)}}async start(){if(this._started)throw Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");this._started=!0,this._stdin.on("data",this._ondata),this._stdin.on("error",this._onerror)}processReadBuffer(){while(!0)try{let e=this._readBuffer.readMessage();if(e===null)break;this.onmessage?.(e)}catch(e){this.onerror?.(e)}}async close(){if(this._stdin.off("data",this._ondata),this._stdin.off("error",this._onerror),this._stdin.listenerCount("data")===0)this._stdin.pause();this._readBuffer.clear(),this.onclose?.()}send(e){return new Promise((t)=>{let r=Kh(e);if(this._stdout.write(r))t();else this._stdout.once("drain",t)})}}var sa={name:"@stophy/mcp",version:"2.0.
|
|
45
|
+
`}class na{constructor(e=Bh.stdin,t=Bh.stdout){this._stdin=e,this._stdout=t,this._readBuffer=new oa,this._started=!1,this._ondata=(r)=>{this._readBuffer.append(r),this.processReadBuffer()},this._onerror=(r)=>{this.onerror?.(r)}}async start(){if(this._started)throw Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");this._started=!0,this._stdin.on("data",this._ondata),this._stdin.on("error",this._onerror)}processReadBuffer(){while(!0)try{let e=this._readBuffer.readMessage();if(e===null)break;this.onmessage?.(e)}catch(e){this.onerror?.(e)}}async close(){if(this._stdin.off("data",this._ondata),this._stdin.off("error",this._onerror),this._stdin.listenerCount("data")===0)this._stdin.pause();this._readBuffer.clear(),this.onclose?.()}send(e){return new Promise((t)=>{let r=Kh(e);if(this._stdout.write(r))t();else this._stdout.once("drain",t)})}}var sa={name:"@stophy/mcp",version:"2.0.1",description:"Live data from 40+ sites for AI agents over MCP: web search, YouTube, Reddit, Google Maps, Amazon, jobs, real estate, ads, stocks and crypto.",type:"module",bin:{"stophy-mcp":"dist/index.js"},files:["dist"],scripts:{build:"bun build ./src/index.ts --outfile ./dist/index.js --target node --minify && chmod +x ./dist/index.js",prepare:"bun run build",start:"node ./dist/index.js",dev:"bun run ./src/index.ts","check-types":"tsc --noEmit",changeset:"changeset",version:"changeset version"},publishConfig:{access:"public"},dependencies:{"@modelcontextprotocol/sdk":"^1.29.0"},devDependencies:{"@changesets/cli":"^2.31.0","@types/node":"^22.0.0",typescript:"^5.8.3"},engines:{node:">=18"},keywords:["stophy","mcp","mcp-server","ai-agent","ai-agents","llm","web-data","web-search","youtube","reddit","scraping","google-maps","transcripts","ads","finance","crypto"],mcpName:"io.github.stophydotdev/mcp",homepage:"https://stophy.dev",license:"MIT",repository:{type:"git",url:"git+https://github.com/stophydotdev/mcp.git"},bugs:{url:"https://github.com/stophydotdev/mcp/issues"}};var MS="https://api.stophy.dev/mcp",DS=()=>{let e=process.env.STOPHY_MCP_URL??MS;try{return new URL(e)}catch{throw Error(`STOPHY_MCP_URL is not a valid URL: ${e}`)}},LS=()=>{let e=process.env.STOPHY_API_KEY?.trim();return e?{Authorization:`Bearer ${e}`}:{}},US=async(e)=>{let t=new Ui({name:"stophy-mcp",version:sa.version}),r=new ea(e,{requestInit:{headers:LS()}});return await t.connect(r),t},VS=async()=>{let e=DS(),t;try{t=await US(e)}catch(o){let n=o instanceof Error?o.message:String(o),s=/401|unauthorized/iu.test(n)?" Check STOPHY_API_KEY, or unset it to use the free tools.":"";throw Error(`Could not connect to Stophy at ${e.origin}: ${n}.${s}`)}let r=new ra({name:"stophy",version:sa.version},{capabilities:{tools:{listChanged:!0}},instructions:t.getInstructions()});r.setRequestHandler(Ts,(o)=>t.listTools(o.params)),r.setRequestHandler(pr,(o)=>t.callTool(o.params)),t.setNotificationHandler(fr,()=>r.sendToolListChanged()),r.onclose=()=>{t.close()},await r.connect(new na)};VS().catch((e)=>{process.stderr.write(`${e instanceof Error?e.message:String(e)}
|
|
46
46
|
`),process.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stophy/mcp",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "Live data from 40+ sites for AI agents over MCP: web search, YouTube, Reddit, Google Maps, Amazon, jobs, real estate, ads, stocks and crypto.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"stophy-mcp": "dist/index.js"
|
|
@@ -43,7 +43,12 @@
|
|
|
43
43
|
"web-search",
|
|
44
44
|
"youtube",
|
|
45
45
|
"reddit",
|
|
46
|
-
"scraping"
|
|
46
|
+
"scraping",
|
|
47
|
+
"google-maps",
|
|
48
|
+
"transcripts",
|
|
49
|
+
"ads",
|
|
50
|
+
"finance",
|
|
51
|
+
"crypto"
|
|
47
52
|
],
|
|
48
53
|
"mcpName": "io.github.stophydotdev/mcp",
|
|
49
54
|
"homepage": "https://stophy.dev",
|