@cyanheads/secedgar-mcp-server 0.14.0 → 0.15.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.
Files changed (55) hide show
  1. package/Dockerfile +11 -3
  2. package/README.md +32 -4
  3. package/dist/index.js +12 -13
  4. package/dist/index.js.map +1 -1
  5. package/dist/mcp-server/prompts/definitions/company-analysis.prompt.d.ts.map +1 -1
  6. package/dist/mcp-server/prompts/definitions/company-analysis.prompt.js +9 -5
  7. package/dist/mcp-server/prompts/definitions/company-analysis.prompt.js.map +1 -1
  8. package/dist/mcp-server/resources/definitions/filing-types.resource.d.ts.map +1 -1
  9. package/dist/mcp-server/resources/definitions/filing-types.resource.js +6 -0
  10. package/dist/mcp-server/resources/definitions/filing-types.resource.js.map +1 -1
  11. package/dist/mcp-server/tools/definitions/company-search.tool.d.ts +3 -0
  12. package/dist/mcp-server/tools/definitions/company-search.tool.d.ts.map +1 -1
  13. package/dist/mcp-server/tools/definitions/company-search.tool.js +16 -1
  14. package/dist/mcp-server/tools/definitions/company-search.tool.js.map +1 -1
  15. package/dist/mcp-server/tools/definitions/dataframe-query.tool.d.ts +3 -0
  16. package/dist/mcp-server/tools/definitions/dataframe-query.tool.d.ts.map +1 -1
  17. package/dist/mcp-server/tools/definitions/dataframe-query.tool.js +21 -2
  18. package/dist/mcp-server/tools/definitions/dataframe-query.tool.js.map +1 -1
  19. package/dist/mcp-server/tools/definitions/get-beneficial-owners.tool.d.ts +93 -0
  20. package/dist/mcp-server/tools/definitions/get-beneficial-owners.tool.d.ts.map +1 -0
  21. package/dist/mcp-server/tools/definitions/get-beneficial-owners.tool.js +457 -0
  22. package/dist/mcp-server/tools/definitions/get-beneficial-owners.tool.js.map +1 -0
  23. package/dist/mcp-server/tools/definitions/get-filing.tool.d.ts +6 -1
  24. package/dist/mcp-server/tools/definitions/get-filing.tool.d.ts.map +1 -1
  25. package/dist/mcp-server/tools/definitions/get-filing.tool.js +23 -1
  26. package/dist/mcp-server/tools/definitions/get-filing.tool.js.map +1 -1
  27. package/dist/mcp-server/tools/definitions/get-fund-holdings.tool.d.ts +88 -0
  28. package/dist/mcp-server/tools/definitions/get-fund-holdings.tool.d.ts.map +1 -0
  29. package/dist/mcp-server/tools/definitions/get-fund-holdings.tool.js +674 -0
  30. package/dist/mcp-server/tools/definitions/get-fund-holdings.tool.js.map +1 -0
  31. package/dist/mcp-server/tools/definitions/get-insider-transactions.tool.d.ts.map +1 -1
  32. package/dist/mcp-server/tools/definitions/get-insider-transactions.tool.js +6 -0
  33. package/dist/mcp-server/tools/definitions/get-insider-transactions.tool.js.map +1 -1
  34. package/dist/mcp-server/tools/definitions/search-filings.tool.d.ts +10 -13
  35. package/dist/mcp-server/tools/definitions/search-filings.tool.d.ts.map +1 -1
  36. package/dist/mcp-server/tools/definitions/search-filings.tool.js +292 -118
  37. package/dist/mcp-server/tools/definitions/search-filings.tool.js.map +1 -1
  38. package/dist/services/edgar/beneficial-ownership-parser.d.ts +70 -0
  39. package/dist/services/edgar/beneficial-ownership-parser.d.ts.map +1 -0
  40. package/dist/services/edgar/beneficial-ownership-parser.js +157 -0
  41. package/dist/services/edgar/beneficial-ownership-parser.js.map +1 -0
  42. package/dist/services/edgar/edgar-api-service.d.ts +78 -0
  43. package/dist/services/edgar/edgar-api-service.d.ts.map +1 -1
  44. package/dist/services/edgar/edgar-api-service.js +140 -1
  45. package/dist/services/edgar/edgar-api-service.js.map +1 -1
  46. package/dist/services/edgar/nport-parser.d.ts +68 -0
  47. package/dist/services/edgar/nport-parser.d.ts.map +1 -0
  48. package/dist/services/edgar/nport-parser.js +102 -0
  49. package/dist/services/edgar/nport-parser.js.map +1 -0
  50. package/dist/services/edgar/xml-nodes.d.ts +31 -0
  51. package/dist/services/edgar/xml-nodes.d.ts.map +1 -0
  52. package/dist/services/edgar/xml-nodes.js +74 -0
  53. package/dist/services/edgar/xml-nodes.js.map +1 -0
  54. package/package.json +11 -11
  55. package/server.json +3 -3
@@ -0,0 +1,457 @@
1
+ /**
2
+ * @fileoverview Blockholder ownership for one issuer, parsed from the structured
3
+ * SCHEDULE 13D / SCHEDULE 13G XML that SEC has required since 2024-12-18. Completes the
4
+ * ownership triangle alongside secedgar_get_insider_transactions (Form 4 officers and
5
+ * directors) and secedgar_get_institutional_holdings (13F portfolios): this tool covers the
6
+ * 5%-and-over stakes, activist and passive. Discovery runs off the issuer's own submissions
7
+ * feed — SEC cross-lists a 13D/G under every CIK party to it, so the issuer's history
8
+ * already carries the filings made about it and the archive document is reachable on the
9
+ * issuer's own path.
10
+ * @module mcp-server/tools/definitions/get-beneficial-owners
11
+ */
12
+ import { tool, z } from '@cyanheads/mcp-ts-core';
13
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
14
+ import { getCanvasBridge, toDatasetField } from '../../../services/canvas-bridge/canvas-bridge.js';
15
+ import { formNameToSchedule, parseBeneficialOwnershipXml, } from '../../../services/edgar/beneficial-ownership-parser.js';
16
+ import { getEdgarApiService, rawDocumentName } from '../../../services/edgar/edgar-api-service.js';
17
+ /**
18
+ * First filing date on which every beneficial-ownership filing arrived in the structured
19
+ * format. The legacy `SC 13D` / `SC 13G` names stop dead here: EDGAR full-text search counts
20
+ * 37 legacy filings on 2024-12-17 and zero on 2024-12-18, against 44 structured ones the
21
+ * same day. Filings before it are text or HTML documents with no XML to parse.
22
+ */
23
+ const STRUCTURED_FROM = '2024-12-18';
24
+ /** Legacy form names that carry the same disclosure with no parseable XML. */
25
+ const LEGACY_FORMS = ['SC 13D', 'SC 13D/A', 'SC 13G', 'SC 13G/A'];
26
+ /**
27
+ * Character ceiling on the Item 4 purpose-of-transaction prose. It is free text and runs to
28
+ * several pages on a control filing, which would put one filing's narrative ahead of every
29
+ * other filing's ownership data in the caller's context. The full text stays one
30
+ * secedgar_get_filing call away on the accession number each row carries.
31
+ */
32
+ const PURPOSE_MAX_CHARS = 1200;
33
+ /** Character ceiling on a reporting person's cover-page footnote — same reasoning, per person. */
34
+ const NOTES_MAX_CHARS = 240;
35
+ /** Trim free text to a ceiling, reporting whether anything was cut. */
36
+ function clip(text, max) {
37
+ if (text === undefined)
38
+ return { text: undefined, cut: false };
39
+ const collapsed = text.replace(/\s+/g, ' ').trim();
40
+ if (collapsed.length <= max)
41
+ return { text: collapsed, cut: false };
42
+ return { text: `${collapsed.slice(0, max)}…`, cut: true };
43
+ }
44
+ export const getBeneficialOwnersTool = tool('secedgar_get_beneficial_owners', {
45
+ title: 'Get Beneficial Owners',
46
+ description: "List the 5%-and-over beneficial owners of a public company, parsed from the structured SCHEDULE 13D and SCHEDULE 13G filings made about it. The input is the ISSUER — the company being held — which is the opposite direction from secedgar_get_institutional_holdings, where the input is the manager. 13D is the activist form and carries the filer's stated purpose of the transaction; 13G is the passive form and has no purpose field at all, which is the substantive difference between a stake that intends to influence control and one that does not. Every filing is returned with each reporting person listed separately, because voting power, dispositive power, and percent of class are reported per person even on a joint filing where several funds and their controlling principal report overlapping shares — summing those percentages double-counts the same position. Coverage starts at 2024-12-18, when SEC replaced the legacy SC 13D / SC 13G text filings with this XML format; earlier stakes are readable but not parseable, and the response reports how many of them the issuer has. The full parsed set is materialized as df_<id> when a canvas is available, one row per reporting person, so it joins against the insider and 13F dataframes on issuer CIK.",
47
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
48
+ errors: [
49
+ {
50
+ reason: 'issuer_not_found',
51
+ code: JsonRpcErrorCode.NotFound,
52
+ when: 'The issuer input does not resolve to a known EDGAR company',
53
+ recovery: 'Use secedgar_company_search to find the issuer ticker or 10-digit CIK.',
54
+ },
55
+ {
56
+ reason: 'ambiguous_issuer',
57
+ code: JsonRpcErrorCode.ValidationError,
58
+ when: 'The issuer name matches several EDGAR companies',
59
+ recovery: 'Retry with the ticker or the 10-digit CIK of the intended issuer from the matches list.',
60
+ },
61
+ {
62
+ reason: 'no_filings_found',
63
+ code: JsonRpcErrorCode.NotFound,
64
+ when: 'The issuer has no structured SCHEDULE 13D/13G filings matching the requested form kind',
65
+ recovery: 'Use secedgar_search_filings with forms ["SC 13D","SC 13G"] to reach the pre-2024-12-18 text filings, then read them with secedgar_get_filing.',
66
+ },
67
+ ],
68
+ input: z.object({
69
+ issuer: z
70
+ .string()
71
+ .trim()
72
+ .min(1, 'Issuer cannot be blank')
73
+ .describe('The company whose blockholders you want — a ticker ("AAPL"), a 10-digit CIK ("0000320193"), or a company name. This is the subject company of the schedule, not the investor filing it; passing an investment manager here returns the schedules filed about that manager, which is almost always empty.'),
74
+ form_kind: z
75
+ .enum(['all', '13D', '13G'])
76
+ .default('all')
77
+ .describe('Which schedule to return. "13D" is the activist form, filed by a holder that may seek to influence control and carrying a stated purpose of transaction. "13G" is the passive form, available to institutions and holders under 20% that certify no control intent. "all" (default) returns both, newest first.'),
78
+ include_amendments: z
79
+ .boolean()
80
+ .default(true)
81
+ .describe('Whether to include amendments (SCHEDULE 13D/A, SCHEDULE 13G/A). Amendments carry the current position and are how an ongoing stake is tracked, so they are included by default. Set false to see only filings that opened a new position.'),
82
+ limit: z
83
+ .number()
84
+ .int()
85
+ .min(1)
86
+ .max(20)
87
+ .default(10)
88
+ .describe('Number of filings to fetch and parse, newest first. Each filing is a separate document fetch, so this is the cost of the call as well as its depth. Default 10; a widely-held company can have dozens of blockholder filings a year.'),
89
+ }),
90
+ output: z.object({
91
+ issuer: z.string().describe('The issuer input, echoed.'),
92
+ issuer_cik: z.string().describe('CIK of the resolved issuer, zero-padded to 10 digits.'),
93
+ issuer_name: z.string().describe('EDGAR-conformed name of the resolved issuer.'),
94
+ form_kind: z
95
+ .enum(['all', '13D', '13G'])
96
+ .describe('The schedule filter applied — the requested value, or the default "all".'),
97
+ total_structured_filings: z
98
+ .number()
99
+ .describe("Structured SCHEDULE 13D/13G filings matching the form filter in the issuer's recent submissions window, before the limit. The population the returned filings are the newest slice of."),
100
+ filings_parsed: z
101
+ .number()
102
+ .describe('Filings actually fetched and parsed — total_structured_filings capped by limit.'),
103
+ structured_coverage_from: z
104
+ .string()
105
+ .describe('First filing date on which SEC required this XML format (YYYY-MM-DD). Blockholder filings before it exist but are not parseable into this schema.'),
106
+ legacy_filings_before_coverage: z
107
+ .number()
108
+ .describe("Legacy SC 13D / SC 13G filings in the issuer's recent submissions window — pre-2024-12-18 stakes this tool cannot parse. Reach them with secedgar_search_filings and read them with secedgar_get_filing. A floor, not a lifetime count: the submissions window holds roughly the last thousand filings of every type."),
109
+ filings: z
110
+ .array(z
111
+ .object({
112
+ form: z.string().describe('EDGAR form name, e.g. "SCHEDULE 13D" or "SCHEDULE 13G/A".'),
113
+ schedule: z
114
+ .enum(['13D', '13G'])
115
+ .describe('Which schedule this is — 13D activist, 13G passive.'),
116
+ is_amendment: z.boolean().describe('True when the form name carries the /A suffix.'),
117
+ amendment_number: z
118
+ .string()
119
+ .optional()
120
+ .describe('Amendment sequence from the cover page. Absent on an original filing.'),
121
+ accession_number: z
122
+ .string()
123
+ .describe('Accession number — pass to secedgar_get_filing for the full document.'),
124
+ filing_date: z.string().describe('Date the schedule was submitted (YYYY-MM-DD).'),
125
+ event_date: z
126
+ .string()
127
+ .optional()
128
+ .describe('Date of the event that required the filing (YYYY-MM-DD) — when the position actually crossed or changed, which precedes filing_date. Absent when the cover page omits it.'),
129
+ security_class: z
130
+ .string()
131
+ .optional()
132
+ .describe('Title of the class of securities the schedule covers. A multi-class issuer has a separate schedule per class, so percentages are of this class only.'),
133
+ cusips: z
134
+ .array(z.string())
135
+ .describe('CUSIPs of the subject class from the cover page. Empty when none listed.'),
136
+ purpose_of_transaction: z
137
+ .string()
138
+ .optional()
139
+ .describe('Item 4 purpose-of-transaction prose — what the holder says it intends. Present on 13D filings only; 13G has no such field, which is what makes it the passive form. Absent on an amendment that restates no purpose.'),
140
+ purpose_truncated: z
141
+ .boolean()
142
+ .describe('True when purpose_of_transaction was clipped to fit — read the full item with secedgar_get_filing on this accession number.'),
143
+ reporting_persons: z
144
+ .array(z
145
+ .object({
146
+ name: z.string().describe('Reporting person as named on the cover page.'),
147
+ cik: z
148
+ .string()
149
+ .optional()
150
+ .describe('Reporting person CIK, when the schedule carries one. SCHEDULE 13G never does — its cover page has no CIK field — so this is populated on 13D filings only.'),
151
+ citizenship: z
152
+ .string()
153
+ .optional()
154
+ .describe('SEC citizenship or place-of-organization code — a US state ("DE"), or an SEC country code ("X1" United States, "E9" Cayman Islands).'),
155
+ percent_of_class: z
156
+ .number()
157
+ .optional()
158
+ .describe('Percent of the class this person beneficially owns (0-100), as this person reports it. Per person, not per filing: joint filers report overlapping shares, so these do not sum to a group total.'),
159
+ aggregate_amount_owned: z
160
+ .number()
161
+ .optional()
162
+ .describe('Shares beneficially owned by this person. Absent when the person reports no amount, which happens on an exit amendment reporting a zero position.'),
163
+ sole_voting_power: z
164
+ .number()
165
+ .optional()
166
+ .describe('Shares this person alone may vote.'),
167
+ shared_voting_power: z
168
+ .number()
169
+ .optional()
170
+ .describe('Shares this person votes jointly with another party.'),
171
+ sole_dispositive_power: z
172
+ .number()
173
+ .optional()
174
+ .describe('Shares this person alone may sell or transfer.'),
175
+ shared_dispositive_power: z
176
+ .number()
177
+ .optional()
178
+ .describe('Shares this person may sell or transfer jointly with another party.'),
179
+ person_types: z
180
+ .array(z.string())
181
+ .describe('SEC type-of-reporting-person codes — IN individual, CO corporation, PN partnership, IA investment adviser, HC holding company, OO other. One person can carry several.'),
182
+ excludes_certain_shares: z
183
+ .boolean()
184
+ .optional()
185
+ .describe('True when the reported aggregate deliberately excludes shares this person disclaims beneficial ownership of. Absent when the filing does not answer.'),
186
+ notes: z
187
+ .string()
188
+ .optional()
189
+ .describe("The filer's own cover-page footnote, usually the share count the percentage was computed against. Clipped when long — the full text is in the filing."),
190
+ })
191
+ .describe('One reporting person from the schedule cover page.'))
192
+ .describe('Every reporting person on this filing. A joint filing lists a fund, its adviser, and its controlling principal separately, each reporting the same underlying shares.'),
193
+ })
194
+ .describe('One SCHEDULE 13D or 13G filing made about this issuer.'))
195
+ .describe('Blockholder filings, newest first, capped at limit.'),
196
+ dataset: z
197
+ .object({
198
+ name: z
199
+ .string()
200
+ .describe('Dataframe handle (df_XXXXX_XXXXX) — pass to secedgar_dataframe_query.'),
201
+ row_count: z.number().describe('Rows materialized in the dataframe.'),
202
+ expires_at: z.string().describe('ISO 8601 expiry timestamp.'),
203
+ truncated: z
204
+ .boolean()
205
+ .describe('True when the issuer has more structured filings than limit fetched — the dataframe holds the parsed filings only, not the whole history.'),
206
+ })
207
+ .optional()
208
+ .describe("Canvas dataframe holding one row per reporting person across every parsed filing, each row carrying the issuer, form, accession, and dates alongside the person's powers. Joins against the insider and 13F dataframes on issuer_cik. Absent when canvas is unavailable or nothing parsed."),
209
+ }),
210
+ enrichment: {
211
+ notice: z
212
+ .string()
213
+ .optional()
214
+ .describe('Guidance when no filings matched — names the coverage boundary and the fallback.'),
215
+ truncated: z.boolean().optional().describe('True when filings were capped by limit.'),
216
+ shown: z.number().optional().describe('Number of filings returned.'),
217
+ cap: z.number().optional().describe('The limit cap applied.'),
218
+ },
219
+ async handler(input, ctx) {
220
+ const api = getEdgarApiService();
221
+ const resolved = await api.resolveCik(input.issuer);
222
+ const candidates = Array.isArray(resolved) ? resolved : [resolved];
223
+ if (candidates.length > 1) {
224
+ const shown = candidates.slice(0, 10);
225
+ const list = shown.map((c) => `${c.ticker ?? c.cik} (${c.name ?? 'Unknown'})`).join(', ');
226
+ throw ctx.fail('ambiguous_issuer', `'${input.issuer}' matches multiple EDGAR companies: ${list}.`, {
227
+ ...ctx.recoveryFor('ambiguous_issuer'),
228
+ matches: shown.map((c) => ({ cik: c.cik, name: c.name, ticker: c.ticker })),
229
+ });
230
+ }
231
+ const match = candidates[0];
232
+ if (!match) {
233
+ throw ctx.fail('issuer_not_found', `Issuer '${input.issuer}' not found in EDGAR.`, {
234
+ ...ctx.recoveryFor('issuer_not_found'),
235
+ });
236
+ }
237
+ const submissions = await api.getSubmissions(match.cik);
238
+ const recent = submissions.filings.recent;
239
+ // SEC indexes a 13D/G under every CIK party to it, so the issuer's own feed already
240
+ // carries the schedules filed about it — no entity-scoped search needed.
241
+ const selected = [];
242
+ let totalMatching = 0;
243
+ let legacyCount = 0;
244
+ for (let i = 0; i < recent.form.length; i++) {
245
+ const form = recent.form[i] ?? '';
246
+ if (LEGACY_FORMS.includes(form)) {
247
+ legacyCount++;
248
+ continue;
249
+ }
250
+ const schedule = formNameToSchedule(form);
251
+ if (!schedule)
252
+ continue;
253
+ if (input.form_kind !== 'all' && schedule !== input.form_kind)
254
+ continue;
255
+ if (!input.include_amendments && form.endsWith('/A'))
256
+ continue;
257
+ totalMatching++;
258
+ if (selected.length < input.limit) {
259
+ selected.push({
260
+ form,
261
+ schedule,
262
+ accessionNumber: recent.accessionNumber[i] ?? '',
263
+ filingDate: recent.filingDate[i] ?? '',
264
+ document: rawDocumentName(recent.primaryDocument[i]),
265
+ });
266
+ }
267
+ }
268
+ if (totalMatching === 0) {
269
+ const kindLabel = input.form_kind === 'all' ? 'SCHEDULE 13D/13G' : `SCHEDULE ${input.form_kind}`;
270
+ const legacyHint = legacyCount > 0
271
+ ? `Its submissions window does hold ${legacyCount} legacy SC 13D/SC 13G filings from before ${STRUCTURED_FROM}; those are text filings with no XML to parse — read them with secedgar_get_filing.`
272
+ : `Blockholder filings from before ${STRUCTURED_FROM} use the legacy SC 13D / SC 13G names and are not parseable into this schema — search for them with secedgar_search_filings.`;
273
+ throw ctx.fail('no_filings_found', `No structured ${kindLabel} filings found for ${submissions.name} (CIK ${match.cik}). ${legacyHint}`, {
274
+ ...ctx.recoveryFor('no_filings_found'),
275
+ issuer_cik: match.cik,
276
+ issuer_name: submissions.name,
277
+ legacy_filings_before_coverage: legacyCount,
278
+ });
279
+ }
280
+ // Fetch and parse each selected filing. A document that 404s or does not parse as a
281
+ // schedule is dropped rather than failing the call — one malformed filing must not
282
+ // hide every other blockholder in the list.
283
+ const filings = [];
284
+ for (const ref of selected) {
285
+ const xml = await api.tryGetFilingDocument(match.cik, ref.accessionNumber, ref.document);
286
+ const parsed = xml ? parseBeneficialOwnershipXml(xml) : undefined;
287
+ if (!parsed) {
288
+ ctx.log.debug('Skipping unparseable beneficial-ownership filing', {
289
+ accessionNumber: ref.accessionNumber,
290
+ document: ref.document,
291
+ });
292
+ continue;
293
+ }
294
+ const purpose = clip(parsed.purpose_of_transaction, PURPOSE_MAX_CHARS);
295
+ filings.push({
296
+ form: ref.form,
297
+ schedule: ref.schedule,
298
+ is_amendment: ref.form.endsWith('/A'),
299
+ amendment_number: parsed.amendment_number,
300
+ accession_number: ref.accessionNumber,
301
+ filing_date: ref.filingDate,
302
+ event_date: parsed.event_date,
303
+ security_class: parsed.security_class,
304
+ cusips: parsed.issuer_cusips,
305
+ purpose_of_transaction: purpose.text,
306
+ purpose_truncated: purpose.cut,
307
+ reporting_persons: parsed.owners.map((o) => ({
308
+ name: o.name,
309
+ cik: o.cik,
310
+ citizenship: o.citizenship,
311
+ percent_of_class: o.percent_of_class,
312
+ aggregate_amount_owned: o.aggregate_amount_owned,
313
+ sole_voting_power: o.sole_voting_power,
314
+ shared_voting_power: o.shared_voting_power,
315
+ sole_dispositive_power: o.sole_dispositive_power,
316
+ shared_dispositive_power: o.shared_dispositive_power,
317
+ person_types: o.person_types,
318
+ excludes_certain_shares: o.excludes_certain_shares,
319
+ notes: clip(o.notes, NOTES_MAX_CHARS).text,
320
+ })),
321
+ });
322
+ }
323
+ const truncated = totalMatching > filings.length;
324
+ // One row per reporting person — the grain the ownership question is asked at, and the
325
+ // grain that joins to the insider and 13F dataframes on issuer_cik.
326
+ let dataset;
327
+ const bridge = getCanvasBridge();
328
+ const rows = filings.flatMap((f) => f.reporting_persons.map((p) => ({
329
+ issuer_cik: match.cik,
330
+ issuer_name: submissions.name,
331
+ form: f.form,
332
+ schedule: f.schedule,
333
+ is_amendment: f.is_amendment,
334
+ accession_number: f.accession_number,
335
+ filing_date: f.filing_date,
336
+ event_date: f.event_date ?? null,
337
+ security_class: f.security_class ?? null,
338
+ cusip: f.cusips[0] ?? null,
339
+ reporting_person: p.name,
340
+ reporting_person_cik: p.cik ?? null,
341
+ citizenship: p.citizenship ?? null,
342
+ percent_of_class: p.percent_of_class ?? null,
343
+ aggregate_amount_owned: p.aggregate_amount_owned ?? null,
344
+ sole_voting_power: p.sole_voting_power ?? null,
345
+ shared_voting_power: p.shared_voting_power ?? null,
346
+ sole_dispositive_power: p.sole_dispositive_power ?? null,
347
+ shared_dispositive_power: p.shared_dispositive_power ?? null,
348
+ person_types: p.person_types.join(',') || null,
349
+ has_stated_purpose: f.purpose_of_transaction !== undefined,
350
+ })));
351
+ if (bridge && rows.length > 0) {
352
+ const registered = await bridge.registerDataframe(ctx, {
353
+ rows,
354
+ sourceTool: 'secedgar_get_beneficial_owners',
355
+ queryParams: {
356
+ issuer: input.issuer,
357
+ issuer_cik: match.cik,
358
+ form_kind: input.form_kind,
359
+ include_amendments: input.include_amendments,
360
+ limit: input.limit,
361
+ },
362
+ truncated,
363
+ });
364
+ if (registered)
365
+ dataset = { ...toDatasetField(registered), truncated };
366
+ }
367
+ if (filings.length === 0) {
368
+ ctx.enrich.notice(`${totalMatching} structured filings are indexed for ${submissions.name}, but none of the ${selected.length} fetched parsed as a SCHEDULE 13D or 13G document. Read one directly with secedgar_get_filing on an accession number from secedgar_search_filings.`);
369
+ }
370
+ else if (truncated) {
371
+ ctx.enrich.truncated({
372
+ shown: filings.length,
373
+ cap: input.limit,
374
+ guidance: `${totalMatching} structured blockholder filings are indexed for this issuer. Raise limit to reach further back, or narrow with form_kind or include_amendments=false.`,
375
+ });
376
+ }
377
+ ctx.log.info('Beneficial owners retrieved', {
378
+ cik: match.cik,
379
+ formKind: input.form_kind,
380
+ totalMatching,
381
+ parsed: filings.length,
382
+ owners: rows.length,
383
+ datasetName: dataset?.name,
384
+ });
385
+ return {
386
+ issuer: input.issuer,
387
+ issuer_cik: match.cik,
388
+ issuer_name: submissions.name,
389
+ form_kind: input.form_kind,
390
+ total_structured_filings: totalMatching,
391
+ filings_parsed: filings.length,
392
+ structured_coverage_from: STRUCTURED_FROM,
393
+ legacy_filings_before_coverage: legacyCount,
394
+ filings,
395
+ dataset,
396
+ };
397
+ },
398
+ format: (result) => {
399
+ const lines = [
400
+ `**5%+ beneficial owners of ${result.issuer_name}** (CIK ${result.issuer_cik}) — input "${result.issuer}"`,
401
+ `Schedule filter: ${result.form_kind} | ${result.filings_parsed} of ${result.total_structured_filings} structured filings parsed`,
402
+ `Structured coverage starts ${result.structured_coverage_from}; ${result.legacy_filings_before_coverage} legacy SC 13D/SC 13G filings sit before it in the submissions window (read those with secedgar_get_filing).`,
403
+ ];
404
+ for (const f of result.filings) {
405
+ lines.push('');
406
+ const amendment = f.is_amendment
407
+ ? ` (amendment${f.amendment_number ? ` no. ${f.amendment_number}` : ''})`
408
+ : '';
409
+ lines.push(`## ${f.form}${amendment} — filed ${f.filing_date} [${f.accession_number}]`);
410
+ const bits = [`Schedule ${f.schedule}`];
411
+ if (f.event_date)
412
+ bits.push(`event ${f.event_date}`);
413
+ if (f.security_class)
414
+ bits.push(f.security_class);
415
+ if (f.cusips.length > 0)
416
+ bits.push(`CUSIP ${f.cusips.join(', ')}`);
417
+ lines.push(bits.join(' | '));
418
+ for (const p of f.reporting_persons) {
419
+ const pct = p.percent_of_class !== undefined ? `${p.percent_of_class}% of class` : 'percent N/A';
420
+ const owned = p.aggregate_amount_owned !== undefined
421
+ ? `${p.aggregate_amount_owned.toLocaleString()} shares`
422
+ : 'amount N/A';
423
+ const idBits = [];
424
+ if (p.cik)
425
+ idBits.push(`CIK ${p.cik}`);
426
+ if (p.citizenship)
427
+ idBits.push(p.citizenship);
428
+ if (p.person_types.length > 0)
429
+ idBits.push(p.person_types.join('/'));
430
+ lines.push(`- **${p.name}**${idBits.length > 0 ? ` (${idBits.join(', ')})` : ''}`);
431
+ lines.push(` ${owned} | ${pct}`);
432
+ lines.push(` voting sole/shared: ${p.sole_voting_power ?? 'N/A'} / ${p.shared_voting_power ?? 'N/A'} | dispositive sole/shared: ${p.sole_dispositive_power ?? 'N/A'} / ${p.shared_dispositive_power ?? 'N/A'}`);
433
+ if (p.excludes_certain_shares !== undefined) {
434
+ lines.push(` Excludes disclaimed shares: ${p.excludes_certain_shares ? 'yes' : 'no'}`);
435
+ }
436
+ if (p.notes)
437
+ lines.push(` Note: ${p.notes}`);
438
+ }
439
+ if (f.purpose_of_transaction) {
440
+ lines.push(`**Purpose of transaction:** ${f.purpose_of_transaction}${f.purpose_truncated ? ' (clipped — read the full Item 4 with secedgar_get_filing)' : ''}`);
441
+ }
442
+ else {
443
+ lines.push(f.schedule === '13G'
444
+ ? '**Purpose of transaction:** not applicable — 13G is the passive form and has no purpose item.'
445
+ : '**Purpose of transaction:** not stated in this filing.');
446
+ }
447
+ }
448
+ if (result.dataset) {
449
+ const note = result.dataset.truncated
450
+ ? ' (truncated — more structured filings exist beyond limit)'
451
+ : '';
452
+ lines.push(`\nDataset: ${result.dataset.name} (${result.dataset.row_count} reporting-person rows, expires ${result.dataset.expires_at})${note} — query with secedgar_dataframe_query.`);
453
+ }
454
+ return [{ type: 'text', text: lines.join('\n') }];
455
+ },
456
+ });
457
+ //# sourceMappingURL=get-beneficial-owners.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-beneficial-owners.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-beneficial-owners.tool.ts"],"names":[],"mappings":"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"}
@@ -90,5 +90,10 @@ export declare const getFilingTool: import("@cyanheads/mcp-ts-core").ToolDefinit
90
90
  readonly code: JsonRpcErrorCode.NotFound;
91
91
  readonly when: "The section string did not match any detected heading in the document";
92
92
  readonly recovery: "Pick a heading from the outline in the error message, or use offset paging instead.";
93
- }], undefined>;
93
+ }], {
94
+ readonly notice: z.ZodOptional<z.ZodString>;
95
+ readonly truncated: z.ZodOptional<z.ZodBoolean>;
96
+ readonly shown: z.ZodOptional<z.ZodNumber>;
97
+ readonly cap: z.ZodOptional<z.ZodNumber>;
98
+ }>;
94
99
  //# sourceMappingURL=get-filing.tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-filing.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-filing.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AA+GjE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkcxB,CAAC"}
1
+ {"version":3,"file":"get-filing.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-filing.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AA+GjE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0dxB,CAAC"}
@@ -45,6 +45,21 @@ const documentEntrySchema = z
45
45
  export const getFilingTool = tool('secedgar_get_filing', {
46
46
  description: "Fetch a specific filing's metadata and document content by accession number. Returns the primary document as readable text. Use offset/next_offset for multi-page access to large filings (10-K, S-1 can exceed 1M chars): pass the next_offset from a truncated response to read the next page. Use section to jump directly to a heading (e.g. 'risk factors', 'item 7') without needing an offset.",
47
47
  annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
48
+ // Agent-facing disclosure of the content window. `content_truncated` types the
49
+ // fact on the wire; this carries how much of the document the page actually
50
+ // held and the cap that produced it, which the output schema does not.
51
+ enrichment: {
52
+ notice: z
53
+ .string()
54
+ .optional()
55
+ .describe('Guidance on reading the next page when the content was capped.'),
56
+ truncated: z
57
+ .boolean()
58
+ .optional()
59
+ .describe('True when the document is longer than `content_limit` allowed through.'),
60
+ shown: z.number().optional().describe('Characters of document text returned on this page.'),
61
+ cap: z.number().optional().describe('The `content_limit` that was applied.'),
62
+ },
48
63
  errors: [
49
64
  {
50
65
  reason: 'document_not_found',
@@ -180,7 +195,7 @@ export const getFilingTool = tool('secedgar_get_filing', {
180
195
  })
181
196
  .describe('One detected heading with its offset.'))
182
197
  .optional()
183
- .describe('Document outline — detected headings with their character offsets. Present on the first page of a truncated response (offset=0, no section). Use a heading offset as offset, or pass heading text as section, to jump to that section.'),
198
+ .describe('Document outline — up to 50 detected headings with their character offsets. Present on the first page of a truncated response (offset=0, no section). Use a heading offset as offset, or pass heading text as section, to jump to that section.'),
184
199
  filing_url: z.string().describe('Direct URL to the filing on SEC.gov.'),
185
200
  }),
186
201
  async handler(input, ctx) {
@@ -315,6 +330,13 @@ export const getFilingTool = tool('secedgar_get_filing', {
315
330
  });
316
331
  }
317
332
  const { text, truncated, totalLength, nextOffset } = windowText(fullText, effectiveOffset, input.content_limit);
333
+ if (truncated) {
334
+ ctx.enrich.truncated({
335
+ shown: text.length,
336
+ cap: input.content_limit,
337
+ guidance: `Showing ${text.length} of ${totalLength} characters. Pass next_offset (${nextOffset ?? '?'}) as offset to read the next page, or jump with section.`,
338
+ });
339
+ }
318
340
  // Emit outline on first-page truncated responses (not on subsequent pages or section jumps)
319
341
  const shouldEmitOutline = truncated && effectiveOffset === 0 && !input.section;
320
342
  const outline = shouldEmitOutline ? detectHeadings(fullText, 50) : undefined;