Analytics Legends — SAP Analytics Intelligence
What this MCP does
Provides SAP analytics intelligence through searchable firm, market, opportunity, news, concept, study, training, and knowledge-graph data.
Tools
Input schema
{'type': 'object', 'required': ['by'], 'properties': {'by': {'enum': ['country', 'kind', 'module', 'sap_signal_band'], 'type': 'string', 'description': 'Which facet to count on. Required — there is no default worth guessing.'}, 'kind': {'type': 'string', 'description': 'Restrict to one organisation kind before counting, same vocabulary as search_firms. Combining it with `by:"kind"` is legal and returns that single bucket.'}, 'query': {'type': 'string', 'maxLength': 200, 'description': 'Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim.'}, 'module': {'type': 'string', 'description': 'Restrict to organisations with a DECLARED link to one SAP module code before counting, same vocabulary as search_firms\' `module`. Combining it with `by:"module"` is legal and returns that single bucket (plus the null bucket).'}, 'country': {'type': 'string', 'pattern': '^[A-Za-z]{2}$', 'description': 'ISO-3166-1 alpha-2 country code, e.g. DE, FR, CH.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'n': {'type': ['integer', 'null']}, 'value': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'properties': {'level': {'type': 'string', 'description': 'Restrict to one level, matched case-insensitively: Beginner · Intermediate · Advanced · Expert. Counts in `_meta.available_levels`.'}, 'limit': {'type': 'integer', 'default': 10, 'maximum': 50, 'minimum': 1, 'description': 'Max rows (hard cap 50).'}, 'query': {'type': 'string', 'maxLength': 200, 'description': 'Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim.'}, 'track': {'type': 'string', 'description': 'Restrict to one track, by SLUG (`databricks-data-eng`) or by English name (`Databricks & Data Eng.`), matched case-insensitively. The live vocabulary with per-track counts is `_meta.available_tracks` on every response. The numeric track_id is deliberately NOT accepted — it is an internal counter, and passing `6` would look like naming a subject.'}, 'cursor': {'type': 'string', 'maxLength': 512, 'description': "Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'id': {'type': ['string', 'null'], 'description': 'Module id, e.g. M001 — the value get_academy_module takes.'}, 'slug': {'type': ['string', 'null']}, 'tags': {'type': ['array', 'null'], 'items': {'type': 'string'}}, 'level': {'type': ['string', 'null']}, 'status': {'type': ['string', 'null'], 'description': "Editorial access marker: 'available' or 'legend-pass'. Served, not filtered on. READ 'legend-pass' AS 'sold at the CONSULTANT tier': it is a LEGACY label from when the paid tier was called Legend, it sits on the majority of rows, and the tier that actually opens the body here is Consultant (get_academy_module). The site stopped rendering this field for exactly that reason on 2026-07-26; this endpoint still serves the raw value, so the LABEL is the stale half and the tier floor is the true one."}, 'title_en': {'type': ['string', 'null']}, 'title_fr': {'type': ['string', 'null']}, 'is_preview': {'type': ['boolean', 'null'], 'description': 'The second free-access marker. Does NOT coincide with status — read both.'}, 'summary_en': {'type': ['string', 'null']}, 'summary_fr': {'type': ['string', 'null']}, 'track_slug': {'type': ['string', 'null']}, 'updated_at': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'track_name_en': {'type': ['string', 'null']}, 'track_name_fr': {'type': ['string', 'null']}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}, 'duration_minutes': {'type': ['number', 'null']}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'properties': {'lang': {'type': 'string', 'pattern': '^[A-Za-z]{2}$', 'description': "Reading language for the TITLE — 'EN' (default), 'FR' or 'DE'. This is a RENDERING choice, never a filter: it changes which string `title` carries, never which rows come back. Read `title_lang` on every row for the language actually served: it differs from what you asked for exactly when that translation does not exist (FR covers 1,492 of 1,588 site-radar rows, DE 1,373 — measured 2026-09-04), and the verbatim is served instead, labelled with the language the harvest chain measured. `source_lang` always carries the language the ADVERTISER wrote in, translated or not. The promoted leg has no translated columns at all: its rows ignore this argument and say so with `title_lang: null` — see `_meta.untranslated_leg`."}, 'limit': {'type': 'integer', 'default': 10, 'maximum': 50, 'minimum': 1, 'description': 'Max rows (hard cap 50).'}, 'query': {'type': 'string', 'maxLength': 200, 'description': 'Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim.'}, 'cursor': {'type': 'string', 'maxLength': 512, 'description': "Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}, 'country': {'type': 'string', 'pattern': '^[A-Za-z]{2}$', 'description': "ISO-3166-1 alpha-2 code, applied to both legs as a predicate on the row's own country_code. It NO LONGER selects the site-radar leg alone: the promoted feed carried country_code on almost none of its rows until 2026-08-28 and now carries it on most, so a country filter now returns both legs. A row still without one is dropped because it does not match, not because its leg was excluded by assumption. `_meta.match_count_by_leg` shows what each leg contributed on YOUR call — read the split there, never from a figure quoted in this text."}, 'location': {'type': 'string', 'description': "City or place, matched case-insensitively as a substring of the posting's location. The promoted leg is all-German (Hamburg, Frankfurt am Main, Bremen, Munich, Cologne, Dortmund, Hanover, Landshut, Mannheim, Stuttgart); the site-radar leg is worldwide."}, 'remote_mode': {'type': 'string', 'description': "Restrict to one work-location policy: `remote`, `hybrid` or `onsite`. READ THIS BEFORE ANSWERING A REMOTE QUESTION: a large share of the radar declares no policy at all (`_meta.remote_mode_undeclared` carries the live count — roughly half the radar when last measured, and a frozen pair written here drifted ~30% in two days), and an undeclared row is NOT an on-site row — it is a posting that does not say. Any value here therefore sets those rows aside rather than classifying them, exactly as the site's own filter does, and `_meta.remote_mode_undeclared` reports how many were set aside. The promoted leg carries its own `remote_mode` column and is filtered by the same predicate. Read `_meta.available_remote_modes` for the live spread before assuming a value exists."}, 'employment_type': {'enum': ['freelance', 'contract', 'permanent'], 'type': 'string', 'description': 'Restrict to one engagement type. THE RADAR IS MOSTLY PERMANENT, so a freelance or contract question answered off an unfiltered page is answered with salaried jobs. For the actual split, make the filtered call and read `_meta.tranche_total_row_count` — it is counted at query time. The promoted leg declared NO contract_type until 2026-08-28 and now declares one on most of its rows, so a value here no longer drops that leg wholesale — only the rows still silent. THOSE ROWS ARE NOT A FOURTH TYPE AND NOT PERMANENT ONES: `_meta.available_employment_types` counts only what declares, and `_meta.employment_type_undeclared` carries the rest, so the two together are the population and either alone is not. Read both before quoting a mix.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'id': {'type': ['string', 'null'], 'description': "The posting's identity — stable across calls, key for dedup."}, 'leg': {'type': ['string', 'null'], 'description': '`promoted` or `site_radar` — which of the two merged public legs served this row.'}, 'title': {'type': ['string', 'null']}, 'skills': {'type': ['array', 'null'], 'description': 'Skills the posting names. Null when it names none.'}, 'source': {'type': ['string', 'null']}, 'category': {'type': ['string', 'null']}, 'currency': {'type': ['string', 'null']}, 'location': {'type': ['string', 'null']}, 'firm_name': {'type': ['string', 'null']}, 'posted_at': {'type': ['string', 'null']}, 'rate_band': {'type': ['object', 'null'], 'description': "Editorial benchmark for this posting's (seniority × product × region) cell — NOT a rate the employer offered. `basis` and `kind` are inside the object on purpose, so no extraction can lift the numbers away from what they mean. 2026-08-29: this band is a SUBSCRIBER surface and is no longer carried by the public radar file this lane reads — expect it to be null here. The posting's OWN published rate, when it has one, stays in currency / daily_rate_min / daily_rate_max."}, 'seniority': {'type': ['string', 'null']}, 'expires_at': {'type': ['string', 'null']}, 'salary_max': {'type': ['number', 'null']}, 'salary_min': {'type': ['number', 'null']}, 'source_url': {'type': ['string', 'null']}, 'title_lang': {'type': ['string', 'null'], 'description': "ISO-639-1 language the SERVED `title` is written in. READ IT ON EVERY ROW: it is what you asked for in `lang` when that translation exists, and the advertiser's own language when it does not (FR covers 1,492 of 1,588 site-radar rows, DE 1,373 — measured 2026-09-04). Null when the harvest chain could not decide, and on every promoted-leg row, which carries no translated column at all. ⚠️ THIS FIELD CHANGED REFERENT ON 2026-09-04: until then it named the language the ADVERTISER wrote in — that fact now lives in `source_lang`. The two coincided while no translation was served and diverge from the first one that is."}, 'description': {'type': ['string', 'null'], 'description': 'Posting text, HTML stripped, clamped. Null on the radar leg.'}, 'rate_period': {'type': ['string', 'null']}, 'remote_mode': {'type': ['string', 'null'], 'description': "The posting's declared work-location policy (`remote` / `hybrid` / `onsite`). NULL means the posting does not say — never read it as on-site."}, 'source_lang': {'type': ['string', 'null'], 'description': "ISO-639-1 language the ADVERTISER wrote the title in, measured by the harvest chain and never changed by `lang` — 'en' on 1,566 rows, 'de' on 337 (2026-08-23). Null when the chain could not decide, and on the promoted leg. Compare it with `title_lang` to know whether the title you are quoting is the advertiser's own words or this platform's rendering of them: a harvested posting is a third party's text, and saying which of the two you are citing is the only honest way to quote it."}, 'citation_url': {'type': 'string'}, 'country_code': {'type': ['string', 'null'], 'description': "ISO-3166-1 alpha-2 of the posting's own country. Null on almost all of the promoted leg."}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}, 'daily_rate_max': {'type': ['number', 'null']}, 'daily_rate_min': {'type': ['number', 'null'], 'description': 'Only when the source declares a DAILY rate period — never converted from other periods.'}, 'duration_months': {'type': ['number', 'null']}, 'employment_type': {'type': ['string', 'null']}, 'application_link': {'type': ['string', 'null'], 'description': '`public` (source_url is served) or `members_only` (the link to the original listing is the paid Consultant-tier deliverable; the row and its facts stay public).'}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 10, 'maximum': 50, 'minimum': 1, 'description': 'Max rows (hard cap 50).'}, 'query': {'type': 'string', 'maxLength': 200, 'description': 'Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim.'}, 'cursor': {'type': 'string', 'maxLength': 512, 'description': "Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}, 'country': {'type': 'string', 'pattern': '^[A-Za-z]{2}$', 'description': 'ISO-3166-1 alpha-2 country code, e.g. DE, FR, CH.'}, 'product': {'enum': ['datasphere', 'bdc', 'sac', 'bw', 'bw4hana', 's4hana', 'ecc', 'hana', 'joule', 'businessobjects', 'bpc', 'successfactors', 'ariba', 'concur'], 'type': 'string', 'description': 'Keep only end-customers where this SAP product was DETECTED in use. Absence from the result means undetected, not unused.'}, 'industry': {'type': 'string', 'maxLength': 200, 'description': 'Industry or sector filter, matched case-insensitively.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'id': {'type': ['string', 'null']}, 'name': {'type': ['string', 'null']}, 'industry': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'country_code': {'type': ['string', 'null']}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}, 'sap_client_verification_status': {'type': ['string', 'null']}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Module id (`M001`) or slug (`datasphere-foundations`), verbatim from find_academy_modules.rows[].id / .slug.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'id': {'type': ['string', 'null']}, 'slug': {'type': ['string', 'null']}, 'body_en': {'type': ['string', 'null']}, 'title_en': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'objectives_en': {'type': ['array', 'null'], 'items': {'type': 'string'}, 'description': 'Learning objectives, one per element — a text[] column, not a paragraph.'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'required': ['slug'], 'properties': {'slug': {'type': 'string', 'description': 'Concept slug from search_concepts.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'slug': {'type': ['string', 'null']}, 'title': {'type': ['string', 'null']}, 'summary': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'required': ['slug'], 'properties': {'slug': {'type': 'string', 'description': 'Concept slug, verbatim from search_concepts.rows[].slug.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'slug': {'type': ['string', 'null']}, 'body_en': {'type': ['string', 'null']}, 'title_en': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'properties': {'country': {'type': 'string', 'pattern': '^[A-Za-z]{2}$', 'description': 'ISO-3166-1 alpha-2 country code, e.g. DE, FR, CH.'}, 'seniority': {'type': 'string', 'description': 'e.g. senior, principal.'}, 'specialisation': {'type': 'string', 'description': "One of the codes the aggregate actually holds — analytics_all, bw, bw4hana, bw4hana_sac, sac, datasphere (2026-08-09; the live list comes back as `_meta.available_specialisations` on every call). They are NOT evenly spread across countries: DE holds analytics_all only, at three seniorities, and datasphere exists for FR alone, as a median with confidence 'low'. There is no bdc row and no joule row in THIS aggregate — but the platform does price BDC: `find_opportunities` carries a panel-inferred band on the live postings, €1,000–€1,400/day P25–P75 for Senior BDC on 52 German postings (2026-08-10). A code this aggregate does not hold returns 0 rows and the available codes; it never widens to a neighbouring band, and 0 here does not mean the platform is silent."}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'country': {'type': ['string', 'null']}, 'currency': {'type': ['string', 'null']}, 'seniority': {'type': ['string', 'null']}, 'sample_size': {'type': ['integer', 'null']}, 'citation_url': {'type': 'string'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}, 'specialisation': {'type': ['string', 'null']}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'required': ['slug'], 'properties': {'slug': {'type': 'string', 'description': 'The DATABASE slug, taken verbatim from search_firms.rows[].slug. It is not always the web slug in citation_url: a minority of published rows carry a numeric firm id instead (365 of them on 2026-08-09 — the population is read at query time and returned as `_meta.tranche_total_row_count`, never written down here). get_firm{slug:"00393"} is GULP, whose page is /companies/gulp/. Deriving a slug from the citation URL fails on those rows, and deriving it from the NAME is not safe either; carry rows[].slug across instead. A slug this tool refuses is not proof the firm is absent from the market or even from the database — the published tranche is an editorial subset, and a row the editor has not published is refused here exactly as a wrong slug is.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'name': {'type': ['string', 'null']}, 'slug': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'properties': {'mode': {'enum': ['freelance', 'permanent', 'subcontract'], 'type': 'string', 'description': 'Keep only firms whose profile declares this engagement mode (mode_freelance / mode_permanent / mode_subcontract). Same reading as `delivers`: declared-only.'}, 'name': {'type': 'string', 'maxLength': 200, 'description': 'Firm name, matched case-insensitively. Omit to browse the corpus by data completeness.'}, 'limit': {'type': 'integer', 'default': 3, 'maximum': 10, 'minimum': 1, 'description': 'Max rows (hard cap 10 — these rows are wide).'}, 'cursor': {'type': 'string', 'maxLength': 512, 'description': "Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}, 'country': {'type': 'string', 'pattern': '^[A-Za-z]{2}$', 'description': 'ISO-3166-1 alpha-2 country code, e.g. DE, FR, CH.'}, 'delivers': {'enum': ['datasphere', 'bdc', 'sac', 'bw', 'bw4hana', 's4hana', 'ecc', 'hana', 'joule', 'businessobjects', 'bpc', 'successfactors', 'ariba', 'concur'], 'type': 'string', 'description': 'Keep only firms whose profile DECLARES delivery of this product (the `delivers_*` flags every row already carries). An undeclared flag drops the row: absence from the result means the profile does not declare it, not that the firm cannot deliver it.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'name': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}, 'firm_id_unique': {}, 'sap_partner_level': {'type': ['string', 'null']}, 'typical_day_rate_eur': {}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'maxLength': 160, 'description': 'Profile id, verbatim from find_sap_clients.rows[].id.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'id': {'type': ['string', 'null']}, 'name': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}, 'sap_products_used': {}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'required': ['slug'], 'properties': {'lang': {'type': 'string', 'default': 'en', 'pattern': '^[A-Za-z]{2}$', 'description': 'ISO-639-1 language of the edition, e.g. en or fr. Defaults to en.'}, 'slug': {'type': 'string', 'description': 'Study slug, verbatim from list_studies.rows[].slug.'}, 'section': {'type': 'string', 'maxLength': 200, 'description': "A section heading from a previous call's `sections` list. Omit to get the list."}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'slug': {'type': ['string', 'null']}, 'title': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}, 'section_heading': {'type': ['string', 'null']}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'properties': {}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'n': {'type': ['integer', 'null']}, 'kind': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 10, 'maximum': 50, 'minimum': 1, 'description': 'Max rows (hard cap 50).'}, 'cursor': {'type': 'string', 'maxLength': 512, 'description': "Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}, 'country': {'type': 'string', 'pattern': '^[A-Za-z]{2}$', 'description': 'ISO-3166-1 alpha-2 country code, e.g. DE, FR, CH.'}, 'platform_type': {'type': 'string', 'description': 'Restrict to one platform type, lowercase snake_case. The live vocabulary with counts is `_meta.available_platform_types` on every response — a well-formed unknown value returns no rows, it never widens the result.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'name': {'type': ['string', 'null']}, 'slug': {'type': ['string', 'null']}, 'confidence': {'type': ['string', 'null'], 'description': 'Editorial confidence in the signup assessment.'}, 'hq_country': {'type': ['string', 'null']}, 'signup_url': {'type': ['string', 'null'], 'description': "The platform's own signup/profile-creation page, verified on assessed_at."}, 'assessed_at': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'platform_type': {'type': ['string', 'null']}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 10, 'maximum': 50, 'minimum': 1, 'description': 'Max rows (hard cap 50).'}, 'query': {'type': 'string', 'maxLength': 200, 'description': 'Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim.'}, 'cursor': {'type': 'string', 'maxLength': 512, 'description': "Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'code': {'type': ['string', 'null']}, 'category': {'type': ['string', 'null']}, 'label_en': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'properties': {'lang': {'type': 'string', 'pattern': '^[A-Za-z]{2}$', 'description': 'ISO-639-1 language of the EDITION to list, e.g. en, fr or de — each study is published as one row per language. Omit it to see every edition of every study; the live list of languages actually present comes back as `_meta.available_languages` on every response. A well-formed code the corpus does not hold returns 0 rows.'}, 'limit': {'type': 'integer', 'default': 10, 'maximum': 50, 'minimum': 1, 'description': 'Max rows (hard cap 50).'}, 'query': {'type': 'string', 'maxLength': 200, 'description': 'Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim.'}, 'cursor': {'type': 'string', 'maxLength': 512, 'description': "Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'lang': {'type': ['string', 'null']}, 'slug': {'type': ['string', 'null']}, 'as_of': {'type': ['string', 'null']}, 'title': {'type': ['string', 'null']}, 'access': {'type': ['string', 'null']}, 'editions': {'type': ['array', 'null'], 'items': {'type': 'string'}}, 'word_count': {'type': ['integer', 'null']}, 'citation_url': {'type': 'string'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'properties': {'lang': {'type': 'string', 'pattern': '^[A-Za-z]{2}$', 'description': 'ISO-639-1 language for the LABELS — en, fr or de. Defaults to en. The fallback is declared and never silent: the language asked for, then English, then French, and `_meta.label_language_coverage` says on how many nodes each language is actually filled. Concept and module titles carry French; German arrives as the corpus is translated, and an untranslated node falls back rather than being hidden.'}, 'limit': {'type': 'integer', 'default': 10, 'maximum': 50, 'minimum': 1, 'description': 'Max rows (hard cap 50).'}, 'query': {'type': 'string', 'description': "Case-insensitive substring of a node's label. Applies to the NODE listing, not to a walk. Matched against the label SERVED, so it follows `lang`."}, 'cursor': {'type': 'string', 'maxLength': 512, 'description': "Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}, 'node_id': {'type': 'string', 'description': "Fully-qualified node id, `<type>:<id>` — `module:M178`, `concept:C001`, `study:ai-impact-2026-EN`, `vendor:alteryx`. With it, rows are that node's EDGES (one row per neighbour). Without it, rows are NODES."}, 'direction': {'enum': ['from', 'to', 'both'], 'type': 'string', 'description': 'Which side of the edge `node_id` must sit on. Default `both`. Ignored without `node_id`, and the response says so rather than pretending it applied.'}, 'edge_type': {'type': 'string', 'description': 'Restrict a walk to one relation. The served projection carries FIVE — teaches · taught_by · covers · related · mentions — and this list is a HINT, not the authority: read `_meta.available_edge_types`, computed on every call. A four-name list stood here while the projection served five, so `mentions` was reachable and undocumented.'}, 'node_type': {'type': 'string', 'description': 'Restrict to one carried node type: concept · module · study · vendor. Read `_meta.available_node_types`.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'label': {'type': ['string', 'null'], 'description': 'In the language asked for when the node carries it, else the declared fallback — see `label_lang`.'}, 'node_id': {'type': ['string', 'null']}, 'direction': {'type': ['string', 'null'], 'description': '`out` = node_id → neighbour, `in` = neighbour → node_id. Walk rows only.'}, 'edge_type': {'type': ['string', 'null'], 'description': 'Present only on a walk (when `node_id` was given).'}, 'node_type': {'type': ['string', 'null']}, 'label_lang': {'type': ['string', 'null'], 'description': 'The language the served `label` is actually written in. It differs from the requested `lang` exactly when that translation does not exist.'}, 'citation_url': {'type': 'string'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 10, 'maximum': 50, 'minimum': 1, 'description': 'Max rows (hard cap 50).'}, 'query': {'type': 'string', 'maxLength': 200, 'description': 'Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim.'}, 'cursor': {'type': 'string', 'maxLength': 512, 'description': "Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}, 'category': {'type': 'string', 'description': 'Concept category, matched case-insensitively as an exact value OR a prefix — so category:"datasphere" reaches \'Datasphere Core\'. The values are long human labels, not codes. DO NOT GUESS THEM FROM THIS TEXT: the live vocabulary with a row count per label comes back as `_meta.available_categories` on EVERY call, including a call that matched nothing. A list written here would say 14 labels with 2026-07-30 counts; the corpus holds 15 today, and five of those counts have moved. Read the envelope, not the prose.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'slug': {'type': ['string', 'null']}, 'title': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'properties': {'kind': {'enum': ['agency_placement', 'professional_services_big4', 'professional_services_esn', 'vendor_sap', 'vendor_partner', 'platform_marketplace', 'community_group', 'client_enterprise', 'other'], 'type': 'string', 'description': 'Restrict to one organisation kind. This list is the vocabulary the corpus holds today, not a frontier — call list_firm_kinds for the live one. A malformed code is refused; a well-formed code the corpus does not hold returns no rows. Neither case is silently ignored, and neither widens the result.'}, 'limit': {'type': 'integer', 'default': 10, 'maximum': 50, 'minimum': 1, 'description': 'Max rows (hard cap 50).'}, 'query': {'type': 'string', 'maxLength': 200, 'description': 'Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim.'}, 'cursor': {'type': 'string', 'maxLength': 512, 'description': "Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}, 'module': {'type': 'string', 'description': 'Restrict to organisations with a DECLARED link to one SAP module/product code (UPPERCASE snake_case, e.g. DATASPHERE, BDC, SAC, BW4HANA, S4HANA, JOULE — case-insensitive on input). The declared links are structured data, far more selective than free text: `count_firms_by {by:"module"}` gives the live vocabulary with counts. A minority of the directory declares any module at all, so this filter finds the DECLARED specialists — absence from the result means no declared link, never that the firm does not work on the module.'}, 'country': {'type': 'string', 'pattern': '^[A-Za-z]{2}$', 'description': 'ISO-3166-1 alpha-2 country code, e.g. DE, FR, CH.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'kind': {'type': ['string', 'null']}, 'name': {'type': ['string', 'null']}, 'slug': {'type': ['string', 'null']}, 'claim': {'type': ['string', 'null']}, 'region': {'type': ['string', 'null']}, 'hq_city': {'type': ['string', 'null']}, 'website': {'type': ['string', 'null']}, 'jobs_url': {'type': ['string', 'null']}, 'hq_country': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'founded_year': {'type': ['integer', 'null']}, 'size_bracket': {'type': ['string', 'null']}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}, 'sap_signal_band': {'type': ['string', 'null']}, 'last_verified_at': {'type': ['string', 'null']}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 10, 'maximum': 50, 'minimum': 1, 'description': 'Max rows (hard cap 50).'}, 'query': {'type': 'string', 'maxLength': 200, 'description': 'Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim.'}, 'cursor': {'type': 'string', 'maxLength': 512, 'description': "Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}, 'category': {'type': 'string', 'description': "Category code, matched case-insensitively. The live vocabulary is NOT written here — read `_meta.available_categories` on any response: every category label this corpus holds right now, with its active-row count, counted at query time. A written list held 21 values while the corpus held 22. One bucket needs a warning. 'SAC' is the noisiest label in this corpus because the acronym collides with unrelated ones — Windows 'Smart App Control', and the surname 'Sacks'. A 2026-07-30 cleanup reclassified half that bucket to AI for carrying no SAP signal at all; the collision pressure is structural and the bucket has kept growing since. For genuine SAC product news, pair category:'SAC' with query:'analytics cloud'."}, 'published_since': {'type': 'string', 'description': 'Lower bound on `published_at`, inclusive, as YYYY-MM-DD. Without a bound a period question is only answerable by walking pages — and `_meta.match_count` then counts the QUERY, not the period, so any figure quoted for the window would be wrong.'}, 'published_until': {'type': 'string', 'description': 'Upper bound on `published_at`, INCLUSIVE of the day named, as YYYY-MM-DD. Combine with `published_since` for a window; `_meta.match_count` then describes that window, which is what makes it quotable.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['tool', 'result_count', 'rows', '_attribution'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'properties': {'title': {'type': ['string', 'null']}, 'source_url': {'type': ['string', 'null']}, 'source_name': {'type': ['string', 'null']}, 'citation_url': {'type': 'string'}, 'published_at': {'type': ['string', 'null']}, 'citation_scope': {'enum': ['record', 'section_hub'], 'type': 'string'}}}}, 'tool': {'type': 'string'}, '_meta': {'type': 'object'}, '_attribution': {'type': 'string'}, 'result_count': {'type': 'integer'}}}
Recent tool changes
Similar MCP servers
AdAdvisor MCP Server
Manages Meta advertising campaigns, creatives, audiences, lead forms, budgets, statuses, and performance reporting.
enforcement-database
Searches and retrieves FDA enforcement records, including warning letters, recalls, approvals, and 483 citations.
AI-Portal Enterprise GenAI Briefing
Provides current GenAI news, model release tracking, AI glossary searches, and information on AI regulations and compliance requi…
GroundTruth - Environmental Records
Retrieves environmental, infrastructure, hazard, and address due-diligence records for locations in the United States.
Business Contact Finder
Checks a business website to identify reachable contact methods, including forms, phone numbers, and email addresses, without sub…
CounterScript - Drug Price Benchmarks
Provides US drug acquisition benchmarks, estimated cash-price ranges, generic equivalents, and applicable Medicare negotiated pri…
AI-Advisors
Provides read-only AI search visibility data, including citations, answer-engine optimization audits, and advisor insights.
AgentUtility Web Probe
Provides access to a pay-per-call web-probe tool cluster, although the specific web capabilities are not listed.