@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 +1 -1
- package/client.mjs +20 -4
- package/index.mjs +3 -3
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SEV MCP
|
|
2
2
|
|
|
3
|
-
Ask a financial research question.
|
|
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
|
|
122
|
-
if(
|
|
123
|
-
|
|
124
|
-
|
|
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.
|
|
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:
|
|
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:
|
|
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.
|
|
4
|
-
"
|
|
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",
|