@etsquare/mcp-server-sec 0.6.3 → 0.7.1

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.
@@ -61,6 +61,21 @@ interface CompanyResearchApiInput {
61
61
  peers?: string[];
62
62
  n_periods?: number;
63
63
  }
64
+ /** Ticker cohort resolver request. */
65
+ interface ResolveTickerCohortApiInput {
66
+ question: string;
67
+ profile_code?: string;
68
+ boost_anchor_terms?: string[];
69
+ boost_topic_terms?: string[];
70
+ boost_negative_terms?: string[];
71
+ boost_positive_seeds?: string[];
72
+ boost_negative_seeds?: string[];
73
+ output_limit?: number;
74
+ semantic_mode?: 'auto' | 'off' | 'on';
75
+ grounding_context?: Record<string, unknown>;
76
+ ticker_cohort_candidate?: Record<string, unknown>;
77
+ response_mode?: 'full' | 'compact';
78
+ }
64
79
  /** Server-side KPI query with metric filtering. */
65
80
  interface QueryKpisApiInput {
66
81
  select?: string[];
@@ -105,6 +120,7 @@ export declare class ETSquareClient {
105
120
  getEarningsActuals(input: EarningsActualsApiInput): Promise<Record<string, unknown>>;
106
121
  getKpiExtractions(input: KpiExtractionsApiInput): Promise<Record<string, unknown>>;
107
122
  getCompanyResearch(input: CompanyResearchApiInput): Promise<Record<string, unknown>>;
123
+ resolveTickerCohort(input: ResolveTickerCohortApiInput): Promise<Record<string, unknown>>;
108
124
  queryKpis(input: QueryKpisApiInput): Promise<Record<string, unknown>>;
109
125
  discoverMetrics(input: DiscoverMetricsApiInput): Promise<Record<string, unknown>>;
110
126
  getChunk(input: GetChunkInput): Promise<Record<string, unknown>>;
@@ -176,6 +176,37 @@ export class ETSquareClient {
176
176
  body: JSON.stringify(body),
177
177
  });
178
178
  }
179
+ async resolveTickerCohort(input) {
180
+ const body = {
181
+ question: input.question,
182
+ semantic_mode: input.semantic_mode || 'auto',
183
+ };
184
+ if (input.profile_code)
185
+ body.profile_code = input.profile_code;
186
+ if (input.boost_anchor_terms && input.boost_anchor_terms.length > 0)
187
+ body.boost_anchor_terms = input.boost_anchor_terms;
188
+ if (input.boost_topic_terms && input.boost_topic_terms.length > 0)
189
+ body.boost_topic_terms = input.boost_topic_terms;
190
+ if (input.boost_negative_terms && input.boost_negative_terms.length > 0)
191
+ body.boost_negative_terms = input.boost_negative_terms;
192
+ if (input.boost_positive_seeds && input.boost_positive_seeds.length > 0)
193
+ body.boost_positive_seeds = input.boost_positive_seeds;
194
+ if (input.boost_negative_seeds && input.boost_negative_seeds.length > 0)
195
+ body.boost_negative_seeds = input.boost_negative_seeds;
196
+ if (input.output_limit !== undefined)
197
+ body.output_limit = input.output_limit;
198
+ if (input.grounding_context)
199
+ body.grounding_context = input.grounding_context;
200
+ if (input.ticker_cohort_candidate)
201
+ body.ticker_cohort_candidate = input.ticker_cohort_candidate;
202
+ if (input.response_mode)
203
+ body.response_mode = input.response_mode;
204
+ return this.request('/api/v1/cohort/resolve', {
205
+ method: 'POST',
206
+ headers: this.headers,
207
+ body: JSON.stringify(body),
208
+ });
209
+ }
179
210
  async queryKpis(input) {
180
211
  const body = {
181
212
  limit: input.limit || 50,
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * @etsquare/mcp-server-sec v0.6.0
3
+ * @etsquare/mcp-server-sec v0.7.0
4
4
  * MCP server for SEC Intelligence: search SEC filings,
5
5
  * resolve company tickers, execute financial metrics templates,
6
6
  * compare companies, and access weekly briefs.
@@ -57,7 +57,7 @@ if (!apiKey) {
57
57
  process.exit(1);
58
58
  }
59
59
  const client = new ETSquareClient({ baseUrl, apiKey });
60
- log('info', `ETSquare MCP Server v0.6.0 starting with backend: ${baseUrl}`);
60
+ log('info', `ETSquare MCP Server v0.7.0 starting with backend: ${baseUrl}`);
61
61
  // ─── Item Code Labels ───────────────────────────────────────────────────────
62
62
  const ITEM_CODE_LABELS = {
63
63
  // 10-K
@@ -358,7 +358,7 @@ function buildMarkdownTable(colNames, rows, maxRows = 20) {
358
358
  // ─── MCP Server ─────────────────────────────────────────────────────────────
359
359
  const server = new McpServer({
360
360
  name: 'etsquare-mcp-sec',
361
- version: '0.6.0',
361
+ version: '0.7.0',
362
362
  });
363
363
  const CITATION_POLICY = 'Citation policy (required): When `cite: true` appears in the response, you MUST include ' +
364
364
  'the sec_url for every filing referenced in the answer. Cite each URL inline with its claim.';
@@ -372,9 +372,7 @@ server.registerTool = ((name, config, handler) => {
372
372
  // ─── Tool 1: Company Lookup ─────────────────────────────────────────────────
373
373
  server.registerTool('etsquare_lookup_company', {
374
374
  title: 'Look Up Company Ticker',
375
- description: 'Resolve a company name or partial ticker to its official SEC ticker symbol and CIK number. ' +
376
- 'Call this when a user mentions a company by name (e.g., "Apple" -> AAPL, "Texas Roadhouse" -> TXRH). ' +
377
- 'Returns ticker, company name, CIK, and SIC industry code.',
375
+ description: 'Resolve company name to ticker/CIK. Call before other tools when user gives a name, not a ticker.',
378
376
  inputSchema: {
379
377
  query: z.string().min(2).describe('Company name or partial ticker to look up (e.g., "Apple", "Texas Road", "NVDA")'),
380
378
  limit: z.number().min(1).max(10).default(5).describe('Max results to return'),
@@ -412,20 +410,82 @@ server.registerTool('etsquare_lookup_company', {
412
410
  };
413
411
  }
414
412
  });
415
- // ─── Tool 2: SEC Filing Search ──────────────────────────────────────────────
413
+ // ─── Tool 2: Resolve Ticker Cohort ──────────────────────────────────────────
414
+ server.registerTool('etsquare_resolve_ticker_cohort', {
415
+ title: 'Resolve Ticker Cohort',
416
+ description: 'Resolve a natural-language question into a ranked ticker cohort using corpus-grounded terms. ' +
417
+ 'Use this before precision search for INDUSTRY/MACRO workflows, then pass selected tickers to etsquare_search with scope_lock=COMPANY.',
418
+ inputSchema: {
419
+ question: z.string().min(3).max(500)
420
+ .describe('Natural-language cohort question (e.g., "public SaaS companies discussing AI pricing power").'),
421
+ profile_code: z.string().min(2).max(80).optional()
422
+ .describe('Optional curated profile code override.'),
423
+ boost_anchor_terms: z.array(z.string()).max(5).optional()
424
+ .describe('WHO anchor terms (industry/exposure/entity class).'),
425
+ boost_topic_terms: z.array(z.string()).max(5).optional()
426
+ .describe('WHAT topic terms (KPI/theme/impact).'),
427
+ boost_negative_terms: z.array(z.string()).max(5).optional()
428
+ .describe('Negative terms to suppress confusable cohorts.'),
429
+ boost_positive_seeds: z.array(z.string().min(1).max(10)).max(5).optional()
430
+ .describe('Manual positive seed tickers (MCP/manual only).'),
431
+ boost_negative_seeds: z.array(z.string().min(1).max(10)).max(5).optional()
432
+ .describe('Manual negative seed tickers (MCP/manual only).'),
433
+ output_limit: z.number().int().min(1).max(50).optional()
434
+ .describe('Output ticker count override.'),
435
+ semantic_mode: z.enum(['auto', 'off', 'on']).default('auto')
436
+ .describe('Semantic embedding mode for resolver matching.'),
437
+ response_mode: z.enum(['full', 'compact']).default('full')
438
+ .describe('Response verbosity. Use "compact" for a consumer-focused payload and "full" for trace-rich output.'),
439
+ grounding_context: z.record(z.unknown()).optional()
440
+ .describe('Optional pre-computed grounding context from upstream workflow.'),
441
+ ticker_cohort_candidate: z.record(z.unknown()).optional()
442
+ .describe('Workflow candidate payload translated into resolver fields before resolution.'),
443
+ },
444
+ }, async (input) => {
445
+ if (containsGuardrailBypass(input))
446
+ return guardrailViolationResponse();
447
+ try {
448
+ log('debug', 'Resolving ticker cohort', {
449
+ question: input.question,
450
+ profile_code: input.profile_code,
451
+ output_limit: input.output_limit,
452
+ semantic_mode: input.semantic_mode,
453
+ });
454
+ const result = await client.resolveTickerCohort({
455
+ question: input.question,
456
+ profile_code: input.profile_code,
457
+ boost_anchor_terms: input.boost_anchor_terms,
458
+ boost_topic_terms: input.boost_topic_terms,
459
+ boost_negative_terms: input.boost_negative_terms,
460
+ boost_positive_seeds: input.boost_positive_seeds?.map((t) => t.trim().toUpperCase()),
461
+ boost_negative_seeds: input.boost_negative_seeds?.map((t) => t.trim().toUpperCase()),
462
+ output_limit: input.output_limit,
463
+ semantic_mode: input.semantic_mode,
464
+ response_mode: input.response_mode,
465
+ grounding_context: input.grounding_context,
466
+ ticker_cohort_candidate: input.ticker_cohort_candidate,
467
+ });
468
+ log('info', 'Ticker cohort resolved', {
469
+ cohort_code: result?.cohort_code,
470
+ profile_match_mode: result?.profile_match_mode,
471
+ ticker_count: Array.isArray(result?.tickers) ? result.tickers.length : 0,
472
+ });
473
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
474
+ }
475
+ catch (error) {
476
+ log('error', 'Ticker cohort resolve failed', { error: error instanceof Error ? error.message : error });
477
+ return {
478
+ content: [{ type: 'text', text: `Ticker cohort resolution failed: ${error instanceof Error ? error.message : 'Unknown error'}` }],
479
+ isError: true,
480
+ };
481
+ }
482
+ });
483
+ // ─── Tool 3: SEC Filing Search ──────────────────────────────────────────────
416
484
  server.registerTool('etsquare_search', {
417
485
  title: 'Search SEC Filings',
418
- description: 'Search 4.0M+ SEC filing sections (10-K, 10-Q, 8-K) with hybrid retrieval. ' +
419
- 'Returns verbatim filing text with citations best for qualitative research.\n\n' +
420
- 'Execution contract (required):\n' +
421
- '- mode_lock: NARRATIVE (recommended) | HYBRID\n' +
422
- '- scope_lock: COMPANY | INDUSTRY | MACRO\n\n' +
423
- 'COMPANY + tickers = precision. INDUSTRY + sector = breadth. ' +
424
- 'When precision matters, supply tickers.\n\n' +
425
- 'For financial statements, use etsquare_financial_statements. ' +
426
- 'For metrics/comparisons, use etsquare_discover_metrics + etsquare_execute_metrics.\n\n' +
427
- 'Results include filing text, chunk_id, accession number, and SEC URL.\n' +
428
- 'Set response_format="structured" for typed JSON.',
486
+ description: 'Search SEC filing text (10-K, 10-Q, 8-K). Returns verbatim excerpts with SEC URL citations.\n\n' +
487
+ 'COMPANY + tickers = precision. INDUSTRY + sector = breadth. When precision matters, supply tickers.\n\n' +
488
+ 'For financial statements use etsquare_financial_statements. For metrics use etsquare_discover_metrics.',
429
489
  inputSchema: {
430
490
  query: z.string().min(3).describe('What to search for in SEC filings (e.g., "customer concentration risk", "Show NVDA revenue trend")'),
431
491
  mode_lock: z.enum(['NARRATIVE', 'HYBRID']).describe('NARRATIVE for text search, HYBRID for text + any available metrics'),
@@ -613,12 +673,8 @@ server.registerTool('etsquare_search', {
613
673
  // ─── Tool 3: Execute Metrics ────────────────────────────────────────────────
614
674
  server.registerTool('etsquare_financial_statements', {
615
675
  title: 'Get Financial Statements',
616
- description: 'Get canonical income statement, balance sheet, or cash flow statement for a company. ' +
617
- 'Assembles structured line items from XBRL facts with concept precedence and provenance.\n\n' +
618
- 'Each line item includes the selected XBRL concept, priority rank, and unit for auditability.\n\n' +
619
- 'Coverage: ~5,100 tickers for income statement and cash flow. ' +
620
- 'Balance sheet coverage is limited for some companies pending XBRL pipeline enhancement.\n\n' +
621
- 'For custom financial queries or peer comparisons, use etsquare_discover_metrics + etsquare_execute_metrics instead.',
676
+ description: 'Canonical income statement, balance sheet, or cash flow from XBRL. ~5,100 tickers. ' +
677
+ 'For custom queries or peer comparisons, use etsquare_discover_metrics instead.',
622
678
  inputSchema: {
623
679
  ticker: z.string().min(1).max(10).describe('Company ticker (e.g., "AAPL", "NVDA")'),
624
680
  statement_type: z.enum(['income_statement', 'balance_sheet', 'cash_flow'])
@@ -715,11 +771,7 @@ server.registerTool('etsquare_financial_statements', {
715
771
  });
716
772
  server.registerTool('etsquare_insider_trades', {
717
773
  title: 'Insider Trading Activity',
718
- description: 'Get insider buying and selling activity for a company from SEC Form 3/4/5 filings. ' +
719
- 'Shows officer/director stock purchases, sales, option exercises, and tax withholdings.\n\n' +
720
- 'Data is sourced directly from SEC EDGAR ownership filings, filed within 2 business days of each transaction.\n\n' +
721
- 'Summary includes open-market buy/sell counts, net shares, and total values. ' +
722
- 'Derivative transactions (options, RSUs) are separated from open-market trades.',
774
+ description: 'Insider buy/sell activity from SEC Form 3/4/5. Open-market trades + derivatives (options, RSUs).',
723
775
  inputSchema: {
724
776
  ticker: z.string().min(1).max(10).describe('Company ticker (e.g., "AAPL", "NVDA")'),
725
777
  days_back: z.number().min(1).max(730).default(90)
@@ -797,12 +849,7 @@ server.registerTool('etsquare_insider_trades', {
797
849
  });
798
850
  server.registerTool('etsquare_institutional_holdings', {
799
851
  title: 'Institutional Ownership (13F)',
800
- description: 'Get institutional investor holdings for a company from SEC 13F filings. ' +
801
- 'Shows tracked managers holding the stock, their position sizes, and portfolio concentration.\n\n' +
802
- 'Data is from tracked institutional managers (top filers by AUM). ' +
803
- 'Coverage is partial — not all institutional holders are tracked. ' +
804
- 'Multiple rows per manager may appear due to sub-manager reporting. ' +
805
- 'Source: SEC EDGAR 13F-HR filings, filed quarterly.',
852
+ description: 'Institutional holdings from SEC 13F filings. Position sizes, portfolio concentration, quarterly changes.',
806
853
  inputSchema: {
807
854
  ticker: z.string().min(1).max(10).describe('Company ticker (e.g., "NVDA", "AAPL")'),
808
855
  quarters: z.number().min(1).max(8).default(2)
@@ -893,14 +940,8 @@ server.registerTool('etsquare_institutional_holdings', {
893
940
  });
894
941
  server.registerTool('etsquare_earnings_actuals', {
895
942
  title: 'Earnings Actuals & Guidance',
896
- description: 'Get issuer-reported earnings actuals and forward guidance for a company from SEC 8-K filings. ' +
897
- 'Extracts revenue, EPS (basic/diluted), and net income from Item 2.02 press releases.\n\n' +
898
- 'Values are deterministically extracted from exhibit press releases (EX-99.1) attached to 8-K filings. ' +
899
- 'Only explicit issuer-reported values are included — no analyst estimates or consensus.\n\n' +
900
- 'Guidance shows forward-looking ranges (low/high) when the issuer provides them.\n\n' +
901
- 'Coverage: ~1,900 tickers, most recent 1-2 quarters (Dec 2025 onward). ' +
902
- 'Historical depth is expanding — some tickers may have fewer quarters than requested.\n\n' +
903
- 'Source: SEC EDGAR 8-K Item 2.02 filings with attached press releases.',
943
+ description: 'Issuer-reported earnings actuals + guidance from 8-K press releases. Revenue, EPS, net income. ' +
944
+ 'No analyst estimates SEC filings only. ~1,900 tickers.',
904
945
  inputSchema: {
905
946
  ticker: z.string().min(1).max(10).describe('Company ticker (e.g., "AAPL", "NVDA")'),
906
947
  quarters: z.number().min(1).max(20).default(4)
@@ -1015,14 +1056,8 @@ server.registerTool('etsquare_earnings_actuals', {
1015
1056
  });
1016
1057
  server.registerTool('etsquare_kpi_extractions', {
1017
1058
  title: 'Get KPI Extractions (Full Detail + Source Chunk IDs)',
1018
- description: 'Returns full KPI extraction detail including source_chunk_ids for provenance.\n\n' +
1019
- 'USE THIS TOOL for the provenance chain:\n' +
1020
- ' 1. etsquare_query_kpis -> find interesting metric + extraction_id\n' +
1021
- ' 2. etsquare_kpi_extractions(ticker, sector) -> get source_chunk_ids array\n' +
1022
- ' 3. etsquare_get_chunk(chunk_id) -> read actual filing paragraph\n\n' +
1023
- 'Also use when you need the complete kpi_json payload for deep analysis of a single ticker.\n\n' +
1024
- 'RETURNS: extraction_id, kpi_json (full), source_chunk_ids (array of chunk IDs), notes, extraction_model.\n\n' +
1025
- 'For compact tabular queries across many tickers, prefer etsquare_query_kpis instead.',
1059
+ description: 'Full KPI extraction with source_chunk_ids for provenance. Use etsquare_get_chunk to read the source filing text. ' +
1060
+ 'For tabular queries across many tickers, prefer etsquare_query_kpis.',
1026
1061
  inputSchema: {
1027
1062
  ticker: z.string().min(1).max(10).optional()
1028
1063
  .describe('Single ticker filter (e.g., "TXRH")'),
@@ -1137,20 +1172,9 @@ server.registerTool('etsquare_kpi_extractions', {
1137
1172
  });
1138
1173
  server.registerTool('etsquare_query_kpis', {
1139
1174
  title: 'Query KPI Extractions (Compare, Screen, Catalog)',
1140
- description: 'Server-side filtered KPI query. Returns compact tabular data with values + YoY changes + summary stats.\n\n' +
1141
- 'WORKFLOW: action="list_metrics" -> discover metrics -> action="query" with select/filter\n\n' +
1142
- 'EXAMPLES:\n' +
1143
- ' Peer comp: select="net_interest_margin,cet1_ratio,return_on_tangible_common_equity", sector="banks", period="FY"\n' +
1144
- ' Screen: filter="net_interest_margin>3;cet1_ratio>11", sector="banks", period="FY"\n' +
1145
- ' SaaS: select="arr,net_dollar_retention,free_cash_flow_margin", sector="saas", sort_by="arr"\n' +
1146
- ' Catalog: action="list_metrics", sector="banks"\n' +
1147
- ' Time series: select="net_interest_margin", tickers="JPM", limit=20\n\n' +
1148
- 'OUTPUT: Each row includes ticker, company_name, extraction_id, metric_value, metric_chg (YoY), metric_unit.\n' +
1149
- ' Summary stats (min/max/avg/median) per metric included.\n\n' +
1150
- 'PROVENANCE CHAIN: Results include extraction_id. To read source MD&A text:\n' +
1151
- ' 1. etsquare_query_kpis -> get extraction_id\n' +
1152
- ' 2. etsquare_kpi_extractions(ticker) -> get source_chunk_ids\n' +
1153
- ' 3. etsquare_get_chunk(chunk_id) -> read actual filing paragraph\n' +
1175
+ description: 'Tabular KPI query with select/filter/sort. Returns values + YoY changes + summary stats.\n\n' +
1176
+ 'action="list_metrics" to discover available metrics for a sector, then action="query" with select/filter.\n\n' +
1177
+ 'Examples: select="arr,net_dollar_retention", sector="saas" | filter="net_interest_margin>3", sector="banks"\n' +
1154
1178
  'Use when a number looks surprising or needs management context.',
1155
1179
  inputSchema: {
1156
1180
  select: z.string().optional()
@@ -1316,12 +1340,8 @@ server.registerTool('etsquare_query_kpis', {
1316
1340
  });
1317
1341
  server.registerTool('etsquare_execute_metrics', {
1318
1342
  title: 'Execute Financial Metrics Query',
1319
- description: 'Execute an XBRL metrics template by template_id to get structured financial data ' +
1320
- '(numbers, ratios, time series). Returns tabular rows with columns like revenue, margins, EPS, etc.\n\n' +
1321
- 'Common bind_params: p_tickers (comma-separated tickers), p_ticker (single ticker), p_sic_code (industry), ' +
1322
- 'p_start_year / p_end_year (time range, e.g., 2023-2025).\n\n' +
1323
- 'Use the tickers array to pass multiple companies — automatically joins as p_tickers comma-separated string.\n\n' +
1324
- 'Set response_format="structured" for typed JSON with column metadata, visualization hints, and summary stats.',
1343
+ description: 'Execute XBRL metrics template by template_id. Returns tabular financial data. ' +
1344
+ 'Use tickers array for multi-company. Common params: p_ticker, p_tickers, p_sic_code, p_start_year, p_end_year.',
1325
1345
  inputSchema: {
1326
1346
  template_id: z.string().min(10).describe('Template ID for metrics execution'),
1327
1347
  bind_params: z.record(z.unknown()).optional().describe('Template parameters as key-value pairs'),
@@ -1469,14 +1489,9 @@ server.registerTool('etsquare_execute_metrics', {
1469
1489
  // ─── Tool 4: Discover Metrics Templates ─────────────────────────────────────
1470
1490
  server.registerTool('etsquare_discover_metrics', {
1471
1491
  title: 'Discover Financial Metrics Templates',
1472
- description: 'Find available XBRL metrics templates by business question. ' +
1473
- 'Returns template IDs and metadata use the template_id with etsquare_execute_metrics.\n\n' +
1474
- 'Use this only for structured metrics such as revenue, gross margin, operating margin, EPS, debt, liquidity, or cash flow.\n\n' +
1475
- 'Do not use this for narrative KPI questions like same-store sales, comparable sales, traffic, guest count, average check, or AUV. ' +
1476
- 'For those, use etsquare_search in NARRATIVE mode instead.\n\n' +
1477
- 'Example: "revenue trend by quarter" → returns matching templates with their required bind_params.\n\n' +
1478
- 'Workflow: discover_metrics → pick template_id → execute_metrics with bind_params.\n\n' +
1479
- 'Set response_format="structured" for JSON with similarity scores and visualization hints.',
1492
+ description: 'Find XBRL metrics templates by question. Returns template_id → use with etsquare_execute_metrics.\n\n' +
1493
+ 'For XBRL metrics (revenue, margins, EPS, debt, cash flow) only. ' +
1494
+ 'For narrative KPIs (comps, traffic, ARR), use etsquare_search or etsquare_query_kpis instead.',
1480
1495
  inputSchema: {
1481
1496
  question: z.string().min(3).describe('Structured metrics question (e.g., "revenue trend by quarter", "gross margin trend", "EPS trend")'),
1482
1497
  scenario: z.enum(['snapshot', 'trends', 'peer_benchmark']).optional().describe('Filter by scenario type'),
@@ -1586,9 +1601,7 @@ server.registerTool('etsquare_discover_metrics', {
1586
1601
  // ─── Tool 5: Get Full Chunk Text ────────────────────────────────────────────
1587
1602
  server.registerTool('etsquare_get_chunk', {
1588
1603
  title: 'Get Full Chunk Text',
1589
- description: 'Fetch the full text for a specific search result chunk. ' +
1590
- 'Use this when etsquare_search returns a truncated snippet and you need the complete chunk text. ' +
1591
- 'Requires both chunk_id and execution_id from a prior search result.',
1604
+ description: 'Fetch full chunk text when etsquare_search returned a truncated snippet.',
1592
1605
  inputSchema: {
1593
1606
  chunk_id: z.string().length(32).describe('Chunk ID from etsquare_search output'),
1594
1607
  execution_id: z.string().min(32).describe('Execution ID from the etsquare_search response header'),
@@ -1625,8 +1638,7 @@ server.registerTool('etsquare_get_chunk', {
1625
1638
  // ─── Tool 6: Get Chunk Context ──────────────────────────────────────────────
1626
1639
  server.registerTool('etsquare_get_chunk_context', {
1627
1640
  title: 'Get Chunk Context',
1628
- description: 'Fetch the highlighted chunk plus surrounding context from the same filing section. ' +
1629
- 'Use this when you need the paragraphs immediately before and after a search hit.',
1641
+ description: 'Fetch chunk with surrounding paragraphs from the same filing section.',
1630
1642
  inputSchema: {
1631
1643
  chunk_id: z.string().length(32).describe('Chunk ID from etsquare_search output'),
1632
1644
  neighbor_span: z.number().min(0).max(5).default(1).optional().describe('How many adjacent chunks to include before and after'),
@@ -1686,11 +1698,8 @@ server.registerTool('etsquare_get_chunk_context', {
1686
1698
  // ─── Tool 7: Compare Companies ──────────────────────────────────────────────
1687
1699
  server.registerTool('etsquare_compare', {
1688
1700
  title: 'Compare Companies in SEC Filings',
1689
- description: 'Compare 2-5 companies across SEC filings in a single call. ' +
1690
- 'Returns per-ticker results grouped for easy side-by-side analysis.\n\n' +
1691
- 'Resolve company names to tickers first with etsquare_lookup_company.\n\n' +
1692
- 'Use mode_lock=HYBRID to include both narrative text and structured metrics.\n\n' +
1693
- 'Always returns structured JSON (comparison results are inherently structured).',
1701
+ description: 'Compare 2-5 companies side-by-side across SEC filings. Returns per-ticker grouped results. ' +
1702
+ 'Use HYBRID mode for text + metrics together.',
1694
1703
  inputSchema: {
1695
1704
  tickers: z.array(z.string()).min(2).max(5)
1696
1705
  .describe('Company tickers to compare (2-5). Resolve names first with etsquare_lookup_company.'),
@@ -1790,10 +1799,7 @@ server.registerTool('etsquare_compare', {
1790
1799
  // ─── Tool 8: Weekly Brief ───────────────────────────────────────────────────
1791
1800
  server.registerTool('etsquare_weekly_brief', {
1792
1801
  title: 'Weekly SEC Filing Intelligence Brief',
1793
- description: 'Get the latest weekly SEC filing intelligence brief. ' +
1794
- 'Returns notable 8-K events, edge signals (unusual filings), and sector heatmap. ' +
1795
- 'Updated weekly. Great for market monitoring and identifying emerging risks.\n\n' +
1796
- 'Default response_format is "structured" (full JSON). Use "text" for readable summary.',
1802
+ description: 'Weekly SEC filing brief: notable 8-K events, edge signals, sector heatmap. Updated weekly.',
1797
1803
  inputSchema: {
1798
1804
  sections: z.array(z.enum(['notable', 'edge_signals', 'heatmap', 'methodology'])).optional()
1799
1805
  .describe('Filter to specific sections. Returns all if omitted.'),
@@ -1879,8 +1885,7 @@ server.registerTool('etsquare_weekly_brief', {
1879
1885
  // ─── Tool 9: Company Research ──────────────────────────────────────────────
1880
1886
  server.registerTool('etsquare_company_research', {
1881
1887
  title: 'Company Research Packet',
1882
- description: 'Returns a citation-grounded research packet for one company in a single call. ' +
1883
- 'Server-side orchestration assembles financials, earnings, narrative, ownership, and KPIs with SEC provenance.',
1888
+ description: 'Full research packet for one company: financials, earnings, narrative, ownership, KPIs. Single call.',
1884
1889
  inputSchema: {
1885
1890
  ticker: z.string().min(1).max(10)
1886
1891
  .describe('Company ticker (e.g., "AAPL", "NVDA"). Resolve names first with etsquare_lookup_company.'),
@@ -1930,4 +1935,4 @@ server.registerTool('etsquare_company_research', {
1930
1935
  // ─── Start Server ───────────────────────────────────────────────────────────
1931
1936
  const transport = new StdioServerTransport();
1932
1937
  await server.connect(transport);
1933
- log('info', 'ETSquare MCP Server v0.6.0 ready and listening on stdio (15 tools)');
1938
+ log('info', 'ETSquare MCP Server v0.7.0 ready and listening on stdio (16 tools)');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsquare/mcp-server-sec",
3
- "version": "0.6.3",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "description": "MCP server for Claude Desktop: search SEC filing sections, financial statements, insider trades, institutional ownership, earnings actuals, XBRL metrics, and company lookup.",
6
6
  "main": "dist/index.js",