@etsquare/sev-mcp 0.1.2 → 0.1.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # SEV MCP
2
2
 
3
- Ask a financial research question. Get relevant public companies and original SEC filing passages to investigate.
3
+ Ask a financial research question. In seconds, get a ranked shortlist of public companies, each with vetted original SEC filing passages and key reported financials: a few paragraphs per company instead of whole filings.
4
4
 
5
5
  SEV searches its supported SEC corpus and returns a ranked company shortlist with precise filing references. Your agent handles further analysis. Results are research leads; omissions and empty results are possible.
6
6
 
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,17 +19,17 @@ 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.4'},{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};}
26
26
  };
27
27
  server.registerTool('discover_sec_companies',{
28
- title:'Discover SEC companies',description:'Find relevant public companies and one to three original SEC passages per company for a research question. Searches the supported indexed corpus; omissions and zero results are possible. Optional explicit tickers OR SICs and an inclusive filing-date cutoff. No synthesis or investment recommendation.',
28
+ title:'Discover SEC companies',description:"Find public companies and evidence in indexed SEC 10-K and 10-Q filings. Use for industry-wide discovery, named-company research or peer comparisons.\n\nReturns ranked research leads with 1-3 passage previews per company, filing metadata and source links, not a synthesized answer. Inspect relevant originals with get_sec_passage before making factual or numerical claims; previews can omit key evidence and qualifications.\n\nWhen available, discovery includes consolidated financial context. Check each figure's own period, source and availability. Numeric conditions may be checked for supported measures, periods and scope; unknown or absent verdicts mean unverified. Returned companies are not guaranteed numerical matches. Figures do not establish causation.\n\nCoverage is bounded: max_companies is a ceiling; missing companies and empty results do not prove absence of evidence. tickers OR sic_codes restrict the universe. filed_since filters filing dates, not report periods. Exact period references may restrict filings; inspect reporting_period notices for fallback.\n\nEach successful request, including a valid empty result, consumes one research allowance unit. Run discoveries sequentially per account; concurrent requests may return account_busy. Do not automatically retry failed or uncertain requests.",
29
29
  inputSchema:discovery,annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:false,openWorldHint:true},
30
30
  },call((input,signal)=>client.discover(input,signal)));
31
31
  server.registerTool('get_sec_passage',{
32
- title:'Read discovered SEC passage',description:'Retrieve an original passage and available adjacent same-section context using a passage_id from discovery. Supporting source retrieval; does not consume a research allowance unit.',
32
+ title:'Read discovered SEC passage',description:"Read the full original SEC passage and available adjacent same-section context using a passage_id from discovery. Verify facts, amounts, dates, actual versus hypothetical disclosures, management explanations and qualifications before answering or citing. Context may omit referenced tables or other sections; do not infer missing facts or causation. No new discovery or model call; no research allowance unit consumed.",
33
33
  inputSchema:source,annotations:{readOnlyHint:true,destructiveHint:false,idempotentHint:true,openWorldHint:true},
34
34
  },call((input,signal)=>client.passage(input.passage_id,signal)));
35
35
  server.registerResource('sec-passage',new ResourceTemplate('sev://passages/{passage_id}',{list:undefined}),{mimeType:'application/json'},
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@etsquare/sev-mcp",
3
- "version": "0.1.2",
4
- "description": "SEV company discovery and original SEC passage access over hosted REST.",
3
+ "version": "0.1.4",
4
+ "mcpName": "io.github.ETSquareAI/sev",
5
+ "description": "Ask a research question in plain English and, in seconds, get a ranked shortlist of public companies, each with vetted original 10-K/10-Q passages and key reported financials: a few paragraphs per company instead of whole filings. Limit the search to tickers or SIC codes to pinpoint passages in specific companies' filings.",
5
6
  "type": "module",
6
7
  "license": "MIT",
7
8
  "engines": {
@@ -34,7 +35,13 @@
34
35
  "edgar",
35
36
  "company-discovery",
36
37
  "claude",
37
- "codex"
38
+ "codex",
39
+ "sec-filings",
40
+ "10-k",
41
+ "10-q",
42
+ "financial-research",
43
+ "company-research",
44
+ "mcp-server"
38
45
  ],
39
46
  "publishConfig": {
40
47
  "access": "public",