diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ae96b8..f2aae4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,25 @@ This ensures clients can always see what tools are available in a given version --- +## [1.14.0] — 2026-08-25 + +**Tool count: 36** (+1: `get_insider_directory`). Free tools 22 → 23; gated unchanged at 13. + +### Added +- `get_insider_directory` (generated) — browse insiders alphabetically by surname: the A–Z rail with a count per letter, plus one page of insiders under the requested letter. Free. Wraps `GET /v1/insiders/directory`, which shipped in the backend as insiderapi #238 and had no MCP tool until now. Returns **one row per filer group**: a fund group files a single Form 4 listing several reporting owners — the fund, its GP, its management company — each a real EDGAR filer with its own CIK, and listing all of them spent about 11% of a capped surface describing the same actors more than once. + + Found by `codegen:check` failing on `main` with a populated diff body, which distinguishes real drift from the documented Windows CRLF artefact. That is the second release running where a missing tool surfaced only from an unrelated `codegen:check` run rather than from anything watching the spec. + +### Changed +- **List results render as a table instead of pretty-printed JSON.** Every tool returned `JSON.stringify(data, null, 2)`; for the list endpoints that is a bad trade. A 100-row `get_transactions` response was ~2,100 lines and ~15k tokens, and roughly 60% of it was the same nineteen key names repeated a hundred times. A pipe table states each key once, in the header: **60,302 → 22,145 characters, 2.7×**, a figure `test/format.mjs` prints on every run so it stays honest as the shape changes. + + That saving is spent from the caller's context window rather than ours, and MCP is this product's highest-reach channel, so two limits are deliberate. **No columns are dropped** — a field the model cannot see is a field the user cannot ask about, and these tools are generated from an evolving spec, so a hand-maintained column list would rot silently. **Rows carrying populated nested collections keep their old JSON output exactly** — `get_signals` returns each signal with its `transactions[]` attached, and those are the substance of the answer. + + Cells truncate at 80 characters. Measured against production before shipping: 41 of 75,833 insider names (0.05%), 0 of 1,345,485 security titles, 4 of 20,313 company names. + +### Fixed +- **Numbers below 1 keep four decimals rather than two.** `formatCell` rounded every non-integer to 2dp with the reasoning that money reads fine that way. It does; returns do not. Return and hit-rate fields are stored as **fractions** — the generated spec says so on every scored endpoint — so at 2dp `avgReturn3m` 0.0234 printed `0.02` (+2%, not +2.34%), 0.109 printed `0.11`, and a −0.30% return printed the nonsense `-0.00`. `GET /v1/insiders/leaderboard` returns an array of flat rows carrying exactly those fields, so it takes the new table path and its entire ranking column would have collapsed into ties. + ## [1.13.0] — 2026-08-12 **Tool count: 35** (+1: `list_filings`). Free tools 21 → 22. diff --git a/package.json b/package.json index 05ed511..5342fd3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "form4api-mcp", - "version": "1.13.0", + "version": "1.14.0", "mcpName": "io.github.theodor90/form4api-mcp", "description": "MCP server for Form4API — SEC Form 4 insider trading data. Lets Claude / Cursor / Windsurf / Zed query real-time US insider trading data via natural language.", "keywords": [ diff --git a/server.json b/server.json index 54cdf19..e777481 100644 --- a/server.json +++ b/server.json @@ -2,8 +2,8 @@ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "io.github.theodor90/form4api-mcp", "title": "Form4API — SEC Insider Trading", - "description": "Real-time SEC Form 4 insider trading + Form 144, 13F-HR & congressional STOCK Act data. 35 tools + 6 research prompts.", - "version": "1.13.0", + "description": "Real-time SEC Form 4 insider trading + Form 144, 13F-HR & congressional STOCK Act data. 36 tools + 6 research prompts.", + "version": "1.14.0", "websiteUrl": "https://www.form4api.com", "repository": { "url": "https://github.com/theodor90/form4api-mcp", @@ -13,7 +13,7 @@ { "registryType": "npm", "identifier": "form4api-mcp", - "version": "1.13.0", + "version": "1.14.0", "transport": { "type": "stdio" }, "environmentVariables": [ { diff --git a/test/mcp-test.mjs b/test/mcp-test.mjs index 76cfdd9..5f55f5b 100644 --- a/test/mcp-test.mjs +++ b/test/mcp-test.mjs @@ -150,7 +150,7 @@ async function runTest() { server.stdin.write(JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized', params: {} }) + '\n') // ── Test 2: tools/list ──────────────────────────────────────────────── - console.log('\n[2] tools/list — 35 tools registered') + console.log('\n[2] tools/list — 36 tools registered') const listRes = await send('tools/list', {}) const toolNames = (listRes.result?.tools ?? []).map(t => t.name) assert(!listRes.error, 'no error in tools/list response')