@stophy/mcp 1.2.1 → 2.1.0
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 +2 -2
package/README.md
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://smithery.ai/servers/stophy/mcp)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Give your agents the live web over MCP. Your agent reaches every Stophy endpoint through three tools.
|
|
6
6
|
|
|
7
7
|
[](https://cursor.com/en/install-mcp?name=stophy&config=eyJ1cmwiOiJodHRwczovL21jcC5zdG9waHkuZGV2L21jcCJ9)
|
|
8
8
|
|
|
9
9
|
## Connect to the hosted server
|
|
10
10
|
|
|
11
|
-
Most apps
|
|
11
|
+
Most apps connect to the hosted server directly, with nothing to install.
|
|
12
12
|
|
|
13
13
|
| URL | How you connect | What your agent can use |
|
|
14
14
|
| ---------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -117,11 +117,11 @@ 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 `googleSearch` or `youtubeSearch`. Lists come back as `results`, and `fields` keeps only the keys you name on each row. Each result says
|
|
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 what it cost.
|
|
121
121
|
|
|
122
122
|
To point at one thing, send its link or its id, never both: `videoUrl` or `videoId`, `placeUrl` or `placeId`, `userUrl` or `username`. The endpoint description lists the pair.
|
|
123
123
|
|
|
124
|
-
One call returns one page from the site
|
|
124
|
+
One call returns one page from the site. Most calls cost $0.0015, long lists cost $0.0015 per 10 results, and a few cost more. See [pricing](https://docs.stophy.dev/billing). Some list endpoints take `page` and return `page`: ask for the next number, and stop when `results` comes back empty. Others return a `cursor` when there is more: pass it back unchanged as `cursor` to get the next page.
|
|
125
125
|
|
|
126
126
|
## Network and credentials
|
|
127
127
|
|
package/dist/index.js
CHANGED
|
@@ -77,5 +77,5 @@ ${se}`,d++}else Uv(b,x,Y)?m=b.slice(b.charCodeAt(x+6)===hr?x+7:x+6,N)||void 0:y(
|
|
|
77
77
|
${Kc}`,d++;return}if(Uv(b,x,Y)){m=b.slice(b.charCodeAt(x+6)===hr?x+7:x+6,N)||void 0;return}if(Y===105&&b.charCodeAt(x+1)===100&&b.charCodeAt(x+2)===58){let zt=b.slice(b.charCodeAt(x+3)===hr?x+4:x+3,N);zt.includes("\x00")||(c=zt);return}if(Y===58){if(o){let zt=b.slice(x,N);o(zt.slice(b.charCodeAt(x+1)===hr?2:1))}return}let F=b.slice(x,N),se=F.indexOf(":");if(se===-1){k(F,"",F);return}let mt=F.slice(0,se),rr=F.charCodeAt(se+1)===hr?2:1,_r=F.slice(se+rr);k(mt,_r,F)}function k(b,x,N){switch(b){case"event":m=x||void 0;break;case"data":l=d===0?x:`${l}
|
|
78
78
|
${x}`,d++;break;case"id":x.includes("\x00")||(c=x);break;case"retry":/^\d+$/.test(x)?n(parseInt(x,10)):r(new Gs(`Invalid \`retry\` value: "${x}"`,{type:"invalid-retry",value:x,line:N}));break;default:r(new Gs(`Unknown field "${b.length>20?`${b.slice(0,20)}…`:b}"`,{type:"unknown-field",field:b,value:x,line:N}));break}}function C(){d>0&&t({id:c,event:m,data:l}),c=void 0,l="",d=0,m=void 0}function U(b={}){if(b.consume&&i.length>0){let x=i.join("");y(x,0,x.length)}u=!0,c=void 0,l="",d=0,m=void 0,i.length=0,a=0,f=!1}return{feed:p,reset:U}}function Lv(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 Uv(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 Lc extends TransformStream{constructor({onError:e,onRetry:t,onComment:r,maxBufferSize:n}={}){let o;super({start(s){o=Fv({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:n})},transform(s){o.feed(s)}})}}var nO={initialReconnectionDelay:1000,maxReconnectionDelay:30000,reconnectionDelayGrowFactor:1.5,maxRetries:2};class gr extends Error{constructor(e,t){super(`Streamable HTTP error: ${t}`);this.code=e}}class Uc{constructor(e,t){if(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=wv(t?.fetch,t?.requestInit),this._followRedirects=t?.redirectPolicy==="follow",this._followRedirects)this._fetch=Tc(this._fetch),this._fetchWithInit=Tc(this._fetchWithInit);this._sessionId=t?.sessionId,this._reconnectionOptions=t?.reconnectionOptions??nO}_unfollowedRedirect(e,t){let r=Zs(e,t);return r&&!this._followRedirects?`${r} (redirectPolicy: 'same-origin')`:r}async _authThenStart(){if(!this._authProvider)throw new tr("No auth provider");let e;try{e=await Fn(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 tr;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=Ns(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 n=this._fetch??fetch,o={method:"GET",headers:r,signal:this._abortController?.signal},s=await n(this._url,this._followRedirects?o:{...o,redirect:"manual"}),i=this._followRedirects?void 0:js(n,this._url,o,s);if(i)s=await i;if(!s.ok){if(await s.body?.cancel(),s.status===401&&this._authProvider)return await this._authThenStart();if(s.status===405)return;throw new gr(s.status,`Failed to open SSE stream: ${this._unfollowedRedirect(s,this._url)??s.statusText}`)}this._handleSseStream(s.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,n=this._reconnectionOptions.maxReconnectionDelay;return Math.min(t*Math.pow(r,e),n)}_scheduleReconnection(e,t=0){let r=this._reconnectionOptions.maxRetries;if(t>=r){this.onerror?.(Error(`Maximum reconnection attempts (${r}) exceeded.`));return}let n=this._getNextReconnectionDelay(t);this._reconnectionTimeout=setTimeout(()=>{this._startOrAuthSse(e).catch((o)=>{this.onerror?.(Error(`Failed to reconnect SSE stream: ${o instanceof Error?o.message:String(o)}`)),this._scheduleReconnection(e,t+1)})},n)}_handleSseStream(e,t,r){if(!e)return;let{onresumptiontoken:n,replayMessageId:o}=t,s,i=!1,a=!1;(async()=>{try{let c=e.pipeThrough(new TextDecoderStream).pipeThrough(new Lc({onRetry:(m)=>{this._serverRetryMs=m}})).getReader();while(!0){let{value:m,done:f}=await c.read();if(f)break;if(m.id)s=m.id,i=!0,n?.(m.id);if(!m.data)continue;if(!m.event||m.event==="message")try{let p=Pr.parse(JSON.parse(m.data));if(ir(p)){if(a=!0,o!==void 0)p.id=o}this.onmessage?.(p)}catch(p){this.onerror?.(p)}}if((r||i)&&!a&&this._abortController&&!this._abortController.signal.aborted)this._scheduleReconnection({resumptionToken:s,onresumptiontoken:n,replayMessageId:o},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:n,replayMessageId:o},0)}catch(m){this.onerror?.(Error(`Failed to reconnect: ${m instanceof Error?m.message:String(m)}`))}}})()}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 tr("No auth provider");if(await Fn(this._authProvider,{serverUrl:this._url,authorizationCode:e,resourceMetadataUrl:this._resourceMetadataUrl,scope:this._scope,fetchFn:this._fetchWithInit})!=="AUTHORIZED")throw new tr("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:n}=t||{};if(r){this._startOrAuthSse({resumptionToken:r,replayMessageId:gn(e)?e.id:void 0}).catch((m)=>this.onerror?.(m));return}let o=await this._commonHeaders();o.set("content-type","application/json"),o.set("accept","application/json, text/event-stream");let s={...this._requestInit,method:"POST",headers:o,body:JSON.stringify(e),signal:this._abortController?.signal},i=await mr(this._fetch??fetch)(this._url,s),a=i.headers.get("mcp-session-id");if(a)this._sessionId=a;if(!i.ok){let m=await i.text().catch(()=>null);if(i.status===401&&this._authProvider){if(this._hasCompletedAuthFlow)throw new gr(401,"Server returned 401 after successful authentication");let{resourceMetadataUrl:f,scope:p}=Dc(i);if(this._resourceMetadataUrl=f,this._scope=p,await Fn(this._authProvider,{serverUrl:this._url,resourceMetadataUrl:this._resourceMetadataUrl,scope:this._scope,fetchFn:this._fetchWithInit})!=="AUTHORIZED")throw new tr;return this._hasCompletedAuthFlow=!0,this.send(e)}if(i.status===403&&this._authProvider){let{resourceMetadataUrl:f,scope:p,error:g}=Dc(i);if(g==="insufficient_scope"){let _=i.headers.get("WWW-Authenticate");if(this._lastUpscopingHeader===_)throw new gr(403,"Server returned 403 after trying upscoping");if(p)this._scope=p;if(f)this._resourceMetadataUrl=f;if(this._lastUpscopingHeader=_??void 0,await Fn(this._authProvider,{serverUrl:this._url,resourceMetadataUrl:this._resourceMetadataUrl,scope:this._scope,fetchFn:this._fetch})!=="AUTHORIZED")throw new tr;return this.send(e)}}throw new gr(i.status,`Error POSTing to endpoint: ${this._unfollowedRedirect(i,this._url)??m}`)}if(this._hasCompletedAuthFlow=!1,this._lastUpscopingHeader=void 0,i.status===202){if(await i.body?.cancel(),Kp(e))this._startOrAuthSse({resumptionToken:void 0}).catch((m)=>this.onerror?.(m));return}let c=(Array.isArray(e)?e:[e]).filter((m)=>("method"in m)&&("id"in m)&&m.id!==void 0).length>0,l=i.headers.get("content-type"),d=bv(l);if(c)if(d==="text/event-stream")this._handleSseStream(i.body,{onresumptiontoken:n},!1);else if(d==="application/json"){let m=await i.json(),f=Array.isArray(m)?m.map((p)=>Pr.parse(p)):[Pr.parse(m)];for(let p of f)this.onmessage?.(p)}else throw await i.body?.cancel(),new gr(-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 mr(this._fetch??fetch)(this._url,t);if(await r.body?.cancel(),!r.ok&&r.status!==405)throw new gr(r.status,`Failed to terminate session: ${this._unfollowedRedirect(r,this._url)??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 Fc{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 n=e.messages[e.messages.length-1],o=Array.isArray(n.content)?n.content:[n.content],s=o.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(o.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(o.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},ar,t)}elicitInputStream(e,t){let r=this._server.getClientCapabilities(),n=e.mode??"form";switch(n){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 o=n==="form"&&e.mode===void 0?{...e,mode:"form"}:e;return this.requestStream({method:"elicitation/create",params:o},Ct,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 Vc extends En{constructor(e,t){super(t);if(this._serverInfo=e,this._loggingLevels=new Map,this.LOG_LEVEL_SEVERITY=new Map(Sn.options.map((r,n)=>[r,n])),this.isMessageIgnored=(r,n)=>{let o=this._loggingLevels.get(n);return o?this.LOG_LEVEL_SEVERITY.get(r)<this.LOG_LEVEL_SEVERITY.get(o):!1},this._capabilities=t?.capabilities??{},this._instructions=t?.instructions,this._jsonSchemaValidator=t?.jsonSchemaValidator??new Un,this.setRequestHandler(ia,(r)=>this._oninitialize(r)),this.setNotificationHandler(Io,()=>this.oninitialized?.()),this._capabilities.logging)this.setRequestHandler($a,async(r,n)=>{let o=n.sessionId||n.requestInfo?.headers["mcp-session-id"]||void 0,{level:s}=r.params,i=Sn.safeParse(s);if(i.success)this._loggingLevels.set(o,i.data);return{}})}get experimental(){if(!this._experimental)this._experimental={tasks:new Fc(this)};return this._experimental}registerCapabilities(e){if(this.transport)throw Error("Cannot register capabilities after connecting to transport");this._capabilities=Lo(this._capabilities,e)}setRequestHandler(e,t){let n=zr(e)?.method;if(!n)throw Error("Schema is missing a method literal");let o=Sr(n);if(typeof o!=="string")throw Error("Schema method literal must be a string");if(o==="tools/call"){let i=async(a,u)=>{let c=Ee($n,a);if(!c.success){let f=c.error instanceof Error?c.error.message:String(c.error);throw new I(j.InvalidParams,`Invalid tools/call request: ${f}`)}let{params:l}=c.data,d=await Promise.resolve(t(a,u));if(l.task){let f=Ee(vt,d);if(!f.success){let p=f.error instanceof Error?f.error.message:String(f.error);throw new I(j.InvalidParams,`Invalid task creation result: ${p}`)}return f.data}let m=Ee(It,d);if(!m.success){let f=m.error instanceof Error?m.error.message:String(m.error);throw new I(j.InvalidParams,`Invalid tools/call result: ${f}`)}return m.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){Cs(this._clientCapabilities?.tasks?.requests,e,"Client")}assertTaskHandlerCapability(e){if(!this._capabilities)return;Is(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:Eo.includes(t)?t:Rt,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"},yt)}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],n=Array.isArray(r.content)?r.content:[r.content],o=n.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(o){if(n.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(n.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},kn,t);return this.request({method:"sampling/createMessage",params:e},ar,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 n=e;return this.request({method:"elicitation/create",params:n},Ct,t)}case"form":{if(!this._clientCapabilities?.elicitation?.form)throw Error("Client does not support form elicitation.");let n=e.mode==="form"?e:{...e,mode:"form"},o=await this.request({method:"elicitation/create",params:n},Ct,t);if(o.action==="accept"&&o.content&&n.requestedSchema)try{let i=this._jsonSchemaValidator.getValidator(n.requestedSchema)(o.content);if(!i.valid)throw new I(j.InvalidParams,`Elicitation response content does not match requested schema: ${i.errorMessage}`)}catch(s){if(s instanceof I)throw s;throw new I(j.InternalError,`Error validating elicitation response: ${s instanceof Error?s.message:String(s)}`)}return o}}}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},Pa,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 Hv from"node:process";var oO=10485760;class Hc{constructor(e){this._maxBufferSize=e?.maxBufferSize??oO}append(e){if((this._buffer?.length??0)+e.length>this._maxBufferSize)throw this.clear(),Error(`ReadBuffer exceeded maximum size of ${this._maxBufferSize} bytes`);this._buffer=this._buffer?Buffer.concat([this._buffer,e]):e}readMessage(){if(!this._buffer)return null;let e=this._buffer.indexOf(`
|
|
79
79
|
`);if(e===-1)return null;let t=this._buffer.toString("utf8",0,e).replace(/\r$/,"");return this._buffer=this._buffer.subarray(e+1),sO(t)}clear(){this._buffer=void 0}}function sO(e){return Pr.parse(JSON.parse(e))}function Vv(e){return JSON.stringify(e)+`
|
|
80
|
-
`}class Bc{constructor(e=Hv.stdin,t=Hv.stdout,r){this._stdin=e,this._stdout=t,this._started=!1,this._ondata=(n)=>{try{this._readBuffer.append(n),this.processReadBuffer()}catch(o){this.onerror?.(o),this.close().catch(()=>{})}},this._onerror=(n)=>{this.onerror?.(n)},this._readBuffer=new Hc({maxBufferSize:r?.maxBufferSize})}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=Vv(e);if(this._stdout.write(r))t();else this._stdout.once("drain",t)})}}var Jc={name:"@stophy/mcp",version:"
|
|
80
|
+
`}class Bc{constructor(e=Hv.stdin,t=Hv.stdout,r){this._stdin=e,this._stdout=t,this._started=!1,this._ondata=(n)=>{try{this._readBuffer.append(n),this.processReadBuffer()}catch(o){this.onerror?.(o),this.close().catch(()=>{})}},this._onerror=(n)=>{this.onerror?.(n)},this._readBuffer=new Hc({maxBufferSize:r?.maxBufferSize})}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=Vv(e);if(this._stdout.write(r))t();else this._stdout.once("drain",t)})}}var Jc={name:"@stophy/mcp",version:"2.1.0",description:"Give your agents the live web. One API to search the web, read what people say, and look up products, places, jobs and homes.",keywords:["ads","ai-agent","ai-agents","google-maps","google-search","linkedin","llm","mcp","mcp-server","reddit","stophy","transcripts","web-data","web-search","youtube"],homepage:"https://stophy.dev",bugs:{url:"https://github.com/stophydotdev/stophy/issues"},license:"MIT",repository:{type:"git",url:"git+https://github.com/stophydotdev/stophy.git",directory:"mcp"},bin:{"stophy-mcp":"dist/index.js"},files:["dist"],type:"module",publishConfig:{access:"public"},scripts:{build:"bun build ./src/index.ts --outfile ./dist/index.js --target node --minify --banner '#!/usr/bin/env node' && chmod +x ./dist/index.js",prepare:"bun run build",start:"node ./dist/index.js",dev:"bun run ./src/index.ts","check-types":"tsc --noEmit"},dependencies:{"@modelcontextprotocol/sdk":"^1.29.0"},devDependencies:{"@types/node":"^22.0.0",typescript:"^5.8.3"},engines:{node:">=18"},mcpName:"io.github.stophydotdev/mcp"};var aO="https://api.stophy.dev/mcp",cO=()=>{let e=process.env.STOPHY_MCP_URL??aO;try{return new URL(e)}catch{throw Error(`STOPHY_MCP_URL is not a valid URL: ${e}`)}},uO=()=>{let e=process.env.STOPHY_API_KEY?.trim();return e?{Authorization:`Bearer ${e}`}:{}},lO=async(e)=>{let t=new Ec({name:"stophy-mcp",version:Jc.version}),r=new Uc(e,{requestInit:{headers:uO()}});return await t.connect(r),t},dO=async()=>{let e=cO(),t;try{t=await lO(e)}catch(n){let o=n instanceof Error?n.message:String(n),s=/401|unauthorized/iu.test(o)?" Check STOPHY_API_KEY, or unset it to use the free endpoints only.":"";throw Error(`Could not connect to Stophy at ${e.origin}: ${o}.${s}`,{cause:n})}let r=new Vc({name:"stophy",version:Jc.version},{capabilities:{tools:{listChanged:!0}},instructions:t.getInstructions()});r.setRequestHandler(wa,(n)=>t.listTools(n.params)),r.setRequestHandler($n,(n)=>t.callTool(n.params)),t.setNotificationHandler(zn,()=>r.sendToolListChanged()),r.onclose=()=>{t.close()},await r.connect(new Bc)};dO().catch((e)=>{process.stderr.write(`${e instanceof Error?e.message:String(e)}
|
|
81
81
|
`),process.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stophy/mcp",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Give your agents the live web. One API to search the web, read what people say, and look up products, places, jobs and homes.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ads",
|
|
7
7
|
"ai-agent",
|