@etsquare/sev-mcp 0.1.2 → 0.1.3

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.
Files changed (3) hide show
  1. package/client.mjs +20 -4
  2. package/index.mjs +1 -1
  3. package/package.json +1 -1
package/client.mjs CHANGED
@@ -68,6 +68,7 @@ function publicFailure(value, status, request) {
68
68
  }
69
69
 
70
70
  export class SevClient {
71
+ #passageTail=Promise.resolve();
71
72
  constructor({baseURL=process.env.SEV_BASE_URL||'https://etsquare.ai', apiKey=process.env.SEV_API_KEY,
72
73
  termsVersion=process.env.SEV_ACCEPT_TERMS_VERSION, fetchImpl=globalThis.fetch, timeout=20000}={}) {
73
74
  const url=new URL(baseURL);
@@ -118,9 +119,24 @@ export class SevClient {
118
119
  }
119
120
  async passage(id,signal){
120
121
  if(!/^[a-f0-9]{32}$/i.test(id))throw new ApiError('invalid_passage_id','Use the passage_id returned by discovery.',400);
121
- const result=await this.request('/v1/sec/passages/'+encodeURIComponent(id),undefined,signal);
122
- if(typeof result.passage_id!=='string'||result.passage_id.toUpperCase()!==id.toUpperCase()||typeof result.text!=='string'||!Array.isArray(result.adjacent_passages))
123
- throw new ApiError('invalid_response','SEV returned an invalid source response.');
124
- return result;
122
+ const cancelled=()=>new ApiError('request_cancelled','Stopped waiting. Work already submitted may continue on the server.');
123
+ if(signal?.aborted)throw cancelled();
124
+ let onAbort;
125
+ const cancellation=signal?new Promise((_,reject)=>{
126
+ onAbort=()=>reject(cancelled());signal.addEventListener('abort',onAbort,{once:true});
127
+ }):null;
128
+ const run=this.#passageTail.then(async()=>{
129
+ // Once sent, request() owns cancellation and starts its existing timeout.
130
+ if(onAbort)signal.removeEventListener('abort',onAbort);
131
+ if(signal?.aborted)throw cancelled();
132
+ const result=await this.request('/v1/sec/passages/'+encodeURIComponent(id),undefined,signal);
133
+ if(typeof result.passage_id!=='string'||result.passage_id.toUpperCase()!==id.toUpperCase()||typeof result.text!=='string'||!Array.isArray(result.adjacent_passages))
134
+ throw new ApiError('invalid_response','SEV returned an invalid source response.');
135
+ return result;
136
+ });
137
+ // Absorb failure only on the queue tail; each caller still gets its own error.
138
+ this.#passageTail=run.then(()=>undefined,()=>undefined);
139
+ try{return await (cancellation?Promise.race([run,cancellation]):run);}
140
+ finally{if(onAbort)signal.removeEventListener('abort',onAbort);}
125
141
  }
126
142
  }
package/index.mjs CHANGED
@@ -19,7 +19,7 @@ const source=z.object({passage_id:z.string().regex(/^[A-Fa-f0-9]{32}$/)}).strict
19
19
  const text=value=>({content:[{type:'text',text:JSON.stringify(value)}],structuredContent:value});
20
20
 
21
21
  export function createServer(client=new SevClient()) {
22
- const server=new McpServer({name:'sev',version:'0.1.2'},{instructions:'SEV finds companies and original SEC passages worth investigating. Rankings indicate research relevance, not investment merit or proof of impact. Follow original sources. Do not automatically repeat a failed or uncertain discovery; it may already have used allowance. Use get_sec_passage for full text and adjacent context.'});
22
+ const server=new McpServer({name:'sev',version:'0.1.3'},{instructions:'SEV finds companies and original SEC passages worth investigating. Rankings indicate research relevance, not investment merit or proof of impact. Follow original sources. Do not automatically repeat a failed or uncertain discovery; it may already have used allowance. Use get_sec_passage for full text and adjacent context.'});
23
23
  const call=operation=>async(input,extra)=>{
24
24
  try{return text(await operation(input,extra.signal));}
25
25
  catch(error){const known=error instanceof ApiError;return {...text({status:'error',error:{code:known?error.code:'client_error',message:known?error.message:'The SEV client could not complete the request.'}}),isError:true};}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsquare/sev-mcp",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "SEV company discovery and original SEC passage access over hosted REST.",
5
5
  "type": "module",
6
6
  "license": "MIT",