Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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": [
Expand Down
6 changes: 3 additions & 3 deletions server.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -13,7 +13,7 @@
{
"registryType": "npm",
"identifier": "form4api-mcp",
"version": "1.13.0",
"version": "1.14.0",
"transport": { "type": "stdio" },
"environmentVariables": [
{
Expand Down
2 changes: 1 addition & 1 deletion test/mcp-test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
Loading