@stophy/mcp 2.0.2 → 2.0.4
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 +4 -4
- package/dist/index.js +1 -1
- package/package.json +3 -6
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://smithery.ai/servers/stophy/mcp)
|
|
4
4
|
|
|
5
|
-
Live data
|
|
5
|
+
Live web data as typed JSON for AI agents. Search, video, social, jobs, places, shopping, apps, property and ads behind one key, with a price shown before every call. You pay only for answers that come back. Your agent reaches every Stophy endpoint through three MCP tools.
|
|
6
6
|
|
|
7
7
|
[](https://cursor.com/en/install-mcp?name=stophy&config=eyJ1cmwiOiJodHRwczovL2FwaS5zdG9waHkuZGV2L21jcC1vYXV0aCJ9)
|
|
8
8
|
|
|
@@ -12,7 +12,7 @@ Most apps can connect to the hosted server directly. There is nothing to install
|
|
|
12
12
|
|
|
13
13
|
| URL | How you connect | What your agent can use |
|
|
14
14
|
| --- | --- | --- |
|
|
15
|
-
| `https://api.stophy.dev/mcp` | No key |
|
|
15
|
+
| `https://api.stophy.dev/mcp` | No key | Web search only |
|
|
16
16
|
| `https://api.stophy.dev/mcp` | `Authorization: Bearer <key>` header | Every endpoint |
|
|
17
17
|
| `https://api.stophy.dev/mcp-oauth` | Sign in with your browser | Every endpoint |
|
|
18
18
|
|
|
@@ -82,7 +82,7 @@ Some apps can only start a local MCP server. For those, use this package. It run
|
|
|
82
82
|
npx -y @stophy/mcp
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
With `STOPHY_API_KEY` set, your agent can use every endpoint. Without it, your agent
|
|
85
|
+
With `STOPHY_API_KEY` set, your agent can use every endpoint. Without it, your agent can use web search only.
|
|
86
86
|
|
|
87
87
|
### Claude Desktop
|
|
88
88
|
|
|
@@ -117,7 +117,7 @@ The package needs Node.js 18 or later.
|
|
|
117
117
|
| `stophy_describe_endpoint` | Shows the input an endpoint takes and what it returns |
|
|
118
118
|
| `stophy_call` | Runs an endpoint with `id`, `input` and optional `fields`, and returns JSON |
|
|
119
119
|
|
|
120
|
-
Your agent usually searches, then describes, then calls. Endpoint ids are camelCase, such as `webSearch` or `youtubeSearch`. Lists come back as `results`, and `fields` keeps only the keys you name on each row. Each result says how many credits it used. One call returns one page for
|
|
120
|
+
Your agent usually searches, then describes, then calls. Endpoint ids are camelCase, such as `webSearch` or `youtubeSearch`. Lists come back as `results`, and `fields` keeps only the keys you name on each row. Each result says how many credits it used. One call returns one page at the price shown for that endpoint, and `limit` on a list endpoint keeps at most that many rows from the page at the same price.
|
|
121
121
|
|
|
122
122
|
## More
|
|
123
123
|
|
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.4",description:"One API for live, structured web data. REST, MCP, SDK and CLI.",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","google-maps","transcripts","ads"],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 web search only.":"";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.4",
|
|
4
|
+
"description": "One API for live, structured web data. REST, MCP, SDK and CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"stophy-mcp": "dist/index.js"
|
|
@@ -43,12 +43,9 @@
|
|
|
43
43
|
"web-search",
|
|
44
44
|
"youtube",
|
|
45
45
|
"reddit",
|
|
46
|
-
"scraping",
|
|
47
46
|
"google-maps",
|
|
48
47
|
"transcripts",
|
|
49
|
-
"ads"
|
|
50
|
-
"finance",
|
|
51
|
-
"crypto"
|
|
48
|
+
"ads"
|
|
52
49
|
],
|
|
53
50
|
"mcpName": "io.github.stophydotdev/mcp",
|
|
54
51
|
"homepage": "https://stophy.dev",
|