@stophy/mcp 2.0.5 → 2.0.7

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 CHANGED
@@ -12,22 +12,22 @@ 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 | Web search only |
15
+ | `https://api.stophy.dev/mcp` | No key | Google search, Google News, YouTube search, YouTube video details and YouTube transcripts, within a free allowance |
16
16
  | `https://api.stophy.dev/mcp` | `Authorization: Bearer <key>` header | Every endpoint |
17
- | `https://api.stophy.dev/mcp-oauth` | Sign in with your browser | Every endpoint |
17
+ | `https://mcp.stophy.dev/mcp` | Sign in with your browser | Every endpoint |
18
18
 
19
19
  Get an API key at [stophy.dev/signup](https://stophy.dev/signup).
20
20
 
21
21
  ### Claude
22
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.
23
+ In Claude on the web, Desktop or mobile, open [Customize > Connectors](https://claude.ai/customize/connectors), choose **Add custom connector**, and paste `https://mcp.stophy.dev/mcp`. Sign in when Claude asks.
24
24
 
25
25
  ### Claude Code
26
26
 
27
27
  To sign in with your browser, add the server, then run `/mcp` and choose **Authenticate**:
28
28
 
29
29
  ```bash
30
- claude mcp add --transport http stophy https://api.stophy.dev/mcp-oauth
30
+ claude mcp add --transport http stophy https://mcp.stophy.dev/mcp
31
31
  ```
32
32
 
33
33
  To use an API key:
@@ -53,7 +53,7 @@ codex mcp add stophy --url https://api.stophy.dev/mcp --bearer-token-env-var STO
53
53
  To sign in with your browser instead, add the sign-in URL, then log in:
54
54
 
55
55
  ```bash
56
- codex mcp add stophy --url https://api.stophy.dev/mcp-oauth
56
+ codex mcp add stophy --url https://mcp.stophy.dev/mcp
57
57
  codex mcp login stophy
58
58
  ```
59
59
 
@@ -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 can use Google search only.
85
+ With `STOPHY_API_KEY` set, your agent can use every endpoint. Without it, your agent can use Google search, Google News, YouTube search, YouTube video details and YouTube transcripts.
86
86
 
87
87
  ### Claude Desktop
88
88
 
@@ -117,7 +117,9 @@ 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 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.
120
+ Your agent usually searches, then describes, then calls. Endpoint ids are camelCase, such as `googleSearch` 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.
121
+
122
+ One call returns one page from the site at the price shown for that endpoint. Some list endpoints take `page` and return `page` and `hasMore`: ask for the next number while `hasMore` is true. Others return a `cursor` when there is more: pass it back unchanged as `cursor` to get the next page.
121
123
 
122
124
  ## More
123
125
 
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.5",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","google-search","linkedin","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)}
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.7",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","google-search","linkedin","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 the free endpoints 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,6 +1,6 @@
1
1
  {
2
2
  "name": "@stophy/mcp",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "description": "One API for live, structured web data. REST, MCP, SDK and CLI.",
5
5
  "type": "module",
6
6
  "bin": {