Skip to main content
Glama

Analytics Legends — SAP AI & Analytics MCP Server

Server Details

SAP AI & analytics market data for agents: SAP firms, day rates, jobs, Joule & BDC news

Ownership verified
Status
Healthy
Uptime
100.0% over 83 days
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL
Repository
analyticslegends/analytics-legends-mcp
GitHub Stars
0
Server Listing
ai.analyticslegends/sap-analytics
ChatGPT
–
Claude
–

TDQS

A3.9/5.0

Scored across 23 tools

Disambiguation3/5

Several tool families crowd the same population: search_firms, find_partner_candidates, list_firm_kinds, count_firms_by, get_firm and get_firm_intel all read the firm directory, and search_concepts / get_concept / get_concept_card plus find_academy_modules / get_academy_module / list_sap_modules overlap heavily on one noun each. The descriptions do a lot of explicit disambiguation work ("DO NOT CONFUSE IT WITH list_sap_modules"), and the paid/free split gives most pairs a real boundary, but the volume of near-duplicate surface makes misselection plausible without careful reading.

Naming Consistency4/5

Names are uniformly snake_case and verb-first (find_*, get_*, list_*, search_*, query_*), with verbs that carry semantic weight rather than being decorative. Minor deviations: count_firms_by ends in a dangling preposition with no stated dimension, and find_answers is a verb_noun name whose noun is a response shape rather than a resource.

Tool Count4/5

23 tools is on the heavy side, but the server spans genuinely distinct corpora — firms, end-customers, academy modules, concepts, studies, news, opportunities, rates, taxonomy and a graph. Each tool maps to a different dataset or a different access tier, so few look redundant in principle, though the firm-directory cluster could be compressed.

Completeness4/5

Search-plus-get pairs exist for firms, clients, concepts, academy modules, studies and the graph, with counting, taxonomy and benchmark tools filling analytical needs — a coherent read-oriented lifecycle. Gaps are minor: news and opportunities have no single-item detail tool (both fall back to upstream citation URLs), and study/concept discovery is browsing-oriented rather than searchable by topic.

Available Tools

23 tools
count_firms_byCount the firm directory by country, region, kind, module or SAP signalA
Read-onlyIdempotent
Inspect

Answer a COUNTING question about the published firm directory in one call: how many organisations per country, per REGION (the six-value geography), per kind, per declared SAP module, or per SAP signal band — with the same country/kind/module/query filters search_firms takes, so you can count a slice as easily as the whole. Use this instead of paging search_firms and tallying rows: the directory holds thousands of organisations, and reading them all to produce a table of counts costs hundreds of calls and megabytes of rows for numbers Postgres computes in one scan. Every bucket is a value the directory actually stores; value: null is a real bucket meaning the field is unknown for those rows, and it is served rather than hidden — a country table that silently drops the rows with no country adds up to less than the population and says nothing about it.

NameRequiredDescriptionDefault
byYesWhich facet to count on. Required — there is no default worth guessing.
kindNoRestrict to one organisation kind before counting, same vocabulary as search_firms. Combining it with `by:"kind"` is legal and returns that single bucket.
queryNoFree-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.
moduleNoRestrict 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).
regionNoRegion code of the HQ country — the platform's six-value geography: EMEA (Europe AND the Middle East), AMER (North America), LATAM, APAC, AFRICA (its own region, not folded into EMEA), GLOBAL (country unknown). Case-insensitive on input; anything else is refused.
countryNoISO-3166-1 alpha-2 country code, e.g. DE, FR, CH.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already cover readOnly/idempotent/non-destructive, but the description adds real behavior the agent could not infer: `value: null` is a served bucket meaning the field is unknown, and dropping it would silently under-count the population. This is exactly the kind of non-obvious trait worth disclosing.

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?

Purpose and the search_firms contrast are front-loaded, and the null-bucket caveat is a worthwhile final sentence. The prose is dense with em-dashes and long clauses, so it is slightly heavier than needed, but no sentence is filler.

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?

For a six-parameter aggregation tool with full schema coverage, an output schema, and safety annotations, the description supplies the remaining decision-relevant context (when to use it, how nulls are handled). Nothing needed to call it correctly is missing.

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?

Schema coverage is 100%, so the baseline is 3, but the description adds legitimate meaning: filters reuse search_firms' vocabulary, `by` has no safe default, and the null bucket semantics affect how filter results should be read. It does not restate the enum values.

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?

States a specific verb ('Answer a COUNTING question') and resource ('the published firm directory') and enumerates the five facets counted. It explicitly distinguishes itself from search_firms, so an agent can route without opening either schema.

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 names the alternative ('Use this instead of paging `search_firms` and tallying rows') and gives the condition that selects this tool (directory holds thousands of orgs; reading all rows costs hundreds of calls). Also notes the filters mirror search_firms' vocabulary.

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

find_academy_modulesSearch the Academy training catalogueA
Read-onlyIdempotent
Inspect

Search the Analytics Legends Academy — the written training modules on SAP Datasphere, Business Data Cloud, SAP Analytics Cloud, BW/4HANA and Databricks — by track, level and free text. _meta.tranche_total_row_count carries the live catalogue size on every call; it is the only count to quote. Returns the catalogue entry: id, slug, EN/FR title, track, level, duration in minutes, tags and the editor's summary. DO NOT CONFUSE IT WITH list_sap_modules, which serves a different population under the same word: that one is the 40-row PRODUCT taxonomy (codes such as SAC, DATASPHERE) used to normalise product wording. This one is the course catalogue. Without query, rows come back in the catalogue's own CURRICULUM order — the order a reader is meant to take them in — track by track. This catalogue is written training, NOT SAP certification tracks: this server publishes no certification data at any tier, so a certification question has no answer here rather than a partial one. CATALOGUE ONLY — the module BODY is subscriber content, served by get_academy_module on this same endpoint with an API key of an MCP Pass or Firm account. On THIS endpoint the paid tranche is opened by the MCP Pass (€29.90/month, analyticslegends.ai/mcp-server/) or the Firm Pass, from one key; the Consultant and Legend web plans do not include MCP access. status and is_preview are SERVED, never filtered on: they are the two flags the WEBSITE marks free access with (a free analyticslegends.ai account reads those modules on the site, M001 Datasphere Foundations included), NOT a free lane of this server — get_academy_module requires an MCP Pass or Firm Pass key for every module (a free account's key gets only the fixed daily showcase). They do not coincide (measured 2026-08-16: 38 rows status='available', 56 rows is_preview), and you decide which one your answer needs. PAGINATED WITH A KEY (a free one is enough): pass _meta.next_cursor back as cursor with the same filters until it is null; without a key, first 10 rows only. Read _meta.available_tracks and _meta.available_levels — both counted on the served population at call time — before assuming a facet value exists.

NameRequiredDescriptionDefault
levelNoRestrict to one level, matched case-insensitively: Beginner · Intermediate · Advanced · Expert. Counts in `_meta.available_levels`.
limitNoMax rows (hard cap 50).
queryNoFree-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.
trackNoRestrict 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.
cursorNoOpaque 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.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare a safe read-only, idempotent, closed-world operation and the description does not contradict them. Beyond that it discloses genuinely non-obvious behaviour: curriculum ordering when `query` is omitted, `status`/`is_preview` being served rather than filtered (with measured counts showing they diverge), and that pagination requires a key. The heavy commercial framing about the €29.90 pass dilutes this slightly but the behavioural content is substantial.

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

Conciseness3/5

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

Core distinction and pagination rules are front-loaded, but the block is long and crowded with ALL-CAPS warnings, pricing tiers and dated measurement asides that don't help an agent invoke the tool. Several sentences could be cut without losing invocation-relevant information.

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?

An output schema exists, yet the description still summarises returned fields and, more importantly, covers pagination, key requirements, ordering defaults and facet discovery — the aspects an agent must know to call it correctly. Nothing operationally necessary appears missing for a five-parameter catalogue search.

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?

Schema coverage is 100%, so the schema already documents each parameter, but the description adds meaning beyond it: omitting `query` yields curriculum order rather than an arbitrary listing, and the agent is told to consult `_meta.available_tracks`/`_meta.available_levels` before assuming a facet exists — compensating for the zero enums. Some of the track slug/name and cursor rules merely restate 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 opens with a specific verb and resource — 'Search the Analytics Legends Academy ... by track, level and free text' — and enumerates the subject domains covered. It then explicitly contrasts itself with `list_sap_modules`, so an agent can distinguish the course catalogue from the product taxonomy without opening either schema.

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?

It gives explicit routing rules: use `list_sap_modules` for the 40-row product taxonomy, `get_academy_module` for module bodies, and this tool for catalogue entries. It also states exclusions ('no certification data at any tier') and pagination conditions ('without a key, first 10 rows only'), leaving little to inference.

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

find_answersFind the answer to an SAP AI & analytics problemA
Read-onlyIdempotent
Inspect

Start here when someone asks about an SAP AI & analytics PROBLEM rather than a term. Matches a natural question, in English, French or German, to the twelve ranked challenges Analytics Legends tracks: agents in production, Joule value, AI cost, AI-ready data, on-premise reach, the open ecosystem, the BW cliff, BDC versus Datasphere versus Databricks, staffing, roadmap volatility, EU compliance, end of BI 4.3. Returns at most three rows: the short answer, what shipped, what is announced, what slipped or is unconfirmed, facts outside the status registry with their source and quality, next steps, review date and citation_url. Statuses are read from the SAP announcement registry; a date is a plan, not a commitment. An empty result means the question is outside these challenges: say so and use search_concepts, find_academy_modules or get_day_rate_benchmark.

NameRequiredDescriptionDefault
langNoLanguage of the answer. Omit it to answer in the language detected from the question, EN, FR or DE.
audienceNoWho is asking. It only reorders challenges that already matched, it never adds one.
questionYesThe question as the person asked it, in English, French or German. Full sentences match best.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, but the description adds real behavioral context: at most three rows, the status source (SAP announcement registry), the caution that 'a date is a plan, not a commitment', and the meaning of an empty result. Enumerating the returned fields overlaps the output schema somewhat, but the plan-vs-commitment caveat is information no structured field carries.

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 trigger condition is front-loaded and the fallback guidance is placed at the end where it belongs. The middle enumerations (twelve challenges, returned columns) are dense and border on schema duplication, but they earn their place by letting the agent judge in-scope vs out-of-scope questions without a second call.

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?

For a read-only search tool with a full output schema, the description covers the trigger, the domain scope, the ranking model, the status provenance, the empty-set behavior and the redirect targets. Nothing material an agent needs to decide whether and how to call it is missing.

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 100%, so the schema already documents question, lang and audience, including the enums and the 'full sentences match best' hint. The description reinforces the EN/FR/DE matching scope, which ties to lang, but says nothing about the audience enum or that it only reorders already-matched challenges — that nuance lives only in the schema. Baseline 3 is appropriate.

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?

A specific verb and resource: it matches a natural-language question to twelve named, ranked challenges, and enumerates them (agents in production, Joule value, the BW cliff, EU compliance, etc.). It explicitly contrasts itself with term lookup ('rather than a term'), which separates it from search_concepts and get_concept_card among the siblings.

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?

'Start here when someone asks about an SAP AI & analytics PROBLEM rather than a term' gives an explicit entry condition and an exclusion. The empty-result case is handled with concrete alternatives: search_concepts, find_academy_modules, get_day_rate_benchmark, so the agent knows where to route a miss.

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

find_opportunitiesSearch the public SAP AI & analytics contract radarA
Read-onlyIdempotent
Inspect

Search every SAP contract and permanent-role posting Analytics Legends publishes to an ANONYMOUS visitor. Only the SITE RADAR leg below is the population a human browses on /opportunities/, where each of its postings has its own prerendered page; the PROMOTED leg is served to agents only — it is not listed on /opportunities/ and its rows have no page of their own (citation_scope "section_hub"). It merges the platform's TWO public legs, which are near-disjoint (measured 2026-07-30: 1 row in common): (a) the PROMOTED feed (public.public_opportunities) — general SAP work (FI/CO, SD, EWM, MDG, BTP, ABAP), all German cities, dated (posted_at is populated on all but a few % of the live rows of that leg — the undated rows are sorted LAST and paginate like the others). 🔴 THIS LEG CHANGED SHAPE ON 2026-08-28: until then it was fed by three keyless APIs and carried no contract_type, country_code, expires_at or rate at all; it was then loaded from the site radar and now declares contract_type and country_code on most of its rows, an expiry on most, and an advertised rate on a small minority. Do NOT assume a field is null on this leg — read the _meta counters on YOUR OWN response, which are computed at query time; (b) the SITE RADAR (/api/contracts-lean.json) — these carry country, category, seniority, posted_at, employment_type and, on most of them, expires_at; they are the analytics-specific ones (SAC Planning, Datasphere Technical Lead, Business Data Cloud). READ employment_type BEFORE CALLING THIS A CONTRACT MARKET: the radar is mostly PERMANENT roles, so an unfiltered page answers a freelance question with salaried jobs unless you filter. The argument of the same name does the filtering, and _meta.tranche_total_row_count on your own response is the live population — read the split from a filtered call, never from a figure quoted in this text. TWO DIFFERENT RATE FIELDS, AND THEY MEAN DIFFERENT THINGS. currency / daily_rate_min / daily_rate_max are the posting's OWN advertised rate and are almost always null — most listings publish no rate at all. rate_band is the platform's editorial benchmark for that posting's (seniority × product × region) cell. It is a SUBSCRIBER surface of the WEBSITE, not of this server: the radar file this server reads carries no band since 2026-08-29, so rate_band is null on EVERY row here, with or without a key (each response's _meta.rate_band_coverage counts it). The panel grid itself covers European cells only — DACH, FR/Benelux, UK/IE, Southern EU, Eastern EU, Nordics — so a posting in the Americas, APAC, Africa or the Middle East has no band at ANY tier: never promise one for it. It is rate_basis: "panel_inferred" — Eursap n=312 plus the Analytics Legends operator panel, permanent rows restated as a TJM equivalent at ~220 billable days a year — NOT a rate this employer offered. Quote it as a band with its basis, kind and source, never as the posting's rate, and never average bands across postings: many rows share one cell. WHAT IS GATED IS A FIELD, NOT A ROW: on most radar rows source_url is null and application_link reads "members_only" — the verified link to the original listing is the paid deliverable (MCP Pass or Firm Pass key). Everything else about the posting is public, and citation_url is that posting's own page on analyticslegends.ai. Quote it. Report _meta.tranche_row_count as the published public population, never as the size of the market.

NameRequiredDescriptionDefault
langNoReading 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 (the live FR/DE coverage is counted on every response in `_meta.untranslated_leg`), 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`.
limitNoMax rows (hard cap 50).
queryNoFree-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.
cursorNoOpaque 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.
countryNoISO-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.
locationNoCity 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.
eligibilityNoWHO MAY APPLY to a remote posting, read from the posting's own text: `open` (it explicitly opens the role across borders — worldwide, anywhere, a time-zone band such as EMEA/CET hours, nearshore welcome), `restricted` (it requires residence, citizenship, work authorisation, a clearance or US W-2 status somewhere, or scopes the remote work to a region — `eligibility_region` on the row names it when stated), `unstated` (it says nothing). Combine with remote_mode="remote" for the contractor abroad. AN UNSTATED ROW IS NOT AN OPEN ROW: most remote postings say nothing about where the contractor may be, so `open` sets them aside and `_meta.eligibility_undeclared` counts how many remote rows THIS call read are silent. Classified deterministically from title, location and (promoted leg) description; the site-radar leg publishes no description, so its rows are mostly `unstated`.
remote_modeNoRestrict 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_typeNoRestrict 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 rows THIS call read (`_meta.employment_mix_rows_read` — a window, NOT the tranche: `_meta.tranche_total_row_count` is the population) and either alone is not even that. Read both before quoting a mix, and quote the window with it.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A3.9/5.0
Behavior5/5

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

Annotations already cover read-only/idempotent safety, yet the description adds genuinely non-obvious behavior: source_url is null and application_link reads "members_only" on most rows (gating a field, not a row), rate_band is null on every row because the radar file stopped carrying it, and rate_basis semantics for panel_inferred bands. It also warns that _meta counters must be read at query time rather than trusting figures in the text — high-value disclosure beyond structured data.

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

Conciseness2/5

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

Purpose is front-loaded, but the body sprawls into dated measurements, change-log narration ("THIS LEG CHANGED SHAPE ON 2026-08-28"), and self-referential instructions about what not to quote from this very text. Several sentences instruct the agent about phrasing rather than describing the tool, which is padding that makes the actionable content harder to extract.

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?

An output schema exists, so return values need not be explained, and the description nonetheless documents the key _meta counters an agent must consult. Complete for calling correctly, though the sheer volume of volatile detail (specific counts, dates) risks going stale and misdirecting an agent that trusts the prose over its own response.

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 100% and the enum/parameter descriptions in the schema are themselves extensive, so the description body largely restates parameter semantics rather than adding to them. Baseline 3 applies; the marginal additions (leg-level null assumptions for country and employment_type) are already present in the parameter descriptions.

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

Purpose4/5

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

The opening states a specific verb and resource (search SAP contract and permanent-role postings) and explicitly separates the two legs being merged (PROMOTED feed vs SITE RADAR). The core purpose is unambiguous but is buried under several paragraphs of caveats and dated change history, so an agent gets the what-it-does only after wading through the how-it-behaves.

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?

Gives explicit conditional guidance: read employment_type before treating this as a contract market, combine eligibility with remote_mode="remote" for the contractor abroad, and note that unfiltered pages answer freelance questions with salaried jobs. It does not say when to use this tool instead of the sibling tools (e.g., get_day_rate_benchmark, search_firms), so sibling routing is left implicit.

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

find_partner_candidatesLocal partner or acquisition candidates for a market entry (MCP Pass)A
Read-onlyIdempotent
Inspect

Rank the LOCAL service providers of a target country or region — the firms a practice partners with, subcontracts to, or acquires to enter a market. local_only (default true) keeps firms with NO sister entity in another country (read from the brand-family key of the SSOT): a subsidiary of a global group is a competitor, not a partner. Filter by kind and by DECLARED SAP module; rows carry the declared modules, the sister countries of the brand (when any), the count of declared partnerships and the public directory fields. Ordered by SAP signal, then data completeness. country or region is required: a partner search without a target market is the whole directory. Paginated by cursor. Requires the API key of an MCP Pass or Firm account (the Consultant and Legend web plans do not include MCP access). No person, no e-mail — outreach details stay behind the platform's signed-URL path.

NameRequiredDescriptionDefault
kindNoRestrict to one provider kind (placement agencies, ESN/SI practices, Big-4, SAP partners, platforms). SAP's own entities, communities, schools and public bodies are never in this population.
limitNoMax rows (hard cap 50).
cursorNoOpaque 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.
moduleNoRestrict to firms with a DECLARED link to one SAP module code (UPPERCASE snake_case, e.g. DATASPHERE, BDC, SAC — call count_firms_by {by:"module"} for the live vocabulary). Absence means no declared link, never incapacity.
regionNoRegion code of the HQ country — the platform's six-value geography: EMEA (Europe AND the Middle East), AMER (North America), LATAM, APAC, AFRICA (its own region, not folded into EMEA), GLOBAL (country unknown). Case-insensitive on input; anything else is refused.
countryNoISO-3166-1 alpha-2 country code, e.g. DE, FR, CH.
local_onlyNotrue (default): only firms with no sister entity abroad. false: every provider of the market, groups included.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.6/5.0
Behavior5/5

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

Well beyond the annotations (which already establish a safe, idempotent read), the description discloses access prerequisites ('Requires the API key of an MCP Pass or Firm account — the Consultant and Legend web plans do not include MCP access'), the return row shape, cursor pagination, and an explicit privacy boundary ('No person, no e-mail'). These are the operational facts an agent needs before calling.

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?

Material is front-loaded: population, then the local_only rationale, then filters, output, ordering, constraints, auth. Some phrasing is dense and parenthetical (e.g. 'read from the brand-family key of the SSOT'), slightly taxing on first read, but every sentence carries distinct information.

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?

For a 7-parameter, cursor-paginated read tool with an output schema and rich annotations, nothing an agent needs is missing: target-market requirement, filter semantics, ordering, pagination, auth, and what the rows contain. Sibling tools and an output schema cover the rest.

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?

Schema coverage is 100%, so the baseline is 3, but the description adds real semantics: the country/region gating that the schema does not enforce (zero required parameters), the cursor's 'same filter arguments' contract, and the ranking order by SAP signal then completeness. Some repetition of the schema's declared-module and sister-country wording keeps it from a 5.

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?

Opens with a specific verb and a precisely bounded population: 'Rank the LOCAL service providers of a target country or region — the firms a practice partners with, subcontracts to, or acquires to enter a market.' The local_only contrast ('a subsidiary of a global group is a competitor, not a partner') makes it unmistakable against broader firm-search siblings such as search_firms or find_sap_clients.

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?

Explicit about the mandatory context — '`country` or `region` is required: a partner search without a target market is the whole directory' — and about the local_only toggle's intended meaning. It even routes to count_firms_by for the module vocabulary. It stops short of naming a specific sibling it should be preferred over, so it is clear context rather than full alternative routing.

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

find_sap_clientsSearch the SAP end-customer corpus (MCP Pass)A
Read-onlyIdempotent
Inspect

Search the SAP END-CUSTOMER corpus — the companies that RUN SAP, not the firms that sell services (those are search_firms). This is the paid Legend+ dataset locked away from the public surface on 2026-07-08; it requires the API key of an MCP Pass or Firm account. Verification status is SERVED, never silently filtered: sap_client_verification_status and status are columns on every row ('verified' on a few hundred of ~15k rows — the exact counts are in _meta on every call, never in this text), and you decide what standard of proof your answer needs. product filters on the detected-adoption flags every profile already carries (the uses_* columns get_sap_client_profile serves): it keeps only rows where that product was DETECTED. A row it drops is 'not detected by our detection pass', never 'does not use it' — detection is a positive signal with no negative counterpart.

NameRequiredDescriptionDefault
limitNoMax rows (hard cap 50).
queryNoFree-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.
cursorNoOpaque 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.
countryNoISO-3166-1 alpha-2 country code, e.g. DE, FR, CH.
productNoKeep only end-customers where this SAP product was DETECTED in use. Absence from the result means undetected, not unused.
industryNoIndustry or sector filter, matched case-insensitively.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already cover safety (readOnly, idempotent, non-destructive, closed-world), but the description adds substantial context they cannot: paid-tier auth requirement, the 2026-07-08 lock date, that verification status is served as columns rather than silently filtered, and that per-call counts live in _meta. The product-detection caveat (a dropped row means 'not detected', never 'does not use it') is exactly the kind of behavioral nuance an agent would otherwise misreport.

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?

Front-loaded with the core differentiator (end-customers vs. firms) and dense throughout, with no filler sentences. A few editorial asides ("never in this text", the exact lock date) are slightly verbose but each still carries routing or trust information.

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?

With an output schema present, return shape and pagination need not be described, and annotations cover safety. The description fills the remaining gaps an agent actually needs: access tier, verification-status handling, and the asymmetry of product detection. Nothing required to call it correctly is missing.

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?

Schema coverage is 100%, so this is already baseline 3; the description earns extra by explaining that `product` filters on positive detection flags only, that a dropped row means 'not detected by our detection pass', and that the flags correspond to uses_* columns served elsewhere. Query/cursor/country semantics stay with the schema, which handles them well.

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?

States a specific verb and resource ("Search the SAP END-CUSTOMER corpus") and immediately disambiguates the exact noun that could confuse an agent: the companies that RUN SAP, not firms that sell services. It names the sibling it is not (search_firms) and the detail tool it complements (get_sap_client_profile), so it is distinguishable without opening any schema.

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 routes firm/vendor lookups to search_firms and states the access precondition (API key of an MCP Pass or Firm account, paid Legend+ dataset). It stops short of stating when to prefer get_sap_client_profile over this list tool, or when not to search at all (e.g. tiny result sets vs. bulk export), so it is strong but not complete routing guidance.

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

get_academy_moduleRead an Academy module (MCP Pass)A
Read-onlyIdempotent
Inspect

Read one Academy training module in full — body, learning objectives and summary, EN, FR and DE — the written course corpus the Consultant web plan sells. Modules marked free on the website (M001 Datasphere Foundations included) are free to read THERE with a free account; on this endpoint they are served like every other module, with an MCP Pass or Firm Pass key. A free account's key gets only the daily taste: the fixed showcase modules that an unfiltered find_academy_modules call serves first, the same for every account. On THIS endpoint the paid tranche is opened by the MCP Pass (€29.90/month, analyticslegends.ai/mcp-server/) or the Firm Pass; the Consultant and Legend web plans do not include MCP access. Requires an API key of an MCP Pass or Firm account (Authorization: Bearer alk_…); without one this tool refuses and find_academy_modules keeps serving the catalogue. Takes the module id (M001) or its slug (datasphere-foundations), both matched case-insensitively — find_academy_modules returns both on every row, and query_knowledge_graph returns the same ids as module:M001 node ids, so a graph walk now ENDS somewhere. The module is served in one call. lang (en · fr · de) returns that language only; without it the three languages come back together — EXCEPT when the three would exceed the response ceiling (the Datasphere foundations course M001, rewritten as a full training on 2026-10-28, weighs 423 KB in three languages): the English text is then served alone and filters.lang says so — call again with lang=fr or lang=de for the other two.

NameRequiredDescriptionDefault
idYesModule id (`M001`) or slug (`datasphere-foundations`), verbatim from find_academy_modules.rows[].id / .slug.
langNoServe this language only. Omit it to get all three, unless they would exceed the response ceiling — then English alone is served and filters.lang says so.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.7/5.0
Behavior5/5

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

Beyond the readOnly/idempotent annotations, it discloses the auth scheme (Bearer alk_…), the refusal behavior without a valid pass key, the entitlement split between web plans and MCP access, and the response-ceiling fallback where English is served alone with a `filters.lang` marker for oversized modules like M001. These are operational facts an agent cannot infer from structured fields.

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

Conciseness3/5

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

The critical facts (what is read, key requirement, id/slug, lang fallback) are front-loaded, but the prose is padded with marketing and pricing asides ('the written course corpus the Consultant web plan sells', €29.90/month, 'so a graph walk now ENDS somewhere'). Several clauses could be trimmed without losing callable information.

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?

For a two-parameter read tool with an output schema and full annotation coverage, nothing needed to call it correctly is missing: entitlement rules, auth header, id provenance, language behavior and the oversized-response fallback are all covered.

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?

Schema coverage is 100%, so the baseline is 3; the description nevertheless adds value by stating that `id` accepts an id or slug matched case-insensitively and where those values come from (`find_academy_modules.rows[]`, graph `module:M001` nodes). It also explains the `lang` omission behavior and the ceiling fallback that the schema mentions only briefly.

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?

Opens with a specific verb and resource — 'Read one Academy training module in full' — and enumerates what is returned (body, learning objectives, summary, EN/FR/DE). It is clearly distinguished from the sibling 'find_academy_modules', which is named as the catalogue-listing counterpart.

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 states when this tool is needed versus the alternatives: free-account users get only the showcase modules via `find_academy_modules`, while the full paid tranche requires an MCP Pass or Firm Pass key on this endpoint. It also names the condition under which a graph walk terminates here (`query_knowledge_graph` returns `module:M001` ids).

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

get_conceptConcept metadata and editor's summary (public)A
Read-onlyIdempotent
Inspect

Fetch one concept entry by slug: title, category, level, tags and the editor's summary. Written by a named human editor, not generated. level is GRADED on every active row since 2026-09-18 (the CHECK constraint accepted only the legacy vocabulary OR NULL, so the loader wrote NULL rather than fail; 108 of 330 were blank). A null, if one ever returns, means 'not graded', never 'Beginner'. The card body, cheat sheet, glossary, pro tip and the four analysis tables are subscriber content and are NOT returned. Why-it-matters and key points are not returned here either, but they ARE published in full on the concept page at citation_url — follow the URL for those.

NameRequiredDescriptionDefault
slugYesConcept slug from search_concepts.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.6/5.0
Behavior5/5

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

The description adds significant behavioral context beyond annotations: it explains the level grading history (NULL meaning 'not graded', never 'Beginner'), the fact that content is human-edited, and the exact handling of null values. This goes well beyond the readOnlyHint and idempotentHint annotations, giving the agent critical interpretation guidance. No contradiction with annotations.

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 structured with the primary purpose first, followed by important data-quality caveats and exclusion lists. Each sentence adds necessary information, and the length is justified given the complexity of the null handling and the need to clarify what is not returned. It is slightly longer than typical but well-organized.

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 the output schema exists (per signal), the description sufficiently covers what an agent needs: the parameter, the returned fields, the null semantics, and the alternative for missing content. The caveat about subscriber content and the citation_url are crucial for correct usage. No gaps that would prevent a correct call.

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?

The schema covers 100% of the single parameter (slug) with a description referencing search_concepts. The tool description adds no new meaning beyond what the schema already provides, so a baseline of 3 is appropriate. The description merely restates 'by slug' without elaborating on format or constraints.

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 fetches a single concept entry by slug and lists the returned fields (title, category, level, tags, editor's summary). It distinguishes from siblings like get_concept_card and search_concepts by explicitly noting what it does not return (card body, cheat sheet, etc.) and where to find that content, making the tool's purpose unambiguous.

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 this tool: it returns only public metadata and the editor's summary. It explicitly lists what is NOT returned (subscriber content, why-it-matters, key points) and instructs the agent to follow the citation_url for the full page, effectively directing to alternatives. This is clear exclusions and routing.

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

get_concept_cardFull concept card (MCP Pass)A
Read-onlyIdempotent
Inspect

The FULL encyclopaedia card for one concept — body, cheat sheet, glossary, pro tip, and the four analysis tables (decision table, peer comparison, named pitfalls, performance facts), EN, FR and DE, plus why-it-matters and key points (those two are also published free on the concept page; here they come structured, in three languages, in the same payload) — the corpus the Consultant web plan sells. On THIS endpoint the paid tranche is opened by the MCP Pass (€29.90/month, analyticslegends.ai/mcp-server/) or the Firm Pass, from one key; the Consultant and Legend web plans do not include MCP access. Requires the API key of an MCP Pass or Firm account (Authorization: Bearer alk_…) — the Consultant and Legend web plans do not include MCP access; without one this tool refuses and get_concept keeps serving the public metadata. Find slugs with search_concepts.

NameRequiredDescriptionDefault
slugYesConcept slug, verbatim from search_concepts.rows[].slug.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.5/5.0
Behavior5/5

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

Adds substantial behavior beyond the read-only, idempotent annotations: paid access gating, required Bearer key, refusal behavior, and the exact premium content returned in EN/FR/DE. The annotations already cover safety, and the description adds the access and content context an agent needs.

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

Conciseness3/5

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

The important content is front-loaded, but the description is a long run-on sentence followed by repeated access-plan wording. The Consultant/Legend exclusion is stated twice, and the pricing URL plus lengthy contents list make it more verbose than necessary.

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 the output schema exists, the description does not need to explain return values and instead covers the critical access, content, and alternative-tool context. An agent has enough information to decide whether to call it and what prerequisites apply.

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 100% and the single slug parameter is already documented as coming verbatim from search_concepts.rows[].slug. The description only repeats the search_concepts pointer, so it adds little semantic value 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?

States a specific verb and resource: retrieves the FULL encyclopaedia card for one concept, and enumerates the included sections and languages. It clearly distinguishes this from get_concept by noting that get_concept serves public metadata while this tool opens the paid tranche.

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 explains when this tool is usable: only with an MCP Pass or Firm Pass API key, and it refuses without one. It names alternatives and prerequisites: use search_concepts to find slugs, and get_concept continues serving public metadata when access is missing.

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

get_day_rate_benchmarkPublic SAP AI & analytics day-rate aggregateA
Read-onlyIdempotent
Inspect

The PUBLIC day-rate aggregate for SAP AI & analytics freelance work: min/max daily rate by country, specialisation and seniority — daily_rate_min / daily_rate_max (plus daily_rate_median, daily_rate_p10, daily_rate_p90 when the source publishes them), every amount in the row's own currency — with source, source date, confidence and the sample the source states. This is the free aggregate published at analyticslegends.ai/api/market-rates.json, and it is SMALL — a few dozen rows at most, every one of them a secondary source (a published market study or a job-board scan), and sample_size is null on most of them. NO COUNT IS WRITTEN HERE ON PURPOSE: _meta.tranche_total_row_count and the rows themselves are the live measure. A frozen pair stood here until 2026-08-27 — '11 rows on 2026-08-09 … sample_size null on 8 of them' — and the second half was WRONG (7 of 11) while the first was still right, which is the whole argument against writing either. NOTHING IS HELD BACK BEHIND IT: there is no paid counterpart to this aggregate. The community-contribution path exists (public.rate_contributions) but publishes nothing yet — v_community_rate_aggregates and v_rate_index are still empty, because a contributed rate only surfaces once a cell holds enough submissions to be reported without identifying anyone. So whatever percentile a source row happens to carry is served here, free, to everyone. The GB row carries a median, p10 and p90, and its own note says its min/max ARE the 25th and 75th percentiles. What is missing from this answer is missing from THIS aggregate; it is not a paid tier. THIS IS NOT THE ONLY RATE THE PLATFORM PUBLISHES, AND ON THE QUESTIONS THIS MARKET ASKS MOST IT IS THE THINNER ONE. The website carries a rate_band per live radar posting for signed-in subscribers — a panel-inferred P25–P75 band per (seniority × product × region) cell, Eursap n=312 plus the Analytics Legends operator panel. This server does not serve it (find_opportunities.rate_band is null on every row, with or without a key). The grid covers EUROPEAN cells only — DACH, FR/Benelux, UK/IE, Southern EU, Eastern EU, Nordics — and there it prices exactly the cells this small aggregate cannot (Senior Datasphere DACH, Senior BDC DACH), where specialisation:"bdc" here returns nothing. When this tool comes back empty for a country × product: in one of those European regions, say the AGGREGATE holds no row and that subscribers read the platform's band on the posting pages; ANYWHERE ELSE (Americas, APAC, Africa, Middle East) say the platform publishes no rate for that cell at any tier — never that subscribers get one. The two are different instruments: this one is a published market study, that one is an editorial benchmark attached to a live posting. Read _meta.available_countries / available_specialisations / available_seniorities — they are computed from the aggregate on every call — before concluding that a rate is unpublished, and quote each row with its own currency, its confidence and its source date.

NameRequiredDescriptionDefault
countryNoISO-3166-1 alpha-2 country code, e.g. DE, FR, CH.
seniorityNoe.g. senior, principal.
specialisationNoA specialisation code, matched exactly. The live list is `_meta.available_specialisations` on every call — no list is kept here, because a written one went stale. Codes are NOT evenly spread across countries: read the rows a country filter returns. A code this aggregate does not hold (bdc, joule) returns 0 rows and the available codes; it never widens to a neighbouring band. 0 rows here is an absence in THIS aggregate only — see the tool description for what the website's subscriber band covers and where no rate exists at any tier.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A3.7/5.0
Behavior3/5

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

Annotations already declare readOnly, idempotent, openWorld and non-destructive, so safety is covered. The description genuinely adds beyond that: the dataset is small (a few dozen rows), every row is a secondary source, `sample_size` is often null, each amount is in the row's own `currency`, and `_meta.available_*` is recomputed per call. Offset against this, the paragraph about a 'frozen pair' that stood until 2026-08-27 is changelog noise that consumes attention without informing a call.

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

Conciseness2/5

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

Purpose is front-loaded, but the text runs to roughly 500 words for a three-parameter read tool and includes internal meta-commentary (the stale '11 rows on 2026-08-09 … sample_size null on 8 of them' correction, 'NO COUNT IS WRITTEN HERE ON PURPOSE') that does not help an agent invoke the tool. Several sentences repeat the same point about the aggregate not being a paid tier.

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?

An output schema exists, so return-field explanations are unnecessary, and the description still covers what an agent needs to interpret results: per-row currency, confidence, source date, empty-result meaning, and the coverage boundary against the subscriber band. It is more than complete; the remaining deficiency is editorial discipline, not missing information.

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 100%, so the schema already documents all three optional parameters, making 3 the baseline. The description reinforces empty-result semantics and warns that codes are unevenly spread across countries, but that guidance is already largely present in the `specialisation` schema description, so it adds little net meaning.

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 opening sentence gives a specific verb+resource: a public day-rate aggregate returning min/max daily rate by country, specialisation and seniority, with named fields. It also explicitly distinguishes itself from the sibling/instrument it is not (`find_opportunities.rate_band` on live postings), so an agent can route between them without opening either schema.

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?

It names the alternatives and the conditions that select them: community aggregates (v_community_rate_aggregates, v_rate_index) publish nothing yet, and the subscriber rate_band exists only on European radar postings. It even prescribes behaviour when results are empty (say the aggregate holds no row in European regions; say no rate exists at any tier elsewhere). The one gap is that the 'use this tool when a user asks about day rates' framing is implied rather than stated.

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

get_expansion_briefExpansion brief for a target region (MCP Pass)A
Read-onlyIdempotent
Inspect

The one-call brief a services practice reads before opening a subsidiary in another region: providers already there (by kind and by country, and how many are LOCAL entities versus members of multi-region groups), SAP end-customers there (by country and by industry — counts from the Legend corpus, never rows), live opportunities by country, and the BRIDGE GROUPS — brand families that hold entities both in the target region and in your home region (or anywhere else when home_region is omitted). Regions are the platform's six-value geography: EMEA holds Europe AND the Middle East, AFRICA is its own region, AMER is North America, LATAM and APAC are what they say, GLOBAL is the country-unknown bucket and is refused as a target. Day rates are NOT in this brief: call get_day_rate_benchmark per country; it answers only for the countries listed in its available_countries (Europe, the Middle East, North America and a few APAC countries at low/medium confidence) and refuses the rest rather than transpose a European band. Every count is read at query time from the SSOT. Requires the API key of an MCP Pass or Firm account (the Consultant and Legend web plans do not include MCP access).

NameRequiredDescriptionDefault
home_regionNoOptional. The region you operate from today. When set, bridge groups are the families present in BOTH regions; when omitted, in the target region and any other.
target_regionYesThe region you want to enter. One of EMEA, AMER, LATAM, APAC, AFRICA (GLOBAL is refused: it is not a market).

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already cover the safety profile (readOnly, idempotent, non-destructive), and the description adds substantial context on top: counts are read at query time from the SSOT, Legend figures are counts and never rows, GLOBAL is rejected rather than silently empty, and authentication tier requirements are stated. Nothing about the call's behavior is left for the agent to infer.

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?

Front-loaded with the core purpose in the opening clause, and every sentence carries real information (region semantics, exclusions, auth, corpus provenance). It is dense and parenthetical-heavy, and the day-rate digression is longer than strictly necessary, but no sentence is filler.

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?

For a two-parameter read-only aggregate tool with an output schema, the description supplies everything the agent needs: what each section contains, how regions are defined, the prerequisite credentials, and which adjacent question requires a different tool. The output schema handles return shape, so no gap remains.

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?

Schema coverage is 100% and the schema already documents home_region omission behavior, so this is mostly reinforcement. However the description adds genuine semantics beyond the schema: the six-value geography definitions (EMEA spans Europe AND the Middle East, AFRICA stands alone, GLOBAL is the country-unknown bucket) and the fact that GLOBAL is refused as a target, which the enum alone cannot convey.

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?

States a concrete verb and resource ('one-call brief') and then enumerates the four payloads it returns: providers by kind/country with LOCAL vs multi-region-group split, SAP end-customers by country and industry, live opportunities by country, and bridge groups. It explicitly carves out what it does NOT return (day rates) and names the sibling that does, so an agent can separate it from get_day_rate_benchmark without opening either schema.

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?

Names the decision context precisely ('the brief a services practice reads before opening a subsidiary in another region'), states the explicit exclusion and routes to the alternative (get_day_rate_benchmark per country, with its coverage caveat), and spells out the access prerequisite (MCP Pass or Firm account; Consultant and Legend web plans excluded). Both when-to-use and when-not-to-use are covered.

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

get_firmGet one firm's published profileA
Read-onlyIdempotent
Inspect

Fetch one organisation from the published directory by its database slug (rows[].slug from search_firms, verbatim). Returns the same public fields plus partnerships_declared, the count of partnerships this directory records for the firm — 0 on ~77 % of rows (re-measured 2026-09-30 on the published tranche: 77,1 %; it read ~97 % until the 2026-09-30 brand-family pass derived 3 730 sibling links from sister entities), meaning none recorded here, never that the firm has no partners; a sibling link is a reading of shared brand, not a declared org chart. Does not return the paid firm-intelligence profile, contacts, or any person.

NameRequiredDescriptionDefault
slugYesThe 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.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.3/5.0
Behavior5/5

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

Annotations already cover the safety profile (readOnlyHint, idempotentHint, non-destructive, closed-world), and the description goes well beyond them by explaining what partnerships_declared actually means, warning that 0 indicates 'none recorded here' rather than 'no partners', and clarifying that a sibling link is an inference of shared brand, not a declared org chart. That interpretation guidance is exactly the kind of context annotations cannot supply.

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

Conciseness3/5

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

Front-loaded correctly — action first, then return-shape caveats — but it is over-stuffed with measurement trivia: precise percentages with comma decimals, multiple re-measurement dates, and the historical '~97 % until the brand-family pass' narrative. The core warning about misreading 0 earns its place; the surrounding statistics are heavier than an agent needs.

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?

Single required parameter, output schema present, annotations covering read-only/idempotent/closed-world, and the description still adds the interpretation caveats an agent needs to avoid false conclusions (empty partnerships, slug refusal not implying absence). Nothing required to call it correctly is missing.

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 100% and the slug property description is itself extremely detailed, so the schema does the heavy lifting. The description reinforces the 'verbatim from search_firms.rows[].slug' rule but adds little semantic detail beyond what the schema already states; baseline 3 applies.

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?

States a specific verb and resource ('Fetch one organisation from the published directory') scoped by an exact identifier source, and distinguishes itself from siblings by explicitly excluding the paid firm-intelligence profile (get_firm_intel) and search_firms' list output. An agent can route correctly without opening any schema.

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?

Gives concrete context for use: pull rows[].slug from search_firms verbatim to call this. The exclusion of the paid firm-intelligence profile implicitly points to get_firm_intel, but the description never names that alternative or states the condition under which to prefer it, so the when-not side is implied rather than explicit.

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

get_firm_intelFirm intelligence profile (MCP Pass)A
Read-onlyIdempotent
Inspect

The paid intelligence profile of a services firm — SAP practice size and partner level, delivery flags per product, typical day rate and seniority, notable clients, analytics practice summary, and a LinkedIn company URL (present on ~71% of the corpus, re-measured 2026-09-05 on 9,104 profiles — it read ~39% from 2026-08-10 to 2026-09-05, i.e. a third of the corpus below the truth, because an enrichment pass filled the column and no reader of this sentence was told — glassdoor_rating, glassdoor_reviews_count and linkedin_followers are null on all but a handful of profiles, absence here is a data gap, not a signal). READ THE SPARSITY BEFORE QUOTING A ROW: on the 9,103 profiles measured 2026-08-23, typical_day_rate_eur is null on 78.0% and sap_partner_level on 85.7% — the two headline fields are the exception, not the rule, and a null means 'not researched', never 'no partner level'. Requires the API key of an MCP Pass or Firm account (the Consultant and Legend web plans do not include MCP access). Person-shaped fields (contacts, founders, leadership, recruiters, postal addresses) are NEVER served by this endpoint at any tier — they remain behind the platform's signed-URL path. Search by name; the public directory (search_firms) is a different, wider population.

NameRequiredDescriptionDefault
modeNoKeep only firms whose profile declares this engagement mode (mode_freelance / mode_permanent / mode_subcontract). Same reading as `delivers`: declared-only.
nameNoFirm name, matched case-insensitively; an exact name ranks first, then a name starting with it, then the other matches. Omit to browse the corpus by data completeness.
limitNoMax rows (hard cap 10 — these rows are wide).
cursorNoOpaque 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.
countryNoISO-3166-1 alpha-2 country code, e.g. DE, FR, CH.
deliversNoKeep 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.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A3.5/5.0
Behavior4/5

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

Beyond the readOnly/idempotent annotations, the description discloses things an agent cannot get elsewhere: the paid-account gate (Consultant and Legend web plans are excluded), the hard exclusion of all person-shaped fields at every tier, the LinkedIn URL coverage figure, and the critical null-vs-false distinction for typical_day_rate_eur and sap_partner_level. The weak spot is the embedded editorial aside about a past measurement error, which reads as a correction to a human reader rather than information the calling agent can act on.

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

Conciseness2/5

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

The core content is a single run-on paragraph whose most actionable warnings (null rates on headline fields, auth tier, person-field exclusion) are buried inside em-dash interjections and a lengthy parenthetical about re-measured LinkedIn coverage. The aside explaining that a prior figure was "a third of the corpus below the truth" and that "no reader of this sentence was told" is self-referential noise for an agent and pushes the operational guidance to the middle of the text.

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?

An output schema exists, so return-format detail is not required, and the description covers the remaining agent-critical facts: auth requirements, the destructive-to-assume null semantics, the person-data exclusion, and the sibling boundary against search_firms. What keeps it short of complete is the absence of any distinction from get_firm despite near-identical naming, and the lack of a stated default behavior when name is omitted.

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 100% and the enum/filter semantics (declared-only reading of `delivers` and `mode`, cursor reuse rules, the cap of 10) are all documented in the schema itself. The description adds only the phrase "Search by name" and a general sparsity warning; it contributes essentially nothing about `country`, `limit`, or `mode` that the schema does not already say. Baseline 3 applies.

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

Purpose4/5

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

The first sentence names the resource concretely (a paid intelligence profile of a services firm) and enumerates the fields it carries, so an agent knows it returns a wide firm record rather than a list of names. It explicitly distinguishes itself from search_firms (public directory, wider population). It does not, however, distinguish itself from sibling get_firm or get_sap_client_profile, which leaves a real ambiguity unresolved.

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

Usage Guidelines3/5

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

"Search by name" plus the tier/auth constraint implies the usage context, and the search_firms exclusion is genuinely useful routing. Missing is any statement of when an agent should prefer this over get_firm, get_sap_client_profile, or find_sap_clients, and no guidance on using the filter-only path (omitting name to browse by completeness). Usage is implied rather than prescribed.

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

get_sap_client_profileOne SAP end-customer profile (MCP Pass)A
Read-onlyIdempotent
Inspect

The full profile of one SAP end-customer — SAP footprint (products in use, modules known), analytics solutions, identity and evidence fields. Requires the API key of an MCP Pass or Firm account (the Consultant and Legend web plans do not include MCP access). id comes verbatim from find_sap_clients.rows[].id.

NameRequiredDescriptionDefault
idYesProfile id, verbatim from find_sap_clients.rows[].id.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnly, idempotent, non-destructive and closed-world, so the safety profile is covered. The description adds real value beyond that with the API-key/tier gating (MCP Pass or Firm account required, Consultant/Legend excluded), which an agent needs before attempting the call. Return shape is not described, but an output schema exists.

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?

Three tight sentences, front-loaded with what the profile contains, then the auth gate, then the id provenance. The id provenance sentence duplicates the schema, which is a minor redundancy, but nothing else is wasted.

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 an output schema present the description rightly omits return values, and it covers the two things an agent actually needs: how to obtain the id and what auth tier is required. Error or not-found behavior is the only notable omission for a single-resource fetch.

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 100% and the schema already states 'Profile id, verbatim from find_sap_clients.rows[].id.' The description repeats that same provenance sentence almost verbatim, so it adds no meaning beyond the structured field. Baseline 3 applies when the schema does the work.

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?

It names a specific verb-and-resource pairing: the full profile of ONE SAP end-customer, and enumerates what the profile contains (footprint, modules, analytics solutions, identity/evidence). The word 'one' plus the pointer to find_sap_clients.rows[].id makes it clearly distinct from the sibling list/search tool.

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?

It gives a clear prerequisite chain — get the id from find_sap_clients, then call this — plus an explicit auth exclusion (Consultant and Legend web plans lack MCP access). It stops short of an explicit 'use find_sap_clients instead when you need to search rather than fetch a known id' statement, so there is a small inference left to the agent.

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

get_studyRead a study (MCP Pass)A
Read-onlyIdempotent
Inspect

Read one Analytics Legends study BODY — the paid text behind list_studies' metadata. Requires the API key of an MCP Pass or Firm account (the Consultant and Legend web plans do not include MCP access). Bodies run to 38k words and exceed the 256 KiB response ceiling, so this tool serves STRUCTURE first: called without section it returns the section list and the introduction; pass section (a heading from that list, matched case-insensitively) to read one section. Find slugs and languages with list_studies.

NameRequiredDescriptionDefault
langNoISO-639-1 language of the edition, e.g. en or fr. Defaults to en.en
slugYesStudy slug, verbatim from list_studies.rows[].slug.
sectionNoA section heading from a previous call's `sections` list. Omit to get the list.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.3/5.0
Behavior3/5

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

Annotations already declare readOnly, idempotent, non-destructive, closed-world, so the safety profile is covered. The description adds real context beyond that: the auth tier gate, the 256 KiB response ceiling versus 38k-word bodies, and the deliberate structure-first serving pattern. However, with no output schema for the section listing it describes, it leaves open what a no-section response actually contains beyond 'the section list and the introduction' — a 3 rather than a 4 — and much of its added value overlaps what a caller could infer from the auth error, not from documented behavior.

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?

Four tight sentences, front-loaded with the resource and the distinction from list_studies, then the access prerequisite, then the pagination-by-section mechanic. Every clause carries information an agent needs to call the tool correctly; nothing is filler.

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?

The tool has an output schema, so return shapes need no prose, yet the description still covers the two things an agent would otherwise learn only by failing: the account-tier requirement and the oversized-body handling via `section`. For a read-only single-record fetch with three parameters, nothing material is missing.

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 100%, so all three parameters are documented in the schema, including that `section` comes from a previous call's `sections` list and that omitting it returns the list. The description adds only the case-insensitive matching rule, which is useful but narrow. With the schema doing nearly all the work, the baseline 3 applies.

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?

States a specific verb and resource ('Read one Analytics Legends study BODY') and immediately distinguishes it from the sibling list_studies by calling the body 'the paid text behind list_studies' metadata.' An agent can tell exactly which of the two tools returns full text versus metadata.

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?

Gives explicit conditional workflow: call without `section` to get the section list plus introduction, then pass a heading to read one section, and use list_studies to find slugs and languages. It also names the prerequisite (MCP Pass or Firm API key) and excludes the Consultant and Legend web plans, which is genuine when-not-to-use guidance.

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

list_firm_kindsList firm kinds with live countsA
Read-onlyIdempotent
Inspect

Breakdown of the published firm directory by organisation kind, with a live row count per kind. Use this before search_firms to know what the population actually is instead of guessing.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare the tool as read-only, idempotent, closed-world and non-destructive, so the safety profile is covered. The description adds useful behavioral context by noting that counts are live and scoped to the published firm directory.

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 two tightly written sentences with no wasted language. The resource and output are front-loaded, followed by a clear usage recommendation.

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?

An output schema exists, so the description does not need to explain return values. It is nearly complete for a zero-parameter read-only listing tool, though it leaves the relationship with count_firms_by unaddressed.

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 tool takes zero parameters, so there are no parameter semantics to document. The baseline for a zero-parameter tool is 4.

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

Purpose4/5

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

The description clearly states a specific resource and output: a breakdown of the published firm directory by organisation kind with live row counts per kind. It does not explicitly distinguish itself from the sibling tool count_firms_by, which is the main remaining ambiguity.

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?

It gives a clear usage context: call this before search_firms to understand the firm population instead of guessing. It does not state when not to use it or how it relates to count_firms_by.

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

list_freelance_platformsList the CV/profile platforms a consultant can sign up onA
Read-onlyIdempotent
Inspect

The subset of the published directory where a consultant can CREATE A PROFILE — freelance marketplaces, job boards with candidate profiles, talent platforms and expert networks — each with its signup URL, an editorial confidence grade and the date it was assessed. This answers the entering-contractor's first practical question ('where do I register?') in one call. Everything here is also in search_firms — this tool adds the platform fields and the filter, never a wider population. signup_url is the platform's own page: it was verified on assessed_at, and a platform absent here is not proven to refuse signups — it is unassessed or unpublished.

NameRequiredDescriptionDefault
limitNoMax rows (hard cap 50).
cursorNoOpaque 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.
countryNoISO-3166-1 alpha-2 country code, e.g. DE, FR, CH.
platform_typeNoRestrict 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.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare read-only, non-destructive, and idempotent behavior, so the description does not need to re-cover those. It does add meaningful semantics: signup_url is verified on assessed_at, and a platform absent here is not proof of refusal—it is merely unassessed or unpublished. These boundary details would be hard to infer from the schema alone.

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 main purpose is front-loaded, and every sentence carries signal: what the list contains, which question it answers, how it relates to search_firms, and how URL verification/absence should be interpreted. There is no filler or redundancy with the title.

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?

The description is complete for this read-only list tool: it clarifies scope, a reliable sibling relationship, verification meaning of the returned URL, and absence semantics. With four optional parameters all documented in the schema and read-only annotations present, nothing critical is missing for correct invocation.

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 100%, and every parameter already has a focused description including cursor rules, country format, and platform_type behavior. The tool description adds little parameter-level meaning beyond clarifying that the tool applies a platform-type filter, so the appropriate baseline is 3.

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 names a specific verb (list) and resource (freelance platforms where a consultant can create a profile) and gives concrete examples of the included platform kinds. It also clearly distinguishes itself from search_firms by stating this is a narrower subset that adds platform fields, so an agent can tell it apart from sibling tools.

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 explicitly positions this tool as the one answering 'where do I register?' and names search_firms as the broader alternative, clarifying that this tool never returns a wider population. That gives an agent a direct routing decision: use this when platform signup fields are the goal, and search_firms for the broader directory.

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

list_sap_modulesSAP AI & analytics module taxonomyA
Read-onlyIdempotent
Inspect

The canonical SAP module/product taxonomy Analytics Legends classifies against (codes and EN/FR labels by category). Use it to normalise a user's loose product wording — 'SAC', 'Analytics Cloud', 'Datasphere' — onto the codes the other tools filter on.

NameRequiredDescriptionDefault
limitNoMax rows (hard cap 50).
queryNoFree-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.
cursorNoOpaque 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.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnlyHint, idempotentHint, destructiveHint=false, closed-world), so the bar is lower. The description still adds useful content semantics — bilingual EN/FR labels organised by category and the canonical code set — that the annotations do not convey.

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, front-loaded with what the resource is before explaining why to call it. No filler text; every clause carries information.

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?

An output schema exists, so return-value detail is not required, and the parameters are self-documenting. Purpose and use case are covered; the only minor omission is any note about pagination behaviour across pages, which the cursor description largely handles.

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 100%, so limit, query and cursor are fully documented in the schema itself, including the substring-per-word matching rule and cursor reuse constraints. The description adds no additional parameter meaning, so the baseline 3 applies.

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?

States a specific verb and resource ('canonical SAP module/product taxonomy') and specifies what it contains ('codes and EN/FR labels by category'), which is more precise than the name alone. It also positions itself relative to the other tools by noting these are 'the codes the other tools filter on', so an agent can tell it apart from look-alikes such as list_firm_kinds and list_freelance_platforms.

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?

Gives an explicit when-to-use with concrete examples ('SAC', 'Analytics Cloud', 'Datasphere') and the goal of normalising loose wording onto filter codes. There is no when-not guidance or named alternative tool, which keeps it short of a 5.

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

list_studiesList the deep-research studies (metadata only)A
Read-onlyIdempotent
Inspect

List the Analytics Legends deep-research studies with their edition, as-of date, audience, word count and canonical URL. METADATA ONLY: study bodies are a paid deliverable, served by get_study on this same endpoint with an MCP Pass or Firm Pass key. Use this to tell a reader that a study exists and where to read it. ONE ROW IS ONE LANGUAGE EDITION, NOT ONE STUDY: each study is published in every language it has been translated into, so _meta.tranche_total_row_count counts editions and _meta.distinct_studies counts the works. _meta.available_languages gives the live per-language counts; each row carries its editions list. Pass lang to get one row per study.

NameRequiredDescriptionDefault
langNoISO-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.
limitNoMax rows (hard cap 50).
queryNoFree-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.
cursorNoOpaque 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.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, and the description adds substantive context beyond them: content is paywalled and requires a pass key, the grain is one row per language edition rather than per study, and the `_meta` counters (`tranche_total_row_count`, `distinct_studies`, `available_languages`, `next_cursor`) are named. That is exactly the non-obvious behavior an agent would otherwise get wrong.

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?

Front-loaded with the resource and output fields, then scope, then the row-grain caveat, which is the highest-risk misconception. The all-caps warnings and the `_meta` enumeration make it denser than ideal, but nearly every clause carries actionable information rather than filler.

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?

For a 4-param, zero-required listing tool with an output schema and full annotation coverage, the description covers access model, row grain, language filtering, and pagination handoff. Nothing an agent needs in order to call it correctly or interpret the counts is missing.

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?

Schema coverage is 100%, so baseline is 3; the description still adds real meaning by explaining that `lang` collapses the edition-per-row grain into one row per study and that an unknown-but-valid code yields 0 rows, which the schema alone does not convey. It says less about `query` and `cursor` than the schema already does, so it does not fully earn a 5.

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?

States a specific verb and resource (list deep-research studies) plus exactly what fields each row carries (edition, as-of date, audience, word count, canonical URL), and explicitly separates itself from `get_study`, which serves the bodies. An agent can tell this is the catalog/metadata tool without opening any schema.

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?

Gives an explicit when-to-use ('tell a reader that a study exists and where to read it') and an explicit when-not/alternative ('study bodies are a paid deliverable, served by `get_study` on this same endpoint with an MCP Pass or Firm Pass key'). It also states the condition that changes the shape of the result ('Pass `lang` to get one row per study').

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

query_knowledge_graphTraverse the learning knowledge graphA
Read-onlyIdempotent
Inspect

The RELATIONS between the platform's teaching objects — which Academy module teaches which concept, which study covers which module, what a concept relates to. THIS IS THE ONLY TOOL ON THIS SERVER THAT SERVES EDGES; the others serve rows. Ask it what connects to what, not what exists. SCOPE, AND IT IS NARROWER THAN 'the knowledge graph': it carries four node types — concept, module, study, vendor — and every edge whose BOTH endpoints are one of them. The whole graph holds twelve node types; the eight it does not carry are each either served by their own tool or named as not served at all, and _meta.excluded_node_types says which per type (consultant data is served at NO tier), so a missing type is a documented boundary and never a silent gap. Call it with node_id (e.g. module:M178, concept:C001, study:ai-impact-2026-EN) to walk one node's neighbourhood; with node_type and/or query to find a node id first. edge_type and direction narrow a walk. Read _meta.available_edge_types — computed from the served projection on every call — before assuming an edge type exists.

NameRequiredDescriptionDefault
langNoISO-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.
limitNoMax rows (hard cap 50).
queryNoCase-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`.
cursorNoOpaque 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_idNoFully-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.
directionNoWhich 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_typeNoRestrict a walk to one relation. The authority is `_meta.available_edge_types`, computed on every call — no list is kept here: a four-name list once stood here while the projection served five, then a five-name list while it served six (`broader`).
node_typeNoRestrict to one carried node type: concept · module · study · vendor. Read `_meta.available_node_types`.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A5/5.0
Behavior5/5

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

Beyond the read-only annotations, it discloses important boundaries: the four carried node types, eight excluded node types documented in `_meta.excluded_node_types`, consultant data served at no tier, and `_meta.available_edge_types` as the runtime authority. It also explains language fallback behavior and cursor reuse constraints, which are behavioral context not present in annotations.

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 long but appropriately so for a complex, multi-parameter traversal tool, and it is front-loaded with the core edge-vs-row distinction. Every major sentence appears to carry operational information, including scope boundaries, invocation modes, and dynamic meta fields.

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 the tool's complexity, 8 parameters, full schema descriptions, annotations, and an output schema, the description is complete enough for correct invocation. It covers purpose, scope, alternatives, edge/node distinction, parameter intent, pagination, language fallback, and dynamic metadata without needing to describe return values already covered by the output schema.

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

Parameters5/5

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

Although schema coverage is 100%, the description adds substantial meaning: node_id examples and its role in switching rows from nodes to edges, direction being ignored without node_id, query applying to node listings rather than walks, and lang affecting served labels with declared fallback. These details go well beyond the schema's field descriptions.

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?

It states a specific verb and resource — traversing the learning knowledge graph for relations — and explicitly distinguishes this as the only tool on the server that serves edges rather than rows. The scope is narrowed to four node types and the contrast with 'what exists' tools makes the purpose unambiguous.

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?

It tells the agent exactly when to use it: 'Ask it what connects to what, not what exists,' and contrasts it with sibling node-serving tools. It also explains the two invocation modes clearly — walk via node_id or discover a node id first via node_type and/or query — and notes how edge_type and direction narrow a walk.

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

search_conceptsSearch the SAP AI & analytics concept encyclopaediaA
Read-onlyIdempotent
Inspect

Search the SAP AI & analytics concept encyclopaedia — the vocabulary of the stack, written for practitioners. Returns slug, title, category, level, tags and the editor's summary. level is GRADED on every active row since 2026-09-18 (the CHECK constraint accepted only the legacy vocabulary OR NULL, so the loader wrote NULL rather than fail; 108 of 330 were blank). A null, if one ever returns, means 'not graded', never 'Beginner'. These are the same fields get_concept returns for ONE slug. The card BODY (cheat sheet, glossary, pro tip and the four analysis tables) is paid (MCP Pass or Firm Pass key): call get_concept_card. Why-it-matters and key points are NOT served by this endpoint either, but they are published in full on the concept page at citation_url — follow the URL for those, a plan buys the body, not them.

NameRequiredDescriptionDefault
limitNoMax rows (hard cap 50).
queryNoFree-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.
cursorNoOpaque 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.
categoryNoConcept 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.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.3/5.0
Behavior5/5

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

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), yet the description still adds substantial context: the null-`level` data-quality caveat ('means not graded, never Beginner'), the plan-key requirement for card bodies, confirmation that this endpoint does NOT serve why-it-matters/key points, and the pointer to `_meta.available_categories`. This is exactly the beyond-annotation value the dimension rewards.

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

Conciseness3/5

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

The purpose and return fields are front-loaded well, but the long parenthetical about the CHECK constraint and loader writing NULL (plus '108 of 330 were blank') is implementation history that costs more tokens than the takeaway ('null means not graded') requires. Structure is sound; sizing is inflated.

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?

For a search tool with an output schema, four optional params, and annotations in place, the description still covers the data quirks an agent would otherwise trip on (null level, incomplete field set, paywalled body, external URL for omitted content). Nothing needed to call or interpret results correctly appears to be missing.

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 100% and the schema itself already explains query word-matching, cursor reuse rules, category prefix behaviour, and the 50-row cap, so structured data carries the load. The description adds little about parameters beyond the `level` field's meaning and the warning to read `_meta.available_categories` rather than trusting prose, which largely duplicates the schema's category note.

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?

States a specific verb and resource ('Search the SAP AI & analytics concept encyclopaedia') and enumerates the returned fields (slug, title, category, level, tags, summary). It explicitly positions itself against siblings: 'the same fields `get_concept` returns for ONE slug' and 'The card BODY ... call `get_concept_card`', so an agent can route without opening another schema.

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?

Alternative routing is present and specific: `get_concept` for a single known slug, `get_concept_card` for the paid body, and citation_url for why-it-matters/key points. It never states the inverse case explicitly (i.e. 'use this first when you don't have a slug'), so it falls just short of full when/when-not guidance.

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

search_firmsSearch the SAP AI & analytics firm directoryA
Read-onlyIdempotent
Inspect

Search the published Analytics Legends directory of SAP AI & analytics service providers — placement agencies, Big-4 and ESN practices, SAP vendors, platforms and community groups — by country, region (EMEA · AMER · LATAM · APAC · AFRICA), kind, declared SAP module and free text. Returns name, HQ country/city, website, careers URL and a one-line editorial claim. SAP END-CUSTOMER companies are NOT in this directory: they are a separate paid dataset, excluded here by the is_client FLAG — not by the client_enterprise kind code. The two are different columns, and where a row's flag and its kind label disagree in the SSOT it is the flag that decides what this tool serves, so read the flag's meaning into the answer and not the label's. PAGINATED WITH A KEY (a free one is enough): the whole matched set is reachable — pass _meta.next_cursor back as cursor with the same filters until it is null. Without a key: first 10 rows only, no cursor. When query is set, rows are ordered by how well the NAME matches it (exact, then prefix, then substring), and rows matching only the description come last; without query the order is the directory's own quality ranking.

NameRequiredDescriptionDefault
kindNoRestrict 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.
limitNoMax rows (hard cap 50).
queryNoFree-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.
cursorNoOpaque 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.
moduleNoRestrict 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.
regionNoRegion code of the HQ country — the platform's six-value geography: EMEA (Europe AND the Middle East), AMER (North America), LATAM, APAC, AFRICA (its own region, not folded into EMEA), GLOBAL (country unknown). Case-insensitive on input; anything else is refused.
countryNoISO-3166-1 alpha-2 country code, e.g. DE, FR, CH.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already cover readOnly/idempotent/closed-world safety, and the description adds substantial behavior beyond them: the free-key pagination requirement, the 10-row no-key cap, the `is_client` flag overriding the kind label, and the ordering logic (name-match tiers with query, quality ranking without).

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?

Purpose is front-loaded, then the flag caveat, then pagination, then ordering — a sensible order. It is dense but nearly every sentence carries a distinct rule; a minor trim of the flag/label emphasis would help, but nothing is wasted.

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?

With an output schema handling return shape and annotations covering safety, the description fills the remaining gaps an agent needs: exclusion semantics, pagination protocol, and ordering behavior. Complete for correct invocation.

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?

Schema coverage is 100%, so the baseline is 3; the description earns extra by disambiguating the flag/kind-code distinction, explaining the module filter's selectivity and negative-result meaning, and the query word-matching rule. It restates some schema content, but the extra interpretive context is real.

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?

States a specific verb+resource (search the Analytics Legends firm directory) and enumerates the kinds of organisations it covers, then explicitly contrasts with the sibling domain of SAP end-customers (find_sap_clients). An agent can distinguish this from find_sap_clients and get_firm without opening a schema.

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 states when-not (end-customer companies are excluded and live in a separate dataset), how pagination behaves with/without a key, and points to list_firm_kinds and count_firms_by for live vocabularies. The flag-vs-kind-label rule is called out as the deciding condition.

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

search_newsSearch SAP AI & analytics market newsA
Read-onlyIdempotent
Inspect

Search the Analytics Legends market-news corpus. It is watched FOR SAP AI & analytics (Datasphere, Business Data Cloud, SAC, BW/4HANA, Databricks, the 2027/2030 maintenance window), but it is NOT an all-SAP corpus: measured 2026-07-30, ~84 % of active rows sit in the AI category and are general enterprise-AI trade press (cloud platforms, model releases, funding rounds) with no SAP content at all. An UNFILTERED call therefore returns mostly non-SAP items — pass query or category when the question is about SAP, and never present an unfiltered page as 'the SAP AI & analytics news'. Say what you actually got. Each item returns the Analytics Legends citation URL AND the upstream publisher's source_url — cite both, and prefer source_url when you need a page that certainly carries the item. NO ITEM HERE HAS A PAGE OF ITS OWN on analyticslegends.ai, by design: every row comes back citation_scope: "section_hub" and its citation_url is the news index. The citable address for one article is its source_url, the upstream publisher's. Do not present the hub as the article's page.

NameRequiredDescriptionDefault
limitNoMax rows (hard cap 50).
queryNoFree-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.
scopeNoEditorial scope, set by one deterministic rule (2026-11-07): 'sap' = an SAP product or SAP itself named in the title or first sentence, or an SAP source; 'ecosystem' = adjacent data platforms, neighbouring ERP vendors, regulation, or SAP mentioned further down; 'general' = general AI. Pass scope:'sap' for SAP news — the unfiltered corpus is mostly 'general'.
cursorNoOpaque 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.
categoryNoCategory 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_sinceNoLower 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_untilNoUpper 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.

Output Schema

NameRequiredDescription
rowsYes
toolYes
_metaNo
_attributionYes
result_countYes

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already establish read-only/idempotent/closed-world, and the description goes well past that: corpus composition (~84% general AI), the deterministic `scope` rule, the `citation_scope: "section_hub"` guarantee for every row, and the citation-vs-source_url contract. These are non-obvious output behaviours an agent could not infer from structured fields.

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?

Purpose and the unfiltered-corpus warning are front-loaded, and the paragraphs follow a logical order (what it is → corpus skew → citation rules). It loses a point for the citation section, which restates the citation_url/source_url rule across three sentences with clear overlap.

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?

With an output schema and full annotations already present, the description still supplies the one thing those cannot: the corpus's actual composition and the citation trap. An agent has everything needed to call this correctly and to report results honestly.

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 100%, so the schema already documents substring-per-word query matching, the dynamic category vocabulary, the SAC collision, and the inclusive date bounds — the description largely corroborates rather than adds. It does reinforce the cross-parameter strategy (filters needed for SAP questions, `match_count` scoping for quotable windows), but adds little new syntax-level meaning.

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?

"Search the Analytics Legends market-news corpus" names a specific verb and resource, then immediately scopes it (SAP AI & analytics trade press) and disclaims what it is not ("NOT an all-SAP corpus"). No sibling tool covers news search, and the description makes that distinct role unmistakable.

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?

It gives explicit when-to guidance (pass `query` or `category` when the question is about SAP) and an explicit when-not (do not present an unfiltered page as 'the SAP AI & analytics news', do not present the hub as the article's page). This is prescriptive routing plus behavioural exclusions, not just implied usage.

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.

  1. 3 tool updates
    • Changedfind_academy_modules2 fields changed
      • changedOutput schema / properties / rows / items / properties / is_preview / description
        Previous value: -"The second free-access marker. Does NOT coincide with status — read both."New value: +"The second free-access marker of the WEBSITE. Does NOT coincide with status — read both. It does not open get_academy_module without a key."
      • changedOutput schema / properties / rows / items / properties / status / description
        Previous value: -"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."New value: +"Editorial access marker: 'available' or 'legend-pass'. Served, not filtered on. 'legend-pass' is a LEGACY label from when the paid web plan was called Legend; it sits on the majority of rows and does not say who can read the body here. On this endpoint every module body (get_academy_module) is opened by an MCP Pass or Firm Pass key, whatever this field says. The site stopped rendering this field on 2026-07-26; this endpoint still serves the raw value."
    • Changedfind_opportunities1 field changed
      • changedOutput schema / properties / rows / items / properties / application_link / description
        Previous value: -"`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)."New value: +"`public` (source_url is served) or `members_only` (the link to the original listing is the paid deliverable, opened by an MCP Pass or Firm Pass key; the row and its facts stay public)."
    • Changedsearch_news1 field changed
      • addedInput schema / properties / scope
        Added value: +{
        +  "description": "Editorial scope, set by one deterministic rule (2026-11-07): 'sap' = an SAP product or SAP itself named in the title or first sentence, or an SAP source; 'ecosystem' = adjacent data platforms, neighbouring ERP vendors, regulation, or SAP mentioned further down; 'general' = general AI. Pass scope:'sap' for SAP news — the unfiltered corpus is mostly 'general'.",
        +  "enum": [
        +    "sap",
        +    "ecosystem",
        +    "general"
        +  ],
        +  "type": "string"
        +}
  2. 1 tool update
    • Changedfind_answers1 field changed
      • changedInput schema / properties / lang / enum
        Previous value: -[
        -  "en",
        -  "fr",
        -  "de"
        -]New value: +[
        +  "EN",
        +  "FR",
        +  "DE"
        +]
  3. 1 tool update
    • Addedfind_answers
  4. 1 tool update
    • Changedget_day_rate_benchmark2 fields changed
      • addedOutput schema / properties / rows / items / properties / daily_rate_max_usd
        Added value: +{
        +  "description": "DEPRECATED — read daily_rate_max + currency.",
        +  "type": [
        +    "number",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / rows / items / properties / daily_rate_min_usd
        Added value: +{
        +  "description": "DEPRECATED — read daily_rate_min + currency.",
        +  "type": [
        +    "number",
        +    "null"
        +  ]
        +}
  5. 1 tool update
    • Changedget_academy_module1 field changed
      • addedInput schema / properties / lang
        Added value: +{
        +  "description": "Serve this language only. Omit it to get all three, unless they would exceed the response ceiling — then English alone is served and filters.lang says so.",
        +  "enum": [
        +    "en",
        +    "fr",
        +    "de"
        +  ],
        +  "type": "string"
        +}
  6. 1 tool update
    • Changedget_day_rate_benchmark3 fields changed
      • addedOutput schema / properties / rows / items / properties / daily_rate_max_zar
        Added value: +{
        +  "description": "DEPRECATED — read daily_rate_max + currency.",
        +  "type": [
        +    "number",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / rows / items / properties / daily_rate_median_zar
        Added value: +{
        +  "description": "DEPRECATED — read daily_rate_median + currency.",
        +  "type": [
        +    "number",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / rows / items / properties / daily_rate_min_zar
        Added value: +{
        +  "description": "DEPRECATED — read daily_rate_min + currency.",
        +  "type": [
        +    "number",
        +    "null"
        +  ]
        +}
  7. 2 tool updates
    • Changedlist_firm_kinds1 field changed
      • addedOutput schema / properties / rows / items / properties / label
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
    • Changedsearch_firms1 field changed
      • addedOutput schema / properties / rows / items / properties / kind_label
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
  8. 1 tool update
    • Changedfind_opportunities3 fields changed
      • addedInput schema / properties / eligibility
        Added value: +{
        +  "description": "WHO MAY APPLY to a remote posting, read from the posting's own text: `open` (it explicitly opens the role across borders — worldwide, anywhere, a time-zone band such as EMEA/CET hours, nearshore welcome), `restricted` (it requires residence, citizenship, work authorisation, a clearance or US W-2 status somewhere, or scopes the remote work to a region — `eligibility_region` on the row names it when stated), `unstated` (it says nothing). Combine with remote_mode=\"remote\" for the contractor abroad. AN UNSTATED ROW IS NOT AN OPEN ROW: most remote postings say nothing about where the contractor may be, so `open` sets them aside and `_meta.eligibility_undeclared` counts how many remote rows THIS call read are silent. Classified deterministically from title, location and (promoted leg) description; the site-radar leg publishes no description, so its rows are mostly `unstated`.",
        +  "enum": [
        +    "open",
        +    "restricted",
        +    "unstated"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / rows / items / properties / eligibility
        Added value: +{
        +  "description": "Who may apply, read from the posting's own text: `open`, `restricted` or `unstated`. `unstated` means the text does not say — never read it as open.",
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / rows / items / properties / eligibility_region
        Added value: +{
        +  "description": "The ISO-3166-1 alpha-2 country, or EU / EMEA, the text names for that opening or restriction. Null when it names none.",
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
  9. 1 tool update
    • Changedget_day_rate_benchmark1 field changed
      • changedInput schema / properties / specialisation / description
        Previous value: -"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."New value: +"A specialisation code, matched exactly. The live list is `_meta.available_specialisations` on every call — no list is kept here, because a written one went stale. Codes are NOT evenly spread across countries: read the rows a country filter returns. A code this aggregate does not hold (bdc, joule) returns 0 rows and the available codes; it never widens to a neighbouring band. 0 rows here is an absence in THIS aggregate only — see the tool description for what the website's subscriber band covers and where no rate exists at any tier."
  10. 2 tool updates
    • Changedfind_partner_candidates2 fields changed
      • changedInput schema / properties / kind / description
        Previous value: -"Restrict to one provider kind (placement agencies, ESN/SI practices, Big-4, SAP partners, platforms). Communities, schools and public bodies are never in this population."New value: +"Restrict to one provider kind (placement agencies, ESN/SI practices, Big-4, SAP partners, platforms). SAP's own entities, communities, schools and public bodies are never in this population."
      • changedInput schema / properties / kind / enum
        Previous value: -[
        -  "agency_placement",
        -  "professional_services_esn",
        -  "professional_services_big4",
        -  "vendor_partner",
        -  "vendor_sap",
        -  "platform_marketplace",
        -  "other"
        -]New value: +[
        +  "agency_placement",
        +  "professional_services_esn",
        +  "professional_services_big4",
        +  "vendor_partner",
        +  "platform_marketplace",
        +  "other"
        +]
    • Changedget_firm_intel1 field changed
      • changedInput schema / properties / name / description
        Previous value: -"Firm name, matched case-insensitively. Omit to browse the corpus by data completeness."New value: +"Firm name, matched case-insensitively; an exact name ranks first, then a name starting with it, then the other matches. Omit to browse the corpus by data completeness."
  11. 1 tool update
    • Changedquery_knowledge_graph1 field changed
      • changedInput schema / properties / edge_type / description
        Previous value: -"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."New value: +"Restrict a walk to one relation. The authority is `_meta.available_edge_types`, computed on every call — no list is kept here: a four-name list once stood here while the projection served five, then a five-name list while it served six (`broader`)."

Related MCP Connectors

Related MCP Servers

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.