Skip to main content
Glama
chidrupa99

northbridge-diligence

by chidrupa99

Northbridge Diligence — SEC EDGAR MCP + Screening Skill

Chidrupa Mamunooru · Delivery Engineer take-home

A two-layer tool for Northbridge Capital Partners' deal team:

  • Data layer (MCP server) — wraps the SEC EDGAR APIs into a focused set of tools a model can call to answer diligence questions, with every number traced to its source filing.

  • Intelligence layer (skill) — sits on top and turns a company name into a first-pass screening memo an analyst would hand to a deal lead.

The goal is the one the client stated: "get this data via Claude so our analysts save time, and the deal team can trust those numbers."

Trust is enforced structurally, not by asking the model nicely. Three things are load-bearing:

  1. Every figure carries its filing — accession number, form type, period end, XBRL tag, and a resolvable EDGAR URL.

  2. The code computes; the model narrates. Ratios, the judgment of whether a ratio is meaningful, and the risk flags are all produced in Python against fixed thresholds. The skill is forbidden from doing arithmetic or inventing a flag.

  3. The behaviour is pinned by tests — 146 offline tests plus a golden-set regression, so a tag-mapping tweak that would silently change a margin fails the build instead.


Architecture

company name ──► [ company-screen skill ]         (intelligence layer)
                        │  selects tools, narrates the result, writes the memo
                        │  does NOT compute ratios or decide risk
                        ▼
             [ northbridge-diligence MCP server ]  (data layer, src/northbridge_diligence/server.py)
                        │  thin MCP shim: decorators + uniform error envelope
                        ▼
             [ edgar_client.py ]                    (all logic: HTTP, XBRL, math, flags)
                        │
                        ▼
                 SEC EDGAR REST APIs

edgar_client.py holds all logic so it is unit-testable and reusable off-server; server.py is a thin registration layer. The sample memos were assembled following the skill's template from the tool functions' outputs — the same functions the MCP server exposes to a Claude client, without the intermediate protocol round-trip.

One fetch, not eighteen

Financial data comes from data.sec.gov/api/xbrl/companyfacts/CIK##########.jsonone request returns every XBRL fact the filer has ever reported. An earlier design called companyconcept once per curated line item — 17 of those, plus the ticker-map lookup — so 18 requests per screen, 18 chances to hit a rate limit, and 18 partial-failure modes.

A full screen is now two HTTP calls: the ticker→CIK map (cached) and one companyfacts blob (cached). A test asserts this and asserts no companyconcept URL is ever requested, so the property can't regress.

The same blob also hands us every prior-year comparative for free — a FY2025 10-K carries FY2023 and FY2024 columns — so a five-year history needs no extra requests.


Related MCP server: OpenCapital MCP Server

Setup

Prerequisites: Python 3.10 or newer, and Claude Code or Claude Desktop. Nothing else — SEC EDGAR is public, so there is no account, API key or cost.

1. Get the code and install it

git clone https://github.com/chidrupa99/northbridge-diligence.git
cd northbridge-diligence
python3 scripts/doctor.py                    # runs on ANY Python; checks yours is >= 3.10 first
python3 -m venv .venv
source .venv/bin/activate                    # Windows: .venv\Scripts\activate
python -m pip install --upgrade pip          # editable installs need pip >= 21.3
pip install -e .
export EDGAR_USER_AGENT="Your Org you@example.com"    # Windows: set EDGAR_USER_AGENT=...
python scripts/doctor.py                     # 11 checks; each failure prints its own fix

export sets an environment variable — a value the terminal remembers and passes to programs it launches. SEC returns HTTP 403 to unidentified clients, so this is required. It is a contact string, not a credential.

2. Install the plugin

/plugin marketplace add /absolute/path/to/northbridge-diligence
/plugin install northbridge-diligence

Restart, and that is the install. The plugin ships the MCP server config and the skill together, so the two cannot end up on different Claude surfaces — which is the most common way this tool gets installed wrong.

Confirm with python scripts/doctor.py: check 11 reports wired: Plugin (bundled).

IMPORTANT

On Windows, edit one line in plugin/.mcp.json before installing: change the command to ${CLAUDE_PLUGIN_ROOT}/../.venv/Scripts/edgar-mcp.exe. A single bundled config cannot cover both platforms — the interpreter path differs and there is no conditional syntax.

3. Use it

Say: "Screen Beyond Meat for the deal team". See Triggering the skill for what else fires it and how to tell it worked.


NOTE

Not using Claude Code? Plugins are a Claude Code feature, so two surfaces need a different route.

Claude Desktop chat (Cowork) — register the server by hand in claude_desktop_config.json, and enable the skill for your claude.ai account via Customize in the sidebar. Cowork sessions do not read ~/.claude/skills/. Quit the app before editing its config — it flushes its own preferences over your write while running.

claude.ai web and mobile — not possible. edgar-mcp speaks MCP over stdio, so the client launches it as a local child process, and a process in Anthropic's cloud cannot spawn a binary on your laptop. An account-synced skill will still trigger there but its tools are unreachable, which looks installed and produces nothing.

Full walkthrough for both — per-platform config paths, the merge case when other MCP servers are already registered, the surface matrix, and hand-installing the skill for Claude Code — is in DEPLOYMENT.md.

  • Installing for a team?DEPLOYMENT.md — security posture, egress requirements, troubleshooting

  • Extending or maintaining it?DEVELOPING.md — test harness, fixtures, tuning knobs, invariants


Triggering the skill

IMPORTANT

There is no command to remember. Say it in plain language:

"Screen Beyond Meat for the deal team"

Any ticker or company name works — BYND, Target, TGT, "size up Dollar General", "run a first pass on Casey's".

The skill triggers on the request, not on a keyword. Its frontmatter description is what Claude matches against, so all of these fire it:

What an analyst actually types

Fires?

"Screen Beyond Meat for the deal team"

"Can you size up Tractor Supply as a comp?"

"Run a first pass on Casey's General Stores"

"Pull the financials on TGT"

"What do we think of Ollie's Bargain Outlet?"

"What's Apple's stock price today?"

✗ — not in EDGAR; this reads filings, not market data

How to tell it worked

A correct result has two tells:

  1. [S1]-style source markers throughout — on every figure in the memo

  2. A Sources table at the bottom, mapping each marker to a filing accession number and URL

WARNING

Figures without source markers mean the skill is not being used. Claude answered from its own knowledge instead of calling the tools, and those numbers are not traceable to a filing. Two causes, in order of likelihood:

  1. Surface mismatch — the MCP server and the skill landed on different clients. Installing the plugin makes this impossible; if you registered by hand instead, check the surface matrix in the Not using Claude Code? section and complete both cells of one row. python scripts/doctor.py check 11 reports which surfaces are wired.

  2. Skill not copied, or client not restarted — check ~/.claude/skills/company-screen exists and restart the client.

That second tell is the whole reason attribution is structural rather than prompted: a memo either carries citations on every number or it visibly does not, and a reader can tell in one glance which one they are holding.

If the company name is ambiguous — "Delta", "American" — the skill returns candidates and asks which you mean rather than guessing. That is deliberate: screening the wrong "Bank of X" is a silent and expensive error.

See samples/BYND_screening_memo.md for what a finished result looks like.


The tools — what each does and why

Scoping the toolset was the main judgment call. The principle: one tool = one diligence question an analyst actually asks, each returning source-attributed data, nothing that overlaps.

Tool

What it does

Why it exists

resolve_company

ticker/name → CIK; flags ambiguous names

Everything keys off CIK. Ambiguity is surfaced (not guessed) because screening the wrong "Bank of X" is a silent, costly error. Every tool raises the same disambiguation payload, so the model never has to learn two shapes.

get_company_profile

identity, SIC industry, fiscal year-end, latest 10-K/10-Q

Orients a screen (who/what/where) and anchors the fiscal calendar before pulling numbers.

get_key_financials

curated multi-year IS/BS/CF, each value source-tagged

The financial-trajectory + capital-structure backbone. Returns reference_fiscal_year, xbrl_tags_used and mixed_tag_basis so the reader can see how the series was assembled.

compute_screening_metrics

growth, margins, leverage, liquidity — computed in code — plus flags, data_quality, and the thresholds used

The client must trust the numbers. LLM arithmetic isn't trustworthy, so ratios are calculated in Python, returned with the sourced inputs, and each marked `meaningful: true

list_filings

recent filings + direct EDGAR URLs

Source citation, latest annual/quarterly report, and recent 8-K events worth a second look.

scan_disclosure_signals

full-text sweep for going-concern doubt, material weaknesses, customer concentration and goodwill impairment — with a computed boilerplate-vs-signal verdict

The numbers cannot show what a company is worried about. Two things make this more than a search box: the phrasing is calibrated against real filings, and the judgment of whether a hit means anything is computed rather than narrated — language present in every annual report is template text, language that comes and goes is news. Deliberately kept out of flags, which stays reserved for red flags code can verify arithmetically.

get_risk_factors

Item 1A from the latest 10-K

The "risk section worth a second look," and the verification step for anything scan_disclosure_signals reports as present. Conservative extraction — returns the source URL and a note rather than a guess if it can't isolate the section.

get_financial_concept

any one metric/US-GAAP tag as a time series

Escape hatch for questions the curated set doesn't cover (R&D, capex). Keeps the curated tools focused while staying flexible. Tag names are validated against a strict pattern before they reach a URL.

The second scoping decision: ~500 concepts down to 17

Scoping happened twice — once at the tool surface above, and once at the data layer. The second is less visible and arguably more consequential.

Filers do not report a common set of concepts. Measured across seven filers in different industries: Beyond Meat reports 376 US-GAAP concepts, Apple 503, JPMorgan 917. Between them they use 2,220 distinct concepts, of which only 49 are common to all seven — a shared core of roughly 2%, and mostly plumbing (share counts, tax line items). Almost nothing you would build a screen on.

So CONCEPT_MAP curates that down to 17 concepts a first-pass PE screen actually turns on, each mapped to an ordered list of candidate US-GAAP tags:

Statement

Concepts

Income

revenue · cost_of_revenue · gross_profit · operating_income · interest_expense · net_income

Balance sheet

total_assets · total_liabilities · current_assets · current_liabilities · stockholders_equity · cash · long_term_debt · current_debt

Cash flow

operating_cash_flow · depreciation_amortization · capex

17 concepts, 33 candidate tags — 11 of the 17 need more than one spelling, because filers disagree:

"revenue": [
    "RevenueFromContractWithCustomerExcludingAssessedTax",  # post-ASC 606: Apple, Target, Tesla
    "Revenues",                                             # JPMorgan, Pfizer, Realty Income
    "RevenueFromContractWithCustomerIncludingAssessedTax",
    "SalesRevenueNet",                                      # legacy, pre-2018
],

The order encodes preference, not just alternatives: the modern tag wins where both exist, and the legacy tag fills the years before the transition.

No single revenue tag covers all seven filers above. The two leading tags cover six each — but not the same six. The contract-revenue tag misses JPMorgan; Revenues misses Beyond Meat. That is why this is a list rather than a string, and why the merge happens per fiscal year rather than per tag.

Curation is not a ceiling. Anything outside the 17 stays reachable through get_financial_concept, by friendly name or raw tag — so the curated set keeps the common path focused without making the uncommon question impossible.

Attribution model

Every financial datapoint is a SourcedValue carrying period_end, fiscal_year, form, accession, xbrl_tag, filed, a resolvable source_url, and — when the figure was later revised — restated plus originally_reported. The skill renders these as [S#] markers mapping to a Sources table. If a number has no source, it does not go in the memo.


The design decision the whole thing turns on: code computes, the model narrates

The first version of this tool put the interesting judgment in the skill prompt: "flag negative equity rather than quoting the exploded ratio," "call out current ratio below 1." It produced good memos. It was also unfalsifiable — two runs could disagree, and nobody could point at the line that decided.

So the judgment moved into Python:

Ratio meaningfulness. _guarded_ratio returns (value, meaningful, caveat). A negative denominator, a zero denominator, or a denominator near zero relative to the numerator all yield meaningful: false with an explanation. Beyond Meat's debt/equity is arithmetically −417.0; the tool returns that number marked unmeaningful with "denominator is negative — the ratio is not interpretable; report the negative balance itself instead." The skill is instructed never to quote an unmeaningful figure.

Risk flags. _detect_flags returns a structured list — code, severity, message, evidence (SourcedValues) — against the thresholds in one THRESHOLDS dict that is returned with the response, so the reader always sees the bar that fired:

NEGATIVE_EQUITY · EARNINGS_QUALITY · LIQUIDITY · LEVERAGE · COVERAGE · NEGATIVE_EBITDA · REVENUE_DECLINE · CASH_BURN · STALE_DATA · MISSING_DATA · TAG_DISCONTINUED · MIXED_TAG_BASIS · RESTATED

The payoff is that an analyst can re-run compute_screening_metrics("BYND") and get byte-identical flags. That is not a property a prompt can have. The skill's remaining job — deciding what leads the memo, what a deal lead actually needs to know — is exactly the part that should be a language model's.


XBRL is messier than it looks — what the client handles

These are the cases that separate a working screen from a demo. Each is covered by a test named after the failure it prevents.

Filers switch tags mid-history. Given the tag ladders above, the naive implementation is first-tag-wins: try the modern tag, and if it returns anything, stop. That silently truncates history at the ASC 606 transition — Ford came back with 10 years instead of 19, Target 10 instead of 18. Fixed by merging candidates per fiscal year rather than per tag. Where a series spans more than one tag, mixed_tag_basis says so and an info flag fires.

Fiscal years aren't calendar years. Target's fiscal 2009 ended 2010-01-30. Taking end[:4] labels it 2010 and puts two "2009"s in the series. The fix reads the filer's own fy label out of the facts — within one accession, the fact with the latest period end is that report's own year — and carries the offset over to comparatives the index didn't cover directly. A test pins 2010-01-30 → FY2009.

Filers abandon tags. Target stopped tagging GrossProfit after FY2017. A positional slice (series[-5:]) happily returned FY2013–2017 gross profit and set it beside FY2021–2025 revenue — which would have produced a gross margin dividing an eight-year-old numerator by a current denominator. Every series is now windowed by fiscal year against a reference_fiscal_year derived from anchor items, and each point-in-time metric reads its exact year or nothing. An abandoned tag becomes a visible gap plus a TAG_DISCONTINUED flag, never a stale number.

Filers restate. When the same period appears in multiple filings, RESTATEMENT_POLICY (default as_last_reported) picks one, and the value carries restated: true with originally_reported so the change is auditable rather than invisible.

Currency. Units are chosen preferring USD and never mixed; if line items span currencies, every metric is marked unmeaningful rather than quietly dividing dollars by euros.

Other error & edge-case handling

  • Missing SEC header → 403: detected and turned into an actionable message.

  • Bad ticker / private company: clear "no SEC filer matched" (EDGAR only covers registered filers).

  • Ambiguous names: returns candidates instead of guessing, from every tool.

  • Rate limits & transient failures: self-throttled to ~8 req/s (under SEC's 10/s), with exponential-backoff retries on 429/5xx that honour Retry-After. 403/404 are not retried — they won't get better.

  • Caching: a bounded, TTL'd, thread-safe cache (64 entries, 1h) so a deal sprint's repeat screens are instant and gentle on EDGAR. STATS exposes requests/cache hits/retries.

  • Messy 10-K HTML: risk-factor extraction is conservative; failure returns the source URL for manual review.

  • Uniform error envelope at the server layer ({"error": ..., "recoverable": ...}) so one bad call never crashes the model's turn.


Tests

146 offline tests plus a golden-set regression, in about a second. Three things about them are deliberate:

Recorded fixtures, not hand-written mocks. Real EDGAR responses for two filers chosen for what they break. Beyond Meat gives negative equity, negative EBITDA and positive net income on a loss-making operating business; Target gives a January fiscal year end, a mid-history tag switch, and an abandoned GrossProfit. Hand-written mocks never invent a January-FYE retailer that stops tagging gross profit — real filings do, which is the point.

Named after failure modes, not functionstest_january_year_end_uses_the_filers_own_label_not_the_calendar_year, test_abandoned_tag_becomes_a_gap_not_a_stale_number, test_a_full_screen_costs_two_http_calls. EDGAR rarely crashes you; it hands you a plausible wrong number, so each test pins one specific way that happens.

The golden set is the behavioural contract. It snapshots entire screen outputs and, on failure, names the field — flags lost: ['LIQUIDITY'] — rather than dumping a 200-line dict. I verified the harness actually bites by moving the current-ratio threshold from 1.0 to 0.5 and confirming it reported exactly that.

One limit worth stating: the suite is offline, so it verifies logic, not installation — it passes with EDGAR unreachable and no contact header set. scripts/doctor.py covers that gap. Running and extending the suite is documented in DEVELOPING.md.


Design decisions & seams

What I deliberately left out (scope discipline — each is a defensible next addition, not an oversight):

  • Public comps / peer benchmarking. High value, but it needs a peer-selection method (SIC is too crude) and multiplies API load. It's the first thing I'd add (see below), built on get_key_financials.

  • Open-ended full-text search. scan_disclosure_signals wraps EDGAR's FTS endpoint, but only behind curated phrases with a computed verdict. A general "search filings for X" tool was deliberately not exposed: an arbitrary phrase gives the model no way to tell boilerplate from news, which is the entire difficulty. extra_phrases is the escape hatch, and it carries the caveat.

  • Quarterly / TTM data. The screen is annual-first for signal clarity. The plumbing (annual_series) generalizes to quarterly with a filter change.

  • Insider / ownership (Forms 3/4/5) and institutional holdings. Useful for a deeper look, noise for a first pass.

Where the seams are (known limitations):

  • US-GAAP XBRL only. Foreign private issuers (20-F / IFRS) and non-XBRL filers won't populate get_key_financials; the tool says so rather than returning partial nonsense.

  • "Total debt" is approximated as long-term + current debt tags; finance-lease and other debt-like items aren't fully assembled. Flagged where it matters.

  • EBITDA is a proxy — operating income plus D&A from the cash flow statement. It is not any filer's adjusted definition and shouldn't be compared to one.

  • Thresholds are one global set. A 4.0x debt/EBITDA bar means different things in software and in distribution. Industry-relative bands are a real improvement, but they need a defensible peer set first — which is the comps tool.

  • Risk-factor extraction is heuristic (heading match on messy HTML); it degrades to "here's the source, read it yourself" instead of fabricating. The heuristic has been through one real failure: anchoring on the last heading match returned 2,958 characters of the wrong section on Dollar General's 10-K — where Item 1C cross-references Item 1A — and reported it as a successful extraction. It now uses the widest start/end pairing to identify the real end marker, then takes the last heading before it, which excludes both contents rows and later cross-references. A filer with a stranger document structure could still defeat it.

  • Covenant compliance is not searchable. A covenant pack was built and then removed: "covenant violation", "waiver from our lenders" and "not in compliance with the covenants" each returned zero hits even against a genuinely distressed filer, while bare "covenant" returned 84 (Beyond Meat) and 274 (Target) of pure boilerplate. A pack that always reports "absent" is worse than no pack, because absence is written into the memo as a finding. Stated as a gap instead.

  • Disclosure phrases trade precision for recall, on purpose. The first version used the full formal wording — "material weakness in our internal control over financial reporting" — which matched 0 Target filings while "material weakness" matched 23. An over-specific phrase produces a false absent, and that is the most damaging error this tool can make. Precision is recovered downstream by the boilerplate classification and the requirement to read the filing.


Sample output

Two real screens, generated live from EDGAR, each as Markdown and a self-contained HTML one-pager. The brief asks for one; a second is included because a single company cannot show that the tool discriminates.

Beyond Meat — the distress case. Five flags fire. It demonstrates the thing that separates a real screen from a naive one: FY2025 net income is positive (+$219M) while the operating business lost −$334M. A naive tool reports "profitable." This one raises an EARNINGS_QUALITY flag naming the ~$553M of profit that came from outside the operating business, marks debt/equity unmeaningful because equity is negative, and tells the deal lead to identify the non-operating item first — because that item is not isolable from XBRL, and saying so is more useful than guessing at it.

Target — the healthy case. Every solvency flag stays silent, which is the harder thing to demonstrate. Revenue is flat over five years while operating income fell 43%, so the finding is a margin problem inside a sound balance sheet. The one flag that does fire — LIQUIDITY, current ratio 0.94 — is shown in the memo to be an artefact of applying one global threshold to a retailer, where payables structurally exceed receivables, rather than a finding. That is a seam this README already declares, caught working in public. Target also exercises the January fiscal year end, a mid-history tag switch across six series, and a gross margin derived because GrossProfit has been untagged since FY2017.


What I'd build next (another week)

  1. Comps tool. Assemble a peer set (SIC + size band, human-overridable) and return side-by-side growth, margin and leverage with the same attribution. A margin falling 240bp means one thing alone and another against five peers — and it's what would make industry-relative thresholds defensible instead of one global set.

  2. Linkbase-aware statements. Statement structure lives in each filing's _pre.xml and _cal.xml, not in companyfacts. _cal.xml declares which lines sum to which subtotals, giving a free reconciliation check — JPMorgan's net interest income ($95.4bn) plus noninterest income ($87.0bn) ties exactly to $182.4bn of revenue. _pre.xml explains gaps: JPMorgan's income statement has no operating income line at all, which turns a bare MISSING_DATA flag into a structural answer. It would surface candidates for a human, never auto-substitute — mapping pretax income onto operating income would break the report-gaps-never-estimate invariant, and for a bank the difference is the loan loss provision.

  3. A covenant signal that actually works. Exact-phrase search failed and was cut (see seams). The tractable version reads the debt footnote and Item 7 liquidity discussion directly instead of pattern-matching the filing — it targets the one capital-structure question this screen cannot answer.

  4. Year-over-year risk-factor diff. A newly added risk factor is a far stronger signal than any standing one. The section extractor already spans Items 1A/3/7/9A, so the plumbing exists; the open problem is aligning risk factors across years in a way that survives rewording.

  5. Widen the golden set. 15–20 filers covering a foreign issuer, a recent IPO, a restatement and a spin-off, run in CI. Trust needs tests, and the tests need coverage.

Available Tools

8 tools
compute_screening_metricsA

The screen result, computed IN CODE (not by the model): revenue CAGR & YoY growth, gross/operating/net margins, total debt, debt/equity, debt/EBITDA, current ratio, interest coverage, EBITDA and latest operating cash flow — PLUS flags (code-detected red flags such as negative equity, weak liquidity, high leverage, cash burn, stale data, and net income that is positive while the operating business loses money) and data_quality.

Read this carefully before writing anything:

  • Every metric has a meaningful boolean and a caveat. If meaningful=false, DO NOT quote the number — state the caveat instead (e.g. a debt/equity of -417x really just means equity is negative).

  • flags is the authoritative list of concerns. Report every high- and medium-severity flag. Do not invent flags that are not in the list, and do not suppress ones that are.

  • Do not recompute or round-trip any arithmetic yourself.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes
yearsNo

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Without annotations, the description fully discloses behavior: the computation is done in code, the output structure (metrics with `meaningful` and `caveat`, `flags`, `data_quality`), and warnings against recomputation. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with purpose and lists metrics and usage instructions. While detailed, it is relatively well-structured and each sentence adds value, but could be more concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description thoroughly explains the output structure and usage. However, it fails to explain input parameters, which are essential for correct invocation, making it somewhat incomplete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the description does not explain the parameters `query` or `years`. The context implies `query` is the screen result and `years` is the time horizon, but this is not explicit, leaving the agent to guess.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool computes screening metrics and flags from a screen result, listing specific metrics and flags. It distinguishes from sibling tools which focus on data retrieval rather than computation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit instructions on how to use the output (e.g., respect `meaningful` boolean, report flags verbatim, do not recompute). However, it lacks explicit guidance on when to invoke this tool versus alternatives, though the context of requiring a screen result is implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_company_profileA

Identity card for a company: legal name, tickers, exchange, SIC industry, fiscal year-end, state of incorporation, and links to its latest 10-K/10-Q. Use this to orient a screen (who/what/where) before pulling numbers. Accepts a ticker or name.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It clearly states what the tool returns (legal name, tickers, links to 10-K/10-Q, etc.), but it does not explicitly confirm that it is a read-only operation or mention any potential errors or limitations. Nonetheless, the description is fairly transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise at three sentences: the first defines the tool, the second provides usage guidance, and the third specifies input. Every sentence earns its place without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description sufficiently lists the expected return fields (legal name, tickers, exchange, etc.) and the input type. For a simple profile retrieval tool, this is complete and aligned with the context signals.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has no description for the single 'query' parameter, but the description clarifies that it accepts a 'ticker or name,' adding meaningful context beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the tool as an 'identity card' for a company, listing specific data points (legal name, tickers, exchange, etc.) and explicitly distinguishes it from sibling tools by stating it is for orientation before pulling numbers.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use the tool ('to orient a screen before pulling numbers') and what input it accepts ('ticker or name'), effectively differentiating it from the financial data tools listed as siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_financial_conceptA

Flexible escape hatch: fetch the annual series for a single financial concept — either a friendly name from the curated map (e.g. "revenue", "operating_cash_flow", "capex") or a raw US-GAAP XBRL tag (e.g. "ResearchAndDevelopmentExpense"). Use when the curated get_key_financials set doesn't cover something the user asks about. Returns which tag matched.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes
yearsNo
metric_or_tagYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries the burden. It mentions input types (friendly name or raw XBRL tag), that it returns the annual series, and which tag matched. It doesn't discuss side effects or auth, but for a read-only data fetch this is adequate. The 'escape hatch' framing sets expectations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no fluff. Front-loaded with 'Flexible escape hatch' to set context. Every word adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 3 parameters, no output schema, and no annotations, the description is mostly sufficient but missing explanation of `query`. It connects to the sibling tool and explains the main parameter. Could improve by clarifying what `query` is (e.g., company ticker or CIK).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so description must compensate. It explains `metric_or_tag` with examples (friendly names like 'revenue' and raw tags like 'ResearchAndDevelopmentExpense'). However, the `query` parameter (presumably a company identifier) is not explained, and `years` is only hinted at by 'annual series'. Partial coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states it fetches 'annual series for a single financial concept' and distinguishes itself from the curated `get_key_financials` by being a flexible escape hatch for concepts not covered there. The verb 'fetch' and resource 'financial concept' are specific.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Use when the curated get_key_financials set doesn't cover something the user asks about.' This provides clear when-to-use guidance and names the sibling alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_key_financialsA

Curated multi-year financials (income statement, balance sheet, cash flow) from annual 10-K XBRL data. Returns each line item as a time series where every value carries its provenance: fiscal year, period end, form, accession number, and a source URL. Use this for the financial-trajectory and capital-structure parts of a screen. years = how many fiscal years back (default 5).

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes
yearsNo

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It discloses that data is sourced from annual 10-K XBRL, curated, and returns each line item as a time series with provenance (fiscal year, period end, form, accession number, URL). It does not mention authentication or rate limits, but it transparently covers data origin and output structure. No contradictions with annotations (none exist).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise: two sentences plus a brief note about years. It front-loads the core functionality and adds critical detail without redundancy. Every sentence adds value, making it efficient for an AI agent.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description adequately explains the return structure (time series with provenance fields). It covers the data source and use case. However, it could be more specific about the content of line items (e.g., which metrics are included) to fully prepare the agent. Overall, it is fairly complete for a financial data retrieval tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so description must compensate. Only the 'years' parameter is explained ('how many fiscal years back (default 5)'). The 'query' parameter, which is required, gets no explanation whatsoever in either schema or description. This is a significant gap for the most important parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool returns curated multi-year financials (income statement, balance sheet, cash flow) from 10-K XBRL data, specifying the verb 'get' and resource 'key financials'. It distinguishes from siblings by targeting 'financial-trajectory and capital-structure parts of a screen', which sets it apart from tools like get_risk_factors or get_financial_concept.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says 'Use this for the financial-trajectory and capital-structure parts of a screen', giving clear context for when to use it. It also explains the years parameter's role. While it doesn't explicitly state when not to use it or list alternatives, the guidance is sufficient given the sibling tool list.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_risk_factorsA

Extract the Item 1A "Risk Factors" section from the company's latest 10-K, plus the source URL. Use this for the risk-signal part of a screen. Extraction is conservative: if the section can't be confidently isolated from the filing's HTML, it returns a note and the source URL rather than a guess — flag that to the user so they open the filing directly.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It discloses conservative extraction, failure mode (returns note and URL instead of guess), and source URL behavior. Could mention auth or rate limits but not critical for this tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences: first states core purpose, second adds behavioral nuance. Efficient, front-loaded, no wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with no output schema, description covers extraction logic and failure handling. Missing input clarification is a gap, but overall adequate given simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only parameter 'query' has 0% schema description coverage. Description does not explain what 'query' represents (e.g., company identifier). Agent must infer from context, risking misuse.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states it extracts Item 1A 'Risk Factors' from the latest 10-K, specifies the use case 'for risk-signal part of a screen', and distinguishes from sibling tools like get_key_financials.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides context on when to use ('for the risk-signal part of a screen') and explains the conservative extraction behavior, including how to handle failure (flag to user to open filing). Missing explicit when-not-to-use or alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_filingsA

Recent SEC filings for a company, each with a direct EDGAR document URL. Optionally filter by form (e.g. ["10-K", "10-Q", "8-K"]). Use this to cite sources, find the latest annual/quarterly report, or spot recent 8-K events worth a second look. limit caps the count (default 15).

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
queryYes
form_typesNo

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It discloses that returns include a direct EDGAR URL, supports optional form filtering, and a limit parameter with default 15. However, it does not mention ordering, date range, pagination, or behavior when no results are found.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences with no wasted words. The first sentence states purpose and output, the second provides usage guidance and parameter hints. Front-loads the key information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with 3 parameters and no output schema, the description covers basic usage and output. However, it lacks details about the query parameter format, result ordering, and the meaning of 'recent', which limits completeness for an AI agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% (no descriptions in schema). The description adds meaning for 'form_types' (example list) and 'limit' (default 15). However, the required 'query' parameter is not explained, leaving ambiguity about what it accepts (e.g., ticker, CIK).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists recent SEC filings with direct EDGAR URLs, specifying verb 'list' and resource 'SEC filings'. It distinguishes from siblings like 'resolve_company' and 'get_company_profile', which serve different purposes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit use cases: citing sources, finding reports, spotting 8-K events. It mentions optional filtering by form types. It does not explicitly state when not to use, but the sibling tools are all different, so confusion is unlikely.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

resolve_companyA

Resolve a ticker OR company name to its SEC CIK.

Call this FIRST for any company. Accepts a ticker ("MSFT") or a name ("Microsoft"). Returns a single {"resolved": {...}} match, or when a name is ambiguous, {"ambiguous": true, "candidates": [...]} — in that case ask the user which company they mean instead of guessing. EDGAR only covers SEC-registered (public) filers.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Describes both success and ambiguous outcomes, and notes EDGAR covers only SEC-registered filers. Without annotations, it carries the burden well.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each adds value: purpose, usage, edge case handling. No unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, description covers both output shapes and domain restriction. Adequate for a simple one-param tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema coverage, description adds full meaning: query accepts ticker or name, with examples. Single parameter is well-explained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the tool resolves a ticker or company name to SEC CIK, with examples. Distinguishes it from sibling tools which focus on financial data.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Call this FIRST for any company' and advises asking user on ambiguous results. No explicit exclusion or alternative mention, but context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

scan_disclosure_signalsA

Sweep a company's filings for the risk LANGUAGE that never appears in the numbers: going-concern doubt, material weaknesses, restatements, covenant breaches, customer concentration, goodwill impairment. Use this alongside compute_screening_metrics for the risk-signals part of a screen — the financial tools cannot see any of it.

Each signal comes back with a computed assessment, and that is the field to read first:

  • "absent" — the phrase appears in no filing since 2001. This is a real negative finding; report it as one.

  • "likely_boilerplate" — present in EVERY annual report, so it is standing risk-factor or audit-report template text. Do NOT report it as a finding without reading the filing.

  • "changed_over_time" — present in some years and not others. The highest- signal case; read the years that differ.

  • "present_non_annual" — appears outside the 10-Ks, so likely a discrete event. Read the filing.

A hit means the words are in the document, NOT that the condition applies. Verify anything present via get_risk_factors or the linked filing before writing it up. These signals are deliberately separate from flags in compute_screening_metrics, which stays reserved for red flags code can verify arithmetically. extra_phrases appends your own exact phrases to the sweep.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes
extra_phrasesNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description thoroughly explains the behavioral traits: it returns computed assessments (absent, likely_boilerplate, etc.) with definitions, warns that a hit is not a condition, and advises verification. Since no annotations are provided, the description fully covers the tool's behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is relatively long but well-structured with bullet points for assessment values. Every sentence adds value, though brevity could be improved slightly. It is appropriately front-loaded with the core action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description explains the four possible assessment outcomes and their meanings. It also positions the tool relative to siblings. The coverage is sufficient for a tool of this complexity, though explicit enumeration of output fields would improve completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage, but the description adds meaning by explaining extra_phrases ('appends your own exact phrases'). It does not explicitly describe the query parameter, but context from sibling tools implies it is a company identifier. This compensation raises the score above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool scans a company's filings for specific risk language (e.g., going-concern doubt, material weaknesses). It distinguishes itself from the sibling tool compute_screening_metrics by noting that financial tools cannot see these qualitative signals.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description advises using this tool alongside compute_screening_metrics for the risk-signals part of a screen, implying when it is appropriate. It does not explicitly list when not to use it, but the context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 8 tool updatesv1.0.0
    • First observedcompute_screening_metrics
    • First observedget_company_profile
    • First observedget_financial_concept
    • First observedget_key_financials
    • First observedget_risk_factors
    • First observedlist_filings
    • First observedresolve_company
    • First observedscan_disclosure_signals

TDQS

A4.4/5.0

Scored across 8 tools

Disambiguation5/5

Each tool has a clearly distinct and well-defined purpose: resolving company identifiers, retrieving profile info, financial data, computed metrics, filing lists, risk text, flexible concept access, and disclosure language scanning. No overlap or ambiguity.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case (e.g., resolve_company, get_company_profile, compute_screening_metrics). The verbs are descriptive, and the pattern is uniform, making intention clear.

Tool Count5/5

With 8 tools, the server is well-scoped for its purpose of SEC-based financial due diligence. Each tool addresses a necessary step without being excessive or minimal.

Completeness5/5

The tool set covers the full workflow: company identification, profile, financials, computed metrics, filing access, risk factors, and disclosure signals. The escape hatch for arbitrary concepts fills any gaps, making it comprehensive.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    B
    maintenance
    MCP server for accessing SEC EDGAR filings. Connects AI assistants to company filings, financial statements, and insider trading data with exact numeric precision.
    21
    355
    AGPL 3.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Hosted MCP server providing read-only access to US public company fundamentals, segment breakdowns, peer comparisons, and earnings data sourced directly from SEC filings.
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    An MCP server that enables models to access SEC EDGAR filings, filing text, and XBRL financial facts with caching, rate limiting, and iXBRL stripping.
    8
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    An MCP server that enables natural-language queries over SEC EDGAR filings and live market data, providing hybrid retrieval with reranking for company snapshots, quotes, fundamentals, and macro indicators.
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/chidrupa99/northbridge-diligence'

If you have feedback or need assistance with the MCP directory API, please join our Discord server