{"schema_version":"verify.compare.v1","generated_at":"2026-09-29T00:46:09.636665+00:00","count":1,"missing_servers":[],"results":[{"server_id":"ai.analyticslegends/sap-analytics","display_name":"Analytics Legends — SAP Analytics Intelligence","profile_url":"https://verify.sentinelsignal.io/servers/ai.analyticslegends/sap-analytics","compare_url":"https://verify.sentinelsignal.io/compare?server=ai.analyticslegends%2Fsap-analytics","trust_summary_url":"https://verify.sentinelsignal.io/v1/servers/ai.analyticslegends/sap-analytics/trust-summary","claimed":false,"verified_publisher":false,"claim_status":"unclaimed","badge_url":"https://verify.sentinelsignal.io/badge/ai.analyticslegends/sap-analytics.svg","report_url":"https://verify.sentinelsignal.io/v1/servers/ai.analyticslegends/sap-analytics/report","policy_url":"https://verify.sentinelsignal.io/v1/servers/ai.analyticslegends/sap-analytics/policy","evidence_url":"https://verify.sentinelsignal.io/api/v1/servers/ai.analyticslegends/sap-analytics/evidence","commerce_signal":null,"payment_capable":null,"delegation_level":null,"risk_flags":[],"strengths":["report_available","policy_available","badge_available"],"limitations":["unclaimed_profile","publisher_not_verified"],"last_seen":null,"last_scored":"2026-09-28T21:46:19.872711+00:00","recommended_agent_action":"allow_with_policy_review","observed_attention":{"schema":"verify.observed_attention.v1","window_days":30,"level":"none","label":"No observed attention","summary":"No recent machine-readable trust or discovery activity observed for this server.","segments":{"useful_ai_user":{"level":"none","observed":false,"description":"AI-assisted user sessions such as ChatGPT/User or Claude/User."},"machine_trust_evaluator":{"level":"none","observed":false,"description":"Synthetic sessions inspecting multiple trust surfaces such as report, policy, ledger, badge, trust-summary, or compare."},"possible_agent_or_script":{"level":"none","observed":false,"description":"Structured direct sessions with rapid profile, compare, report, policy, badge, or trust-surface fan-out."},"isolated_machine_surface":{"level":"none","observed":false,"description":"Aged-out direct synthetic singleton sessions that touched a machine-readable trust surface without becoming a broader evaluator."},"ai_crawler":{"level":"none","observed":false,"description":"Known AI crawler activity such as ClaudeBot, GPTBot, or similar crawlers."},"search_crawler":{"level":"none","observed":false,"description":"Search and SEO crawler activity."},"browser_like_automation":{"level":"none","observed":false,"description":"Browser-like synthetic sessions with rapid structured endpoint activity."},"confirmed_human":{"level":"none","observed":false,"description":"Confirmed browser-session human activity."}},"surfaces_observed":{"server_profile":false,"compare":false,"compare_json":false,"compare_api":false,"report_json":false,"policy":false,"ledger":false,"badge_metadata":false,"badge_svg":false,"trust_summary":false,"mcp_tool":false},"claim_prompt":{"recommended":false,"reason":"No claim prompt is recommended from observed attention in the current window."},"notes":["Observed attention is based on segmented first-party telemetry.","Crawler and evaluator activity is not treated as confirmed human demand.","Public levels are bucketed to avoid exposing raw traffic counts."]},"owner_activation":{"claim_recommended":false,"reason":"no_observed_attention"}}],"servers":[{"namespace":"ai.analyticslegends","name":"sap-analytics","title":"Analytics Legends — SAP Analytics Intelligence","description":"AI agent for SAP analytics: firms, day rates, contract radar, news, concepts, studies","homepage_url":"https://analyticslegends.ai","docs_url":null,"icon_url":null,"support_url":null,"remote_url":"https://analyticslegends.ai/mcp","server_card_url":null,"latest_version":"1.0.6","current_status":"healthy","current_score":67.19,"transport_type":"streamable-http","has_oauth":false,"has_dcr":false,"has_prompts":true,"tool_count":20,"current_validation_schema_version":"8058defc70ca932c","last_validated_at":"2026-09-28T21:46:19.872711+00:00","registry_source":"official_registry","registry_identifier":"ai.analyticslegends/sap-analytics","canonical_identifier":null,"current_score_components":{"auth_operability_score":2.0,"error_contract_score":1.0,"rate_limit_semantics_score":2.0,"schema_completeness_score":3.0,"backward_compatibility_score":4.0,"slo_health_score":3.0,"security_hygiene_score":3.0,"task_success_score":4.0,"trust_confidence_score":4.0,"abuse_noise_ratio_score":4.0,"prompt_contract_score":3.0,"resource_contract_score":4.0,"discovery_metadata_score":2.0,"registry_consistency_score":2.0,"installability_score":4.0,"session_semantics_score":4.0,"tool_surface_design_score":4.0,"result_shape_stability_score":4.0,"oauth_interop_score":0.0,"recovery_semantics_score":1.0,"maintenance_signal_score":4.0,"adoption_signal_score":3.0,"freshness_confidence_score":4.0,"transport_fidelity_score":4.0,"spec_recency_score":2.0,"session_resume_score":3.0,"step_up_auth_score":0.0,"transport_compliance_score":2.0,"utility_coverage_score":1.0,"advanced_capability_coverage_score":1.0,"connector_publishability_score":2.0,"tool_snapshot_churn_score":4.0,"connector_replay_score":4.0,"request_association_score":0.0,"interactive_flow_safety_score":0.0,"action_safety_score":3.0,"official_registry_presence_score":4.0,"safety_transparency_score":2.0,"tool_capability_clarity_score":4.0,"destructive_operation_safety_score":3.0,"egress_ssrf_resilience_score":2.0,"execution_sandbox_safety_score":4.0,"data_exfiltration_resilience_score":1.0,"least_privilege_scope_score":3.0,"secret_handling_hygiene_score":3.0,"dependency_supply_chain_signal_score":1.0,"input_sanitization_safety_score":3.0,"tool_namespace_clarity_score":4.0},"capability_taxonomy":[],"machine_summary":{},"taxonomy_tags":[],"score_decomposition":[],"validation_diff":null,"tool_snapshot_diff":null,"connector_replay":{},"request_association":{},"production_readiness":{"code":"safe_for_evaluation","label":"Safe for evaluation","reason":"The server is suitable for evaluation, but remaining gaps should be resolved before broad production use.","badge":"score-medium","critical_alerts":0,"high_or_critical_alerts":0,"degraded_by_active_alerts":false},"recommended_for":[],"history_summary":{},"validation_timeline":[],"evidence_confidence":{"score":100.0,"label":"high","reason":"Based on 20 recent validations, 18 captured checks, and validation age of 3.0 hours.","live_check_count":18,"validation_age_hours":3.0,"basis":{"evidence_bearing_validations":20,"affirmative_live_check_count":18,"validation_age_hours":3.0,"freshness_threshold_hours":24}},"incident_feed":[],"disputes":[],"remediations":[],"client_remediation_modes":[],"client_profiles":[],"client_readiness_verdicts":[],"publishability_policy_profiles":[],"compatibility_fixtures":[],"install_snippets":{},"aliases":[],"raw_evidence":{"checks":{"probe_noise_resilience":{"status":"ok","latency_ms":152.5,"details":{"url":"https://analyticslegends.ai/robots.txt","http_status":200,"headers":{"content-type":"text/plain; charset=utf-8","strict-transport-security":"max-age=31536000; includeSubDomains; preload"},"validation_disallowed":false,"consent_error":null}},"server_card":{"status":"error","latency_ms":64.99,"details":{"url":"https://analyticslegends.ai/.well-known/mcp/server-card.json","error":"Client error '404 Not Found' for url 'https://analyticslegends.ai/.well-known/mcp/server-card.json'\nFor more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404"}},"oauth_protected_resource":{"status":"error","latency_ms":359.25,"details":{"url":"https://analyticslegends.ai/.well-known/oauth-protected-resource","error":"Client error '404 Not Found' for url 'https://analyticslegends.ai/.well-known/oauth-protected-resource/'\nFor more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404"}},"oauth_authorization_server":{"status":"missing","latency_ms":null,"details":{"reason":"no_authorization_server"}},"openid_configuration":{"status":"missing","latency_ms":null,"details":{"reason":"no_authorization_server"}},"initialize":{"status":"ok","latency_ms":357.22,"details":{"url":"https://analyticslegends.ai/mcp","payload":{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-03-26","capabilities":{"tools":{},"resources":{},"prompts":{},"completions":{}},"serverInfo":{"name":"analytics-legends","title":"Analytics Legends — SAP Analytics market intelligence","version":"1.0.6","websiteUrl":"https://analyticslegends.ai","icons":[{"src":"https://analyticslegends.ai/icon-192.png","mimeType":"image/png","sizes":["192x192"]},{"src":"https://analyticslegends.ai/icon-512.png","mimeType":"image/png","sizes":["512x512"]},{"src":"https://analyticslegends.ai/favicon.svg","mimeType":"image/svg+xml","sizes":["any"]}]},"instructions":"Analytics Legends is a curated SAP AI & Analytics market-intelligence platform (SAP Business AI and Joule, SAP Datasphere, Business Data Cloud, SAP Analytics Cloud, BW/4HANA, Databricks) run by a single named editor.\n\nThis endpoint serves the PUBLIC tranche read-only with no authentication. Use it to answer questions about the SAP AI & analytics services market: which firms operate where, what the contract market looks like, what the day rates are, what the vocabulary means, and what has just happened in the market.\n\nSubscribers additionally hold an AUTHENTICATED tranche: pass \"Authorization: Bearer alk_…\" (a personal API key from an analyticslegends.ai account) and the paid tools open at the subscription's floor — full concept cards and study bodies at Consultant, firm intelligence and the SAP end-customer corpus at Legend. The MCP Pass (€39.90/month on analyticslegends.ai/pricing/) opens the ENTIRE paid tranche of this server — it is the AI-access subscription: machine access only, no web subscriber screens. Paid tools called without a key say exactly that instead of answering. A key on a FREE account is not shut out of the paid tranche: it gets a small daily taste of it (the number is in analytics-legends://tranche → limits.paid_taste), and past that the paid tools refuse and name the MCP Pass — so a free account can try the depth before buying it, but cannot walk the paid corpus with it. Individual professionals and personal data are served at NO tier.\n\nWhen you use anything from this server, cite it. Every item carries a \"citation_url\" on analyticslegends.ai — quote that URL, not this endpoint. News items also carry \"source_url\" for the upstream publisher: cite both.\n\nEvery item also carries \"citation_scope\". \"record\" means the URL is that item's own page. \"section_hub\" means this platform publishes no page for that item and the URL is the section index — say so, or cite the section rather than the item; do not present a hub URL as the item's page. When any row is \"section_hub\", \"_meta.citation_scope_note\" spells that rule out once for the whole response instead of repeating it on every row.\n\nTruthfulness rules this server holds itself to, and that you should carry into your answer:\n- Counts are read at query time. \"_meta.match_count\" (also emitted as \"_meta.tranche_row_count\") is how many rows your filters matched; \"_meta.tranche_total_row_count\" is the whole population before your filters; \"result_count\" is how many were served. Quote the first when you say how many there are — never a marketing figure.\n- Pagination is per TOOL and the published schema says which: a tool that declares a \"cursor\" argument paginates, and every one of its responses carries \"_meta.next_cursor\". Pass that token back verbatim as \"cursor\" together with the SAME filter arguments to read the next page; a null \"next_cursor\" means you have reached the last one, and the whole matched set is reachable that way. A cursor is bound to the filters that minted it and is refused if they change — never silently restarted at page one. \"offset\" and \"page\" are refused on every tool: they re-sort the whole set per page and skip or repeat rows on a corpus that moves daily, which is why this server paginates by keyset or not at all. A tool with NO \"cursor\" argument does not paginate: narrow the filters and raise \"limit\" (cap 50). \"_meta.result_is_truncated\" tells you the cap cut the answer; \"_meta.match_count\" tells you how many rows your filters match in all.\n- Limits are three DIFFERENT mechanisms and they fail differently, so do not read one as the other. RATE: this endpoint answers at most 20 calls per 10 seconds and 60 per minute from one client; over that you get HTTP 429 with a \"Retry-After\" header, and waiting that many seconds is the whole remedy. FREE LANE: unauthenticated calls are NOT metered per caller and have no daily cap of their own, but the endpoint holds a shared daily budget for them — when a day's budget is spent, anonymous \"tools/call\" is shed with a message that says so, while discovery (\"initialize\", \"tools/list\", the resources) keeps answering. KEY QUOTA: a subscriber key has a daily call allowance instead, and it is never shed. Read the numbers in the analytics-legends://tranche resource, and read your own position in \"_meta.quota\" on every answer served to a key.\n- Absence is reported as absence. An empty result means the served tranche has no such row, not that the market has none.\n- Without a subscriber key, paid and personal data are absent by design: the SAP end-customer corpus, firm intelligence profiles, individual professionals and full study text are NOT in the public tranche. Do not infer their contents.\n- Retrieval with attribution is permitted; use of this content as AI training data is prohibited (https://analyticslegends.ai/.well-known/agent.json)."}},"http_status":200,"headers":{"content-type":"application/json","mcp-protocol-version":"2025-03-26","strict-transport-security":"max-age=31536000; includeSubDomains; preload"}}},"protocol_version_probe":{"status":"warning","latency_ms":null,"details":{"claimed_version":"2025-03-26","validator_protocol_version":"2025-03-26","latest_known_version":"2025-11-25","releases_behind":2,"lag_days":244}},"tools_list":{"status":"ok","latency_ms":192.28,"details":{"url":"https://analyticslegends.ai/mcp","payload":{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"search_firms","title":"Search the SAP analytics firm directory","description":"Search the published Analytics Legends directory of SAP analytics service providers — placement agencies, Big-4 and ESN practices, SAP vendors, platforms and community groups — by country, 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: the whole matched set is reachable — pass `_meta.next_cursor` back as `cursor` with the same filters until it is null. 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.","inputSchema":{"type":"object","properties":{"query":{"type":"string","maxLength":200,"description":"Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim."},"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO-3166-1 alpha-2 country code, e.g. DE, FR, CH."},"kind":{"type":"string","enum":["agency_placement","professional_services_big4","professional_services_esn","vendor_sap","vendor_partner","platform_marketplace","community_group","training_institution","client_enterprise","other"],"description":"Restrict to one organisation kind. This list is the vocabulary the corpus holds today, not a frontier — call list_firm_kinds for the live one. A malformed code is refused; a well-formed code the corpus does not hold returns no rows. Neither case is silently ignored, and neither widens the result."},"module":{"type":"string","description":"Restrict to organisations with a DECLARED link to one SAP module/product code (UPPERCASE snake_case, e.g. DATASPHERE, BDC, SAC, BW4HANA, S4HANA, JOULE — case-insensitive on input). The declared links are structured data, far more selective than free text: `count_firms_by {by:\"module\"}` gives the live vocabulary with counts. A minority of the directory declares any module at all, so this filter finds the DECLARED specialists — absence from the result means no declared link, never that the firm does not work on the module."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10,"description":"Max rows (hard cap 50)."},"cursor":{"type":"string","maxLength":512,"description":"Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}},"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"slug":{"type":["string","null"]},"name":{"type":["string","null"]},"kind":{"type":["string","null"]},"hq_country":{"type":["string","null"]},"hq_city":{"type":["string","null"]},"region":{"type":["string","null"]},"website":{"type":["string","null"]},"jobs_url":{"type":["string","null"]},"claim":{"type":["string","null"]},"size_bracket":{"type":["string","null"]},"founded_year":{"type":["integer","null"]},"sap_signal_band":{"type":["string","null"]},"last_verified_at":{"type":["string","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Search the SAP analytics firm directory","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"count_firms_by","title":"Count the firm directory by country, kind, module or SAP signal","description":"Answer a COUNTING question about the published firm directory in one call: how many organisations per country, 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.","inputSchema":{"type":"object","properties":{"by":{"type":"string","enum":["country","kind","module","sap_signal_band"],"description":"Which facet to count on. Required — there is no default worth guessing."},"query":{"type":"string","maxLength":200,"description":"Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim."},"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO-3166-1 alpha-2 country code, e.g. DE, FR, CH."},"kind":{"type":"string","description":"Restrict to one organisation kind before counting, same vocabulary as search_firms. Combining it with `by:\"kind\"` is legal and returns that single bucket."},"module":{"type":"string","description":"Restrict to organisations with a DECLARED link to one SAP module code before counting, same vocabulary as search_firms' `module`. Combining it with `by:\"module\"` is legal and returns that single bucket (plus the null bucket)."}},"required":["by"],"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"value":{"type":["string","null"]},"n":{"type":["integer","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Count the firm directory by country, kind, module or SAP signal","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"get_firm","title":"Get one firm's published profile","description":"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 ~97 % of rows (re-measured 2026-08-14 on the published tranche: 96,8 %), meaning none declared here, never that the firm has no partners. Does not return the paid firm-intelligence profile, contacts, or any person.","inputSchema":{"type":"object","properties":{"slug":{"type":"string","description":"The DATABASE slug, taken verbatim from search_firms.rows[].slug. It is not always the web slug in citation_url: a minority of published rows carry a numeric firm id instead (365 of them on 2026-08-09 — the population is read at query time and returned as `_meta.tranche_total_row_count`, never written down here). get_firm{slug:\"00393\"} is GULP, whose page is /companies/gulp/. Deriving a slug from the citation URL fails on those rows, and deriving it from the NAME is not safe either; carry rows[].slug across instead. A slug this tool refuses is not proof the firm is absent from the market or even from the database — the published tranche is an editorial subset, and a row the editor has not published is refused here exactly as a wrong slug is."}},"required":["slug"],"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"slug":{"type":["string","null"]},"name":{"type":["string","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Get one firm's published profile","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"list_firm_kinds","title":"List firm kinds with live counts","description":"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.","inputSchema":{"type":"object","properties":{},"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"kind":{"type":["string","null"]},"n":{"type":["integer","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"List firm kinds with live counts","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"list_freelance_platforms","title":"List the CV/profile platforms a consultant can sign up on","description":"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.","inputSchema":{"type":"object","properties":{"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO-3166-1 alpha-2 country code, e.g. DE, FR, CH."},"platform_type":{"type":"string","description":"Restrict to one platform type, lowercase snake_case. The live vocabulary with counts is `_meta.available_platform_types` on every response — a well-formed unknown value returns no rows, it never widens the result."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10,"description":"Max rows (hard cap 50)."},"cursor":{"type":"string","maxLength":512,"description":"Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}},"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"slug":{"type":["string","null"]},"name":{"type":["string","null"]},"platform_type":{"type":["string","null"]},"signup_url":{"type":["string","null"],"description":"The platform's own signup/profile-creation page, verified on assessed_at."},"hq_country":{"type":["string","null"]},"confidence":{"type":["string","null"],"description":"Editorial confidence in the signup assessment."},"assessed_at":{"type":["string","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"List the CV/profile platforms a consultant can sign up on","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"find_opportunities","title":"Search the public SAP analytics contract radar","description":"Search every SAP contract and permanent-role posting Analytics Legends publishes to an ANONYMOUS visitor — the same population a human browses on /opportunities/, where each posting has its own prerendered page. 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 EVERY active row of that leg — an invariant held since 2026-07-31, not a snapshot). 🔴 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 Consultant-tier deliverable. 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.","inputSchema":{"type":"object","properties":{"query":{"type":"string","maxLength":200,"description":"Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim."},"location":{"type":"string","description":"City or place, matched case-insensitively as a substring of the posting's location. The promoted leg is all-German (Hamburg, Frankfurt am Main, Bremen, Munich, Cologne, Dortmund, Hanover, Landshut, Mannheim, Stuttgart); the site-radar leg is worldwide."},"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO-3166-1 alpha-2 code, applied to both legs as a predicate on the row's own country_code. It NO LONGER selects the site-radar leg alone: the promoted feed carried country_code on almost none of its rows until 2026-08-28 and now carries it on most, so a country filter now returns both legs. A row still without one is dropped because it does not match, not because its leg was excluded by assumption. `_meta.match_count_by_leg` shows what each leg contributed on YOUR call — read the split there, never from a figure quoted in this text."},"employment_type":{"type":"string","enum":["freelance","contract","permanent"],"description":"Restrict to one engagement type. THE RADAR IS MOSTLY PERMANENT, so a freelance or contract question answered off an unfiltered page is answered with salaried jobs. For the actual split, make the filtered call and read `_meta.tranche_total_row_count` — it is counted at query time. The promoted leg declared NO contract_type until 2026-08-28 and now declares one on most of its rows, so a value here no longer drops that leg wholesale — only the rows still silent. THOSE ROWS ARE NOT A FOURTH TYPE AND NOT PERMANENT ONES: `_meta.available_employment_types` counts only what declares, and `_meta.employment_type_undeclared` carries the rest, so the two together are the 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."},"remote_mode":{"type":"string","description":"Restrict to one work-location policy: `remote`, `hybrid` or `onsite`. READ THIS BEFORE ANSWERING A REMOTE QUESTION: a large share of the radar declares no policy at all (`_meta.remote_mode_undeclared` carries the live count — roughly half the radar when last measured, and a frozen pair written here drifted ~30% in two days), and an undeclared row is NOT an on-site row — it is a posting that does not say. Any value here therefore sets those rows aside rather than classifying them, exactly as the site's own filter does, and `_meta.remote_mode_undeclared` reports how many were set aside. The promoted leg carries its own `remote_mode` column and is filtered by the same predicate. Read `_meta.available_remote_modes` for the live spread before assuming a value exists."},"lang":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"Reading language for the TITLE — 'EN' (default), 'FR' or 'DE'. This is a RENDERING choice, never a filter: it changes which string `title` carries, never which rows come back. Read `title_lang` on every row for the language actually served: it differs from what you asked for exactly when that translation does not exist (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`."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10,"description":"Max rows (hard cap 50)."},"cursor":{"type":"string","maxLength":512,"description":"Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}},"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"title":{"type":["string","null"]},"title_lang":{"type":["string","null"],"description":"ISO-639-1 language the SERVED `title` is written in. READ IT ON EVERY ROW: it is what you asked for in `lang` when that translation exists, and the advertiser's own language when it does not (the live FR/DE coverage is counted on every response in `_meta.untranslated_leg`). Null when the harvest chain could not decide — on some site-radar rows too, counted in `_meta.untranslated_radar_rows` — and on every promoted-leg row, which carries no translated column at all. ⚠️ THIS FIELD CHANGED REFERENT ON 2026-09-04: until then it named the language the ADVERTISER wrote in — that fact now lives in `source_lang`. The two coincided while no translation was served and diverge from the first one that is."},"source_lang":{"type":["string","null"],"description":"ISO-639-1 language the ADVERTISER wrote the title in, measured by the harvest chain and never changed by `lang` — 'en' on 1,566 rows, 'de' on 337 (2026-08-23). Null when the chain could not decide, and on the promoted leg. Compare it with `title_lang` to know whether the title you are quoting is the advertiser's own words or this platform's rendering of them: a harvested posting is a third party's text, and saying which of the two you are citing is the only honest way to quote it."},"firm_name":{"type":["string","null"]},"location":{"type":["string","null"]},"country_code":{"type":["string","null"],"description":"ISO-3166-1 alpha-2 of the posting's own country. Null on almost all of the promoted leg."},"seniority":{"type":["string","null"]},"remote_mode":{"type":["string","null"],"description":"The posting's declared work-location policy (`remote` / `hybrid` / `onsite`). NULL means the posting does not say — never read it as on-site."},"posted_at":{"type":["string","null"]},"source_url":{"type":["string","null"]},"employment_type":{"type":["string","null"]},"expires_at":{"type":["string","null"]},"rate_band":{"type":["object","null"],"description":"Editorial benchmark for this posting's (seniority × product × region) cell — NOT a rate the employer offered. `basis` and `kind` are inside the object on purpose, so no extraction can lift the numbers away from what they mean. 2026-08-29: this band is a SUBSCRIBER surface and is no longer carried by the public radar file this lane reads — expect it to be null here. The posting's OWN published rate, when it has one, stays in currency / daily_rate_min / daily_rate_max."},"id":{"type":["string","null"],"description":"The posting's identity — stable across calls, key for dedup."},"leg":{"type":["string","null"],"description":"`promoted` or `site_radar` — which of the two merged public legs served this row."},"canonical_id":{"type":["string","null"],"description":"Set when the site folded this posting into another one it judged identical: `citation_url` is then the page of THAT posting (`canonical_id`). When both are matched, only the canonical row is served and `_meta.duplicates_folded` counts the fold. Null otherwise."},"application_link":{"type":["string","null"],"description":"`public` (source_url is served) or `members_only` (the link to the original listing is the paid Consultant-tier deliverable; the row and its facts stay public)."},"skills":{"type":["array","null"],"description":"Skills the posting names. Null when it names none."},"category":{"type":["string","null"]},"description":{"type":["string","null"],"description":"Posting text, HTML stripped, clamped. Null on the radar leg."},"currency":{"type":["string","null"]},"daily_rate_min":{"type":["number","null"],"description":"Only when the source declares a DAILY rate period — never converted from other periods."},"daily_rate_max":{"type":["number","null"]},"rate_period":{"type":["string","null"]},"duration_months":{"type":["number","null"]},"salary_min":{"type":["number","null"],"description":"The posting's own advertised salary, YEARLY (see `salary_period`). Null when none was published, and null when the published amount cannot be a yearly salary — `salary_withheld_reason` then says why."},"salary_max":{"type":["number","null"]},"salary_period":{"type":["string","null"],"description":"`year` when salary_min/salary_max are served. Null otherwise — never a guessed unit."},"salary_withheld_reason":{"type":["string","null"],"description":"Why a published salary was NOT served: `below_annual_floor` (the low end is below any yearly salary in that currency — a monthly or daily figure filed as a salary) or `board_estimate` (the job board's own min = max estimate, not the employer's). The amount is withheld, never converted. Null when nothing was withheld."},"source":{"type":["string","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Search the public SAP analytics contract radar","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"search_news","title":"Search SAP analytics market news","description":"Search the Analytics Legends market-news corpus. It is watched FOR SAP 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 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.","inputSchema":{"type":"object","properties":{"query":{"type":"string","maxLength":200,"description":"Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim."},"category":{"type":"string","description":"Category code, matched case-insensitively. The live vocabulary is NOT written here — read `_meta.available_categories` on any response: every category label this corpus holds right now, with its active-row count, counted at query time. A written list held 21 values while the corpus held 22. One bucket needs a warning. 'SAC' is the noisiest label in this corpus because the acronym collides with unrelated ones — Windows 'Smart App Control', and the surname 'Sacks'. A 2026-07-30 cleanup reclassified half that bucket to AI for carrying no SAP signal at all; the collision pressure is structural and the bucket has kept growing since. For genuine SAC product news, pair category:'SAC' with query:'analytics cloud'."},"published_since":{"type":"string","description":"Lower bound on `published_at`, inclusive, as YYYY-MM-DD. Without a bound a period question is only answerable by walking pages — and `_meta.match_count` then counts the QUERY, not the period, so any figure quoted for the window would be wrong."},"published_until":{"type":"string","description":"Upper bound on `published_at`, INCLUSIVE of the day named, as YYYY-MM-DD. Combine with `published_since` for a window; `_meta.match_count` then describes that window, which is what makes it quotable."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10,"description":"Max rows (hard cap 50)."},"cursor":{"type":"string","maxLength":512,"description":"Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}},"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"title":{"type":["string","null"]},"published_at":{"type":["string","null"]},"source_name":{"type":["string","null"]},"source_url":{"type":["string","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Search SAP analytics market news","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"search_concepts","title":"Search the SAP analytics concept encyclopaedia","description":"Search the SAP 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 Consultant-tier: 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.","inputSchema":{"type":"object","properties":{"query":{"type":"string","maxLength":200,"description":"Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim."},"category":{"type":"string","description":"Concept category, matched case-insensitively as an exact value OR a prefix — so category:\"datasphere\" reaches 'Datasphere Core'. The values are long human labels, not codes. DO NOT GUESS THEM FROM THIS TEXT: the live vocabulary with a row count per label comes back as `_meta.available_categories` on EVERY call, including a call that matched nothing. A list written here would say 14 labels with 2026-07-30 counts; the corpus holds 15 today, and five of those counts have moved. Read the envelope, not the prose."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10,"description":"Max rows (hard cap 50)."},"cursor":{"type":"string","maxLength":512,"description":"Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}},"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"slug":{"type":["string","null"]},"title":{"type":["string","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Search the SAP analytics concept encyclopaedia","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"get_concept","title":"Concept metadata and editor's summary (public)","description":"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.","inputSchema":{"type":"object","properties":{"slug":{"type":"string","description":"Concept slug from search_concepts."}},"required":["slug"],"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"slug":{"type":["string","null"]},"title":{"type":["string","null"]},"summary":{"type":["string","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Concept metadata and editor's summary (public)","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"list_studies","title":"List the deep-research studies (metadata only)","description":"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 Consultant-tier deliverable, served by `get_study` on this same endpoint with a subscriber 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.","inputSchema":{"type":"object","properties":{"query":{"type":"string","maxLength":200,"description":"Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim."},"lang":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO-639-1 language of the EDITION to list, e.g. en, fr or de — each study is published as one row per language. Omit it to see every edition of every study; the live list of languages actually present comes back as `_meta.available_languages` on every response. A well-formed code the corpus does not hold returns 0 rows."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10,"description":"Max rows (hard cap 50)."},"cursor":{"type":"string","maxLength":512,"description":"Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}},"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"slug":{"type":["string","null"]},"lang":{"type":["string","null"]},"editions":{"type":["array","null"],"items":{"type":"string"}},"title":{"type":["string","null"]},"as_of":{"type":["string","null"]},"word_count":{"type":["integer","null"]},"access":{"type":["string","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"List the deep-research studies (metadata only)","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"get_day_rate_benchmark","title":"Public SAP analytics day-rate aggregate","description":"The PUBLIC day-rate aggregate for SAP 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.","inputSchema":{"type":"object","properties":{"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO-3166-1 alpha-2 country code, e.g. DE, FR, CH."},"specialisation":{"type":"string","description":"One of the codes the aggregate actually holds — analytics_all, bw, bw4hana, bw4hana_sac, sac, datasphere (2026-08-09; the live list comes back as `_meta.available_specialisations` on every call). They are NOT evenly spread across countries: DE holds analytics_all only, at three seniorities, and datasphere exists for FR alone, as a median with confidence 'low'. There is no bdc row and no joule row in THIS aggregate — but the platform does price BDC: `find_opportunities` carries a panel-inferred band on the live postings, €1,000–€1,400/day P25–P75 for Senior BDC on 52 German postings (2026-08-10). A code this aggregate does not hold returns 0 rows and the available codes; it never widens to a neighbouring band, and 0 here does not mean the platform is silent."},"seniority":{"type":"string","description":"e.g. senior, principal."}},"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"country":{"type":["string","null"]},"specialisation":{"type":["string","null"]},"seniority":{"type":["string","null"]},"currency":{"type":["string","null"],"description":"ISO-4217 unit of every daily_rate_* amount on THIS row (EUR, GBP, CHF) — never an envelope constant."},"daily_rate_min":{"type":["number","null"],"description":"Lower bound of the published band, in `currency`."},"daily_rate_max":{"type":["number","null"],"description":"Upper bound of the published band, in `currency`."},"daily_rate_median":{"type":["number","null"],"description":"Median when the source publishes one, in `currency`."},"daily_rate_p10":{"type":["number","null"],"description":"10th percentile when the source publishes one, in `currency`."},"daily_rate_p90":{"type":["number","null"],"description":"90th percentile when the source publishes one, in `currency`."},"sample_size":{"type":["integer","null"],"description":"The sample the SOURCE states behind this row; null when it states none — never estimated."},"sample_basis":{"type":["string","null"],"description":"What `sample_size` counts (profiles, vacancies…), when the source says."},"basis":{"type":["string","null"],"description":"external_published_median | external_published_range | panel — see /api/market-rates.json _meta.basis_values."},"confidence":{"type":["string","null"]},"source":{"type":["string","null"]},"source_url":{"type":["string","null"]},"source_date":{"type":["string","null"]},"yoy_change_pct":{"type":["number","null"]},"trend":{"type":["string","null"]},"note":{"type":["string","null"]},"daily_rate_min_eur":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_min + currency."},"daily_rate_max_eur":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_max + currency."},"daily_rate_median_eur":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_median + currency."},"daily_rate_min_gbp":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_min + currency."},"daily_rate_max_gbp":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_max + currency."},"daily_rate_median_gbp":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_median + currency."},"daily_rate_p10_gbp":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_p10 + currency."},"daily_rate_p90_gbp":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_p90 + currency."},"daily_rate_min_chf":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_min + currency."},"daily_rate_max_chf":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_max + currency."},"daily_rate_min_aud":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_min + currency."},"daily_rate_max_aud":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_max + currency."},"daily_rate_median_aud":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_median + currency."},"daily_rate_min_nzd":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_min + currency."},"daily_rate_max_nzd":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_max + currency."},"daily_rate_median_nzd":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_median + currency."},"daily_rate_min_sgd":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_min + currency."},"daily_rate_max_sgd":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_max + currency."},"daily_rate_median_sgd":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_median + currency."},"daily_rate_min_jpy":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_min + currency."},"daily_rate_max_jpy":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_max + currency."},"daily_rate_median_jpy":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_median + currency."},"daily_rate_min_hkd":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_min + currency."},"daily_rate_max_hkd":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_max + currency."},"daily_rate_median_hkd":{"type":["number","null"],"description":"DEPRECATED — read daily_rate_median + currency."},"indicative":{"type":["boolean","null"],"description":"true = orientation only: the source is a proxy (non-SAP BI band, generic ERP, agency monthly contract or marketing average). Never quote it as the SAP analytics rate of its country."},"sap_scope":{"type":["string","null"],"description":"what the source actually measures: sap_analytics | sap_general | erp_general | bi_non_sap"},"source_type":{"type":["string","null"],"description":"primary_agency_guide | primary_job_ads | aggregator | marketing"},"source_period":{"type":["string","null"]},"conversion":{"type":["string","null"],"description":"how an hourly or monthly source figure was turned into a day rate"},"accessed":{"type":["string","null"],"description":"date the source was read (YYYY-MM-DD)"},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Public SAP analytics day-rate aggregate","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"list_sap_modules","title":"SAP analytics module taxonomy","description":"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.","inputSchema":{"type":"object","properties":{"query":{"type":"string","maxLength":200,"description":"Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10,"description":"Max rows (hard cap 50)."},"cursor":{"type":"string","maxLength":512,"description":"Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}},"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"code":{"type":["string","null"]},"label_en":{"type":["string","null"]},"category":{"type":["string","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"SAP analytics module taxonomy","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"find_academy_modules","title":"Search the Academy training catalogue","description":"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 a subscriber key (Consultant tier or above), which is the same door the €29.90 Consultant Pass opens on the site. On THIS endpoint the machine-access subscription is the MCP Pass (€39.90/month, analyticslegends.ai/pricing/), which opens the ENTIRE paid tranche from one key; the €29.90 Consultant Pass is its web-subscriber equivalent and opens the same tier floor here. `status` and `is_preview` are SERVED, never filtered on: they are the two flags the platform marks free access with, 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: pass `_meta.next_cursor` back as `cursor` with the same filters until it is null. Read `_meta.available_tracks` and `_meta.available_levels` — both counted on the served population at call time — before assuming a facet value exists.","inputSchema":{"type":"object","properties":{"query":{"type":"string","maxLength":200,"description":"Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim."},"track":{"type":"string","description":"Restrict to one track, by SLUG (`databricks-data-eng`) or by English name (`Databricks & Data Eng.`), matched case-insensitively. The live vocabulary with per-track counts is `_meta.available_tracks` on every response. The numeric track_id is deliberately NOT accepted — it is an internal counter, and passing `6` would look like naming a subject."},"level":{"type":"string","description":"Restrict to one level, matched case-insensitively: Beginner · Intermediate · Advanced · Expert. Counts in `_meta.available_levels`."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10,"description":"Max rows (hard cap 50)."},"cursor":{"type":"string","maxLength":512,"description":"Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}},"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":["string","null"],"description":"Module id, e.g. M001 — the value get_academy_module takes."},"slug":{"type":["string","null"]},"title_en":{"type":["string","null"]},"track_slug":{"type":["string","null"]},"level":{"type":["string","null"]},"duration_minutes":{"type":["number","null"]},"summary_en":{"type":["string","null"]},"status":{"type":["string","null"],"description":"Editorial access marker: 'available' or 'legend-pass'. Served, not filtered on. READ 'legend-pass' AS 'sold at the CONSULTANT tier': it is a LEGACY label from when the paid tier was called Legend, it sits on the majority of rows, and the tier that actually opens the body here is Consultant (get_academy_module). The site stopped rendering this field for exactly that reason on 2026-07-26; this endpoint still serves the raw value, so the LABEL is the stale half and the tier floor is the true one."},"is_preview":{"type":["boolean","null"],"description":"The second free-access marker. Does NOT coincide with status — read both."},"title_fr":{"type":["string","null"]},"summary_fr":{"type":["string","null"]},"track_name_en":{"type":["string","null"]},"track_name_fr":{"type":["string","null"]},"tags":{"type":["array","null"],"items":{"type":"string"}},"updated_at":{"type":["string","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Search the Academy training catalogue","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"query_knowledge_graph","title":"Traverse the learning knowledge graph","description":"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.","inputSchema":{"type":"object","properties":{"node_id":{"type":"string","description":"Fully-qualified node id, `<type>:<id>` — `module:M178`, `concept:C001`, `study:ai-impact-2026-EN`, `vendor:alteryx`. With it, rows are that node's EDGES (one row per neighbour). Without it, rows are NODES."},"node_type":{"type":"string","description":"Restrict to one carried node type: concept · module · study · vendor. Read `_meta.available_node_types`."},"edge_type":{"type":"string","description":"Restrict a walk to one relation. The served projection carries FIVE — teaches · taught_by · covers · related · mentions — and this list is a HINT, not the authority: read `_meta.available_edge_types`, computed on every call. A four-name list stood here while the projection served five, so `mentions` was reachable and undocumented."},"direction":{"type":"string","enum":["from","to","both"],"description":"Which side of the edge `node_id` must sit on. Default `both`. Ignored without `node_id`, and the response says so rather than pretending it applied."},"query":{"type":"string","description":"Case-insensitive substring of a node's label. Applies to the NODE listing, not to a walk. Matched against the label SERVED, so it follows `lang`."},"lang":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO-639-1 language for the LABELS — en, fr or de. Defaults to en. The fallback is declared and never silent: the language asked for, then English, then French, and `_meta.label_language_coverage` says on how many nodes each language is actually filled. Concept and module titles carry French; German arrives as the corpus is translated, and an untranslated node falls back rather than being hidden."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10,"description":"Max rows (hard cap 50)."},"cursor":{"type":"string","maxLength":512,"description":"Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}},"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"node_id":{"type":["string","null"]},"node_type":{"type":["string","null"]},"label":{"type":["string","null"],"description":"In the language asked for when the node carries it, else the declared fallback — see `label_lang`."},"label_lang":{"type":["string","null"],"description":"The language the served `label` is actually written in. It differs from the requested `lang` exactly when that translation does not exist."},"edge_type":{"type":["string","null"],"description":"Present only on a walk (when `node_id` was given)."},"direction":{"type":["string","null"],"description":"`out` = node_id → neighbour, `in` = neighbour → node_id, `both` = the relation is stored in both directions (served once — see `_meta.symmetric_edges_folded`). Walk rows only."},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Traverse the learning knowledge graph","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"get_concept_card","title":"Full concept card (Consultant tier)","description":"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 €29.90 Consultant Pass sells. On THIS endpoint the machine-access subscription is the MCP Pass (€39.90/month, analyticslegends.ai/pricing/), which opens the ENTIRE paid tranche from one key; the €29.90 Consultant Pass is its web-subscriber equivalent and opens the same tier floor here. Requires a subscriber API key (Authorization: Bearer alk_…), Consultant tier or above; without one this tool refuses and get_concept keeps serving the public metadata. Find slugs with search_concepts.","inputSchema":{"type":"object","properties":{"slug":{"type":"string","description":"Concept slug, verbatim from search_concepts.rows[].slug."}},"required":["slug"],"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"slug":{"type":["string","null"]},"title_en":{"type":["string","null"]},"body_en":{"type":["string","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Full concept card (Consultant tier)","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"_meta":{"ai.analyticslegends/requiresTier":"consultant"}},{"name":"get_study","title":"Read a study (Consultant tier)","description":"Read one Analytics Legends study BODY — the paid text behind list_studies' metadata. Requires a subscriber API key, Consultant tier or above. 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.","inputSchema":{"type":"object","properties":{"slug":{"type":"string","description":"Study slug, verbatim from list_studies.rows[].slug."},"lang":{"type":"string","pattern":"^[A-Za-z]{2}$","default":"en","description":"ISO-639-1 language of the edition, e.g. en or fr. Defaults to en."},"section":{"type":"string","maxLength":200,"description":"A section heading from a previous call's `sections` list. Omit to get the list."}},"required":["slug"],"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"slug":{"type":["string","null"]},"title":{"type":["string","null"]},"section_heading":{"type":["string","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Read a study (Consultant tier)","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"_meta":{"ai.analyticslegends/requiresTier":"consultant"}},{"name":"get_academy_module","title":"Read an Academy module (Consultant tier)","description":"Read one Academy training module in full — body, learning objectives and summary, EN, FR and DE — the written course corpus the €29.90 Consultant Pass sells. On THIS endpoint the machine-access subscription is the MCP Pass (€39.90/month, analyticslegends.ai/pricing/), which opens the ENTIRE paid tranche from one key; the €29.90 Consultant Pass is its web-subscriber equivalent and opens the same tier floor here. Requires a subscriber API key (Authorization: Bearer alk_…), Consultant tier or above; 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. Unlike `get_study`, the whole module is served in one call: the longest body measured is 17 865 characters, two orders of magnitude under the response ceiling, so sectioning it would cost the caller context without protecting anything.","inputSchema":{"type":"object","properties":{"id":{"type":"string","description":"Module id (`M001`) or slug (`datasphere-foundations`), verbatim from find_academy_modules.rows[].id / .slug."}},"required":["id"],"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":["string","null"]},"slug":{"type":["string","null"]},"title_en":{"type":["string","null"]},"body_en":{"type":["string","null"]},"objectives_en":{"type":["array","null"],"items":{"type":"string"},"description":"Learning objectives, one per element — a text[] column, not a paragraph."},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Read an Academy module (Consultant tier)","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"_meta":{"ai.analyticslegends/requiresTier":"consultant"}},{"name":"find_sap_clients","title":"Search the SAP end-customer corpus (Legend tier)","description":"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 a subscriber API key, Legend tier or above. Verification status is SERVED, never silently filtered: `sap_client_verification_status` and `status` are columns on every row ('verified' on ~550 of ~21k rows), 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.","inputSchema":{"type":"object","properties":{"query":{"type":"string","maxLength":200,"description":"Free-text filter, case-insensitive. EVERY word must appear in the record (substring per word, any order), so a natural-language phrase narrows the answer instead of having to match verbatim."},"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO-3166-1 alpha-2 country code, e.g. DE, FR, CH."},"industry":{"type":"string","maxLength":200,"description":"Industry or sector filter, matched case-insensitively."},"product":{"type":"string","enum":["datasphere","bdc","sac","bw","bw4hana","s4hana","ecc","hana","joule","businessobjects","bpc","successfactors","ariba","concur"],"description":"Keep only end-customers where this SAP product was DETECTED in use. Absence from the result means undetected, not unused."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10,"description":"Max rows (hard cap 50)."},"cursor":{"type":"string","maxLength":512,"description":"Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}},"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":["string","null"]},"name":{"type":["string","null"]},"country_code":{"type":["string","null"]},"industry":{"type":["string","null"]},"sap_client_verification_status":{"type":["string","null"]},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Search the SAP end-customer corpus (Legend tier)","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"_meta":{"ai.analyticslegends/requiresTier":"legend"}},{"name":"get_sap_client_profile","title":"One SAP end-customer profile (Legend tier)","description":"The full profile of one SAP end-customer — SAP footprint (products in use, modules known), analytics solutions, identity and evidence fields. Requires a subscriber API key, Legend tier or above. `id` comes verbatim from find_sap_clients.rows[].id.","inputSchema":{"type":"object","properties":{"id":{"type":"string","maxLength":160,"description":"Profile id, verbatim from find_sap_clients.rows[].id."}},"required":["id"],"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":["string","null"]},"name":{"type":["string","null"]},"sap_products_used":{},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"One SAP end-customer profile (Legend tier)","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"_meta":{"ai.analyticslegends/requiresTier":"legend"}},{"name":"get_firm_intel","title":"Firm intelligence profile (Legend tier)","description":"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 the entire corpus as of 2026-08-10, 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 a subscriber API key, Legend tier or above. 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.","inputSchema":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"description":"Firm name, matched case-insensitively. Omit to browse the corpus by data completeness."},"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO-3166-1 alpha-2 country code, e.g. DE, FR, CH."},"delivers":{"type":"string","enum":["datasphere","bdc","sac","bw","bw4hana","s4hana","ecc","hana","joule","businessobjects","bpc","successfactors","ariba","concur"],"description":"Keep only firms whose profile DECLARES delivery of this product (the `delivers_*` flags every row already carries). An undeclared flag drops the row: absence from the result means the profile does not declare it, not that the firm cannot deliver it."},"mode":{"type":"string","enum":["freelance","permanent","subcontract"],"description":"Keep only firms whose profile declares this engagement mode (mode_freelance / mode_permanent / mode_subcontract). Same reading as `delivers`: declared-only."},"limit":{"type":"integer","minimum":1,"maximum":10,"default":3,"description":"Max rows (hard cap 10 — these rows are wide)."},"cursor":{"type":"string","maxLength":512,"description":"Opaque token from a previous response's `_meta.next_cursor`. Pass it back with the SAME filter arguments; `null` means the last page. Changing a filter refuses the cursor."}},"additionalProperties":false},"outputSchema":{"type":"object","properties":{"tool":{"type":"string"},"result_count":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"firm_id_unique":{},"name":{"type":["string","null"]},"sap_partner_level":{"type":["string","null"]},"typical_day_rate_eur":{},"citation_url":{"type":"string"},"citation_scope":{"type":"string","enum":["record","section_hub"]}}}},"_meta":{"type":"object"},"_attribution":{"type":"string"}},"required":["tool","result_count","rows","_attribution"]},"annotations":{"title":"Firm intelligence profile (Legend tier)","readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"_meta":{"ai.analyticslegends/requiresTier":"legend"}}]}},"http_status":200,"headers":{"content-type":"application/json","mcp-protocol-version":"2025-03-26","strict-transport-security":"max-age=31536000; includeSubDomains; preload"}}},"prompts_list":{"status":"ok","latency_ms":170.36,"details":{"url":"https://analyticslegends.ai/mcp","payload":{"jsonrpc":"2.0","id":3,"result":{"prompts":[{"name":"brief_sap_analytics_market","title":"Brief me on the SAP analytics market in a country","description":"Assemble a sourced, cited briefing on the SAP analytics services market for one country: who the providers are, what is on the radar, what the day rates look like and what has just happened.","arguments":[{"name":"country","description":"ISO-3166 alpha-2 country code, e.g. DE.","required":true},{"name":"focus","description":"Optional product focus, e.g. Datasphere, BDC, SAC.","required":false}]},{"name":"explain_sap_analytics_term","title":"Explain an SAP analytics term with a citation","description":"Explain one SAP analytics term from the Analytics Legends encyclopaedia and cite the canonical URL.","arguments":[{"name":"term","description":"The term to explain.","required":true}]},{"name":"shortlist_firms_for_requirement","title":"Shortlist SAP analytics firms for a requirement","description":"Build a sourced shortlist of service firms for one requirement — country plus SAP module — walking the population before naming anyone, and saying what each number's population is.","arguments":[{"name":"country","description":"ISO-3166 alpha-2 country code, e.g. DE.","required":true},{"name":"module","description":"SAP module/product code, e.g. DATASPHERE, BDC, SAC.","required":true}]},{"name":"price_my_mission","title":"Price an SAP analytics mission honestly","description":"Assemble a day-rate answer for one (country × specialisation × seniority) cell from the platform's TWO rate instruments, kept apart and both cited.","arguments":[{"name":"country","description":"ISO-3166 alpha-2 country code, e.g. DE.","required":true},{"name":"specialisation","description":"Optional product focus, e.g. Datasphere, BDC, SAC.","required":false},{"name":"seniority","description":"Optional seniority, e.g. senior, principal.","required":false}]}]}},"http_status":200,"headers":{"content-type":"application/json","mcp-protocol-version":"2025-03-26","strict-transport-security":"max-age=31536000; includeSubDomains; preload"}}},"prompt_get":{"status":"error","latency_ms":166.21,"details":{"url":"https://analyticslegends.ai/mcp","payload":{"jsonrpc":"2.0","id":4,"error":{"code":-32602,"message":"`country` is a required argument of the 'brief_sap_analytics_market' prompt and was not supplied. It is refused rather than defaulted: a default would have produced a briefing about something you did not ask for.","data":{"prompt":"brief_sap_analytics_market","argument":"country","expected":"an ISO-3166-1 alpha-2 code such as DE, FR or CH"}}},"http_status":200,"headers":{"content-type":"application/json","mcp-protocol-version":"2025-03-26","strict-transport-security":"max-age=31536000; includeSubDomains; preload"},"prompt_name":"brief_sap_analytics_market","prompt_arguments":[{"name":"country","description":"ISO-3166 alpha-2 country code, e.g. DE.","required":true},{"name":"focus","description":"Optional product focus, e.g. Datasphere, BDC, SAC.","required":false}]}},"resources_list":{"status":"ok","latency_ms":185.97,"details":{"url":"https://analyticslegends.ai/mcp","payload":{"jsonrpc":"2.0","id":5,"result":{"resources":[{"uri":"analytics-legends://tranche","name":"Public tranche contract","title":"What this endpoint serves, and what it deliberately does not","description":"The explicit list of datasets this hosted MCP endpoint serves, the datasets it excludes and why, and the live row count of each. Read this before trusting or citing any tool result.","mimeType":"application/json"},{"uri":"analytics-legends://agents-policy","name":"AI access policy","title":"Retrieval-with-attribution carve-out (.well-known/agent.json)","description":"The machine-readable policy governing AI access to Analytics Legends: retrieval with attribution is permitted, training-data use is prohibited.","mimeType":"application/json"},{"uri":"analytics-legends://about","name":"Platform manifest","title":"Platform manifest (api/about.json)","description":"Auto-derived platform manifest: counts, tiers, routes, tech stack.","mimeType":"application/json"}]}},"http_status":200,"headers":{"content-type":"application/json","mcp-protocol-version":"2025-03-26","strict-transport-security":"max-age=31536000; includeSubDomains; preload"}}},"resource_read":{"status":"ok","latency_ms":6273.83,"details":{"url":"https://analyticslegends.ai/mcp","payload":{"jsonrpc":"2.0","id":6,"result":{"contents":[{"uri":"analytics-legends://tranche","mimeType":"application/json","text":"{\n  \"endpoint\": \"https://analyticslegends.ai/mcp\",\n  \"auth\": \"none for the public tranche. Subscribers may pass `Authorization: Bearer alk_…` (a personal API key from their analyticslegends.ai account) to open the authenticated tranche below at their subscription's floor.\",\n  \"authenticated\": {\n    \"how\": \"Authorization: Bearer alk_<48 hex> — minted by the account owner (public.mcp_create_key), revocable, SHA-256-stored.\",\n    \"consultant_floor\": {\n      \"tools\": [\n        \"get_concept_card\",\n        \"get_study\",\n        \"get_academy_module\"\n      ],\n      \"corpus\": \"full concept cards, study bodies, Academy module bodies\"\n    },\n    \"legend_floor\": {\n      \"tools\": [\n        \"find_sap_clients\",\n        \"get_sap_client_profile\",\n        \"get_firm_intel\"\n      ],\n      \"corpus\": \"SAP end-customer corpus, firm intelligence profiles (PII deny-listed)\"\n    },\n    \"quota\": \"daily, per subscription tier — see `limits` below for the numbers, and `_meta.quota` on every answer served to a key for where you stand.\"\n  },\n  \"limits\": {\n    \"rate\": {\n      \"scope\": \"per client IP, enforced at the edge before this function runs\",\n      \"burst\": \"20 requests / 10 seconds\",\n      \"sustained\": \"60 requests / minute\",\n      \"endpoint_wide\": \"300 requests / minute\",\n      \"on_refusal\": \"HTTP 429 with a `Retry-After` header carrying the seconds to wait.\",\n      \"source\": \"infra/cloudflare/wrangler.toml\"\n    },\n    \"free_lane\": {\n      \"scope\": \"ENDPOINT-WIDE per day — NOT a per-caller cap\",\n      \"metered_per_caller\": false,\n      \"daily_budget\": 60000,\n      \"behaviour\": \"Unauthenticated calls are not counted against any individual. The endpoint holds a shared daily budget for them; once a day's budget is spent, anonymous `tools/call` is shed with an explicit refusal until midnight UTC. Discovery (`initialize`, `tools/list`, `resources/read`) is never shed, and a subscriber key is never shed.\",\n      \"why_not_per_ip\": \"Assistant connectors egress from shared IPs, so a per-IP DAILY cap would lock out every user of a provider for a day because of one. The per-minute rate limit above is per IP precisely because it clears itself in sixty seconds.\"\n    },\n    \"per_key\": {\n      \"scope\": \"per ACCOUNT, per day, resetting at midnight UTC — every key of the same account shares one counter, so minting a second key does not reset it\",\n      \"unit\": \"calls to `tools/call`; `initialize`, `tools/list` and `ping` are never counted\",\n      \"covers\": \"public tools too — presenting a key meters the call, so a key whose day is spent is refused on the public tools as well. Calling with no key serves the public tranche and counts nothing.\",\n      \"daily_limit\": {\n        \"free\": 1000,\n        \"consultant\": 2000,\n        \"legend\": 10000,\n        \"mcp\": 10000,\n        \"firm\": 50000\n      },\n      \"read_your_own\": \"`_meta.quota` on every answer served to a key.\",\n      \"source\": \"billing.tier_feature_quotas (feature_key = 'api_queries_per_day')\"\n    },\n    \"paid_taste\": {\n      \"scope\": \"per ACCOUNT, per day, resetting at midnight UTC — every key of the same account shares one sample, so minting a second key does not grant a second taste\",\n      \"unit\": \"calls to tools ABOVE this key's tier floor — the paid tranche. Calls at or below the floor are not counted here at all.\",\n      \"daily_limit\": {\n        \"firm\": 0,\n        \"legend\": 0,\n        \"mcp\": 0,\n        \"consultant\": 25,\n        \"free\": 25\n      },\n      \"anonymous\": 0,\n      \"behaviour\": \"A free account may call the paid tools this many times a day; past it they refuse and name the MCP Pass. A tier that is already entitled to the whole paid tranche shows 0 because there is nothing to taste — it is not a restriction on them.\",\n      \"not_a_traversal_budget\": \"This is a SAMPLE, not a budget to walk the paid corpus with: paginating it costs far more calls than the taste holds, deliberately. A refusal here is not broken pagination.\",\n      \"upgrade\": \"https://analyticslegends.ai/pricing/\",\n      \"read_your_own\": \"`_meta.quota.paid_taste` on every paid answer served under the taste.\",\n      \"source\": \"billing.tier_feature_quotas (feature_key = 'mcp_paid_taste_per_day')\"\n    }\n  },\n  \"served\": {\n    \"firms\": {\n      \"source\": \"database.organizations (+ database.organization_sap_modules for the `module` facet)\",\n      \"rows\": 7875,\n      \"tools\": [\n        \"search_firms\",\n        \"count_firms_by\",\n        \"get_firm\",\n        \"list_firm_kinds\",\n        \"list_freelance_platforms\"\n      ]\n    },\n    \"opportunities\": {\n      \"source\": \"public.public_opportunities + https://analyticslegends.ai/api/contracts-lean.json (all active rows; the application link alone is tier-gated)\",\n      \"rows\": 3292,\n      \"rows_note\": \"`rows` counts the promoted leg only; the site-radar leg is read at query time.\",\n      \"tools\": [\n        \"find_opportunities\"\n      ]\n    },\n    \"news\": {\n      \"source\": \"content.news_items\",\n      \"rows\": 7120,\n      \"tools\": [\n        \"search_news\"\n      ]\n    },\n    \"concepts\": {\n      \"source\": \"content.concepts\",\n      \"rows\": 378,\n      \"tools\": [\n        \"search_concepts\",\n        \"get_concept\"\n      ]\n    },\n    \"studies\": {\n      \"source\": \"content.studies (metadata only)\",\n      \"rows\": 66,\n      \"tools\": [\n        \"list_studies\"\n      ]\n    },\n    \"modules\": {\n      \"source\": \"lookup.sap_modules (PRODUCT taxonomy)\",\n      \"rows\": 40,\n      \"tools\": [\n        \"list_sap_modules\"\n      ]\n    },\n    \"academy\": {\n      \"source\": \"content.academy_modules (catalogue only; bodies are Consultant-tier, see get_academy_module)\",\n      \"rows\": 385,\n      \"tools\": [\n        \"find_academy_modules\"\n      ]\n    },\n    \"day_rates\": {\n      \"source\": \"https://analyticslegends.ai/api/market-rates.json\",\n      \"rows\": null,\n      \"tools\": [\n        \"get_day_rate_benchmark\"\n      ]\n    },\n    \"learning_graph\": {\n      \"source\": \"https://analyticslegends.ai/api/learning-graph.json (projection of the knowledge graph's extended-star files)\",\n      \"rows\": null,\n      \"rows_note\": \"the graph is fetched from the site at query time; query_knowledge_graph reports its population per call in `_meta.tranche_total_row_count`, so no count is frozen here. 🔴 THAT FIELD COUNTS ROWS, AND THIS TOOL SERVES TWO KINDS: with `node_id` the rows are EDGES and the figure is the edge population; without it the rows are NODES and the figure is the node population. The two differ by more than an order of magnitude (measured 2026-08-27: 9 823 edges against 712 nodes), so reading one for the other misstates the graph's size in whichever direction you guessed. This line said \\\"node population\\\" flatly until then, which was true of exactly one of the two modes.\",\n      \"tools\": [\n        \"query_knowledge_graph\"\n      ]\n    }\n  },\n  \"coverage\": {\n    \"tools_dispatched\": 20,\n    \"tools_not_described_above\": []\n  },\n  \"excluded_from_public_tranche\": {\n    \"sap_end_customer_corpus\": \"paid Legend+ dataset (find_sap_clients / get_sap_client_profile with a Legend key)\",\n    \"firm_intelligence_profiles\": \"paid Legend+ dataset (get_firm_intel with a Legend key; person fields deny-listed)\",\n    \"study_bodies\": \"paid Consultant corpus (get_study with a Consultant key); metadata public via list_studies\",\n    \"concept_bodies\": \"paid Consultant corpus (get_concept_card with a Consultant key); metadata public via get_concept\"\n  },\n  \"excluded_at_every_tier\": {\n    \"professionals_and_people\": \"personal data — never served, with or without a key\",\n    \"firm_contact_and_leadership_fields\": \"PII deny-list (contact_email, contact_phone, founders, leadership, recruiters, postal addresses)\",\n    \"full_knowledge_graph_artefact\": \"the full knowledge-graph build artefact (hundreds of MB, gitignored) has no server home. The learning-graph PROJECTION cut from it IS served, publicly, by query_knowledge_graph — see `served.learning_graph`.\",\n    \"day_rate_quartiles\": \"NOT a tier — every percentile the platform's public aggregate holds (the GB median, its p10/p90, its 25th/75th min-max) is served free by get_day_rate_benchmark, and the community-contributed rate corpus has no published aggregate for anyone to gate. No row count is restated here: a count written into this document froze once already — it said the contribution tables were \\\"all empty (2026-08-09)\\\" for days after the first real contribution landed. get_day_rate_benchmark's own response says what exists at query time.\",\n    \"opportunity_consultant_matches\": \"Firm-tier deliverable computed by get-firm-intel from artefacts not present here\"\n  },\n  \"_attribution\": \"Source: Analytics Legends (https://analyticslegends.ai) — retrieval-with-attribution permitted per https://analyticslegends.ai/.well-known/agent.json; use as AI training data is prohibited. Cite the canonical URL on each item.\"\n}"}]}},"http_status":200,"headers":{"content-type":"application/json","mcp-protocol-version":"2025-03-26","strict-transport-security":"max-age=31536000; includeSubDomains; preload"},"resource_uri":"analytics-legends://tranche"}},"determinism_probe":{"status":"ok","latency_ms":183.27,"details":{"attempts":2,"successful":2,"matches":2,"stable_ratio":1.0,"baseline_signature":"233612d42811377e9866c98101ded1814ec725c1722aba645e7afdbbd728e17b","errors":[]}},"instruction_tool_reference_probe":{"status":"warning","latency_ms":null,"details":{"referenced_tools":["allowance","answering","anything","it","of","repeating"],"missing_tools":["allowance","answering","anything","it","of","repeating"],"observed_tool_count":20}},"session_resume_probe":{"status":"warning","latency_ms":null,"details":{"reason":"no_session_id","transport":"streamable-http","resume_expected":true,"protocol_version":"2025-03-26"}},"step_up_auth_probe":{"status":"missing","latency_ms":null,"details":{"oauth_present":false,"auth_required_checks":[],"supported_scopes":[],"scope_specificity_ratio":0.0,"broad_scopes":[],"challenge_headers":[],"step_up_signals":[],"minimal_scope_documented":false}},"transport_compliance_probe":{"status":"warning","latency_ms":169.74,"details":{"transport":"streamable-http","session_id_present":false,"protocol_header_present":true,"last_event_id_visible":false,"requested_protocol_version":"2025-03-26","bad_protocol_status_code":400,"bad_protocol_payload":{"jsonrpc":"2.0","id":410,"error":{"code":-32022,"message":"Unsupported protocol version","data":{"supported":["2026-07-28","2025-11-25","2025-06-18","2025-03-26"],"requested":"1999-99-99"}}},"bad_protocol_headers":{"content-type":"application/json","strict-transport-security":"max-age=31536000; includeSubDomains; preload"},"bad_protocol_error":null,"delete_status_code":null,"delete_error":null,"expired_session_status_code":null,"expired_session_error":null,"issues":["missing_session_id"]}},"utility_coverage_probe":{"status":"warning","latency_ms":156.96,"details":{"completions":{"advertised":true,"sample_target":{"type":"prompt","name":"brief_sap_analytics_market","argument_name":"country"},"live_probe":"not_executed"},"pagination":{"supported":false,"next_cursor_methods":[],"metadata_signal":false},"tasks":{"advertised":false,"probe_status":"missing","http_status":404},"initialize_capability_keys":["completions","prompts","resources","tools"]}},"advanced_capabilities_probe":{"status":"ok","latency_ms":null,"details":{"capabilities":{"prompts":true,"resources":true,"completions":true,"roots":false,"sampling":false,"elicitation":false,"structured_outputs":true,"resource_links":true},"enabled_count":5,"enabled":["completions","prompts","resource_links","resources","structured_outputs"],"initialize_capability_keys":["completions","prompts","resources","tools"]}},"tool_snapshot_probe":{"status":"ok","latency_ms":null,"details":{"current_tool_count":20,"previous_tool_count":20,"similarity":1.0,"added":[],"removed":[],"changed_outputs":[]}},"connector_replay_probe":{"status":"ok","latency_ms":null,"details":{"backward_compatible":true,"would_break_after_refresh":false,"added_tools":[],"removed_tools":[],"required_arg_breaks":[],"output_breaks":[],"additive_output_changes":[]}},"request_association_probe":{"status":"missing","latency_ms":null,"details":{"reason":"no_request_association_capabilities_advertised"}},"interactive_flow_probe":{"status":"missing","latency_ms":null,"details":{"risk_hits":[],"safe_hits":[],"oauth_supported":false,"prompt_available":false}},"action_safety_probe":{"status":"ok","latency_ms":null,"details":{"summary":{"tool_count":20,"high_risk_tools":0,"destructive_tools":0,"exec_tools":0,"egress_tools":1,"secret_tools":0,"bulk_access_tools":11,"declared_non_read_only_tools":0,"annotation_conflict_tools":0,"risk_distribution":{"low":10,"medium":10,"high":0,"critical":0},"capability_distribution":{"read":20,"export":11,"financial":1,"network":1},"has_mutating_capability":true,"has_non_read_capability":true},"auth_present":false,"safeguard_count":2,"confirmation_signals":["find_academy_modules"],"reason":null}},"official_registry_probe":{"status":"ok","latency_ms":null,"details":{"registry_source":"official_registry","registry_identifier":"ai.analyticslegends/sap-analytics","direct_match":true,"official_peer_count":1}},"provenance_divergence_probe":{"status":"not_assessed","latency_ms":null,"details":{"direct_official_match":true,"registry_title":null,"server_card_title":null,"registry_version":null,"server_card_version":null,"registry_homepage":null,"server_card_homepage":null,"registry_repository":null,"server_card_repository":null,"drift_fields":[],"metadata_document_count":2,"compared_fields":["title","version","homepage","repository"],"readable_sources":["registry"],"comparable_field_count":0}},"schema_divergence_probe":{"status":"missing","latency_ms":null,"details":{"reason":"no_server_card_tools","compared_tool_count":0,"compared_dimensions":["server_name","server_version","declared_vs_observed_auth","tool_membership","parameter_names","required_parameters","parameter_types","output_schema_presence"],"server_name_mismatch":false,"card_server_name":null,"live_server_name":"analytics-legends","server_version_mismatch":false,"card_server_version":null,"live_server_version":"1.0.6","auth_scheme_mismatch":false}},"connector_publishability_probe":{"status":"warning","latency_ms":null,"details":{"transport":"streamable-http","tool_count":20,"high_risk_tools":0,"blockers":["protocol_version","session_resume","step_up_auth","transport_compliance","request_association","server_card"],"criteria":{"remote_transport":true,"initialize":true,"tools_list":true,"protocol_version":false,"session_resume":false,"step_up_auth":false,"transport_compliance":false,"connector_replay":true,"request_association":false,"action_safety":true,"server_card":false,"tool_surface":true,"auth_flow":true}}}}},"active_alerts":[{"code":"instruction_tool_reference_mismatch","severity":"low","title":"Server instructions name unavailable tools","message":"Initialize instructions reference tools not present in tools/list: allowance, answering, anything, it, of, repeating","addressee":"publisher"}],"maintainer_analytics":{},"public_server_reputation":{},"maintainer_response_quality":{},"maintainer_annotations":[],"maintainer_rebuttals":[],"security_posture_summary":{},"tool_security_inventory":[],"transport_compliance":{},"utility_coverage":{},"write_action_governance":{},"provenance_divergence":{},"alias_consolidation":{},"alert_routing":{},"authenticated_validation":{},"hosted_runtime":{},"action_controls_diff":null,"benchmark_tasks":[],"latest_capability_counts":{},"point_loss_breakdown":[],"verdict_traces":{},"current_snapshot":{"schema_version":"verify.trust_snapshot.v1","snapshot_id":"trustsnap_8372c109b96e996d","generated_at":"2026-09-29T00:46:09.676300+00:00","trust_evaluated_at":"2026-09-29T00:46:09.676300+00:00","evidence_revision":"52562cd6fc9d68f3607dd67f","source":"current_snapshot","server":"ai.analyticslegends/sap-analytics","last_validated_at":"2026-09-28T21:46:19.872711+00:00","validation_age_hours":3.0,"freshness":{"schema_version":"verify.freshness_profile.v1","last_validated_at":"2026-09-28T21:46:19.872711+00:00","age_hours":3.0,"bucket":"verified_last_24h","label":"Verified in last 24h","badges":["verified_last_24h"],"freshness_sla_hours":720.0,"freshness_sla_status":"met","stale_score_suppressed":false,"display_score":67.19,"raw_score":67.19,"confidence_score":100.0,"confidence_weighted_score":67.2,"tier_status":[{"tier":"community","label":"Community","freshness_sla_hours":720,"met":true,"priority_revalidation":false},{"tier":"pro","label":"Pro","freshness_sla_hours":168,"met":true,"priority_revalidation":true},{"tier":"enterprise","label":"Enterprise","freshness_sla_hours":24,"met":true,"priority_revalidation":true}]},"current_status":"healthy","current_score":67.19,"display_score":67.19,"stale_score_suppressed":false,"production_trust_decision":{"schema_version":"verify.executive_verdict.v1","decision":"Allow with approval","why":"no blocking gaps found in current evidence","next_action":"export policy, require approval for writes, add authenticated validation","reason_count":1},"production_readiness_class":{"code":"safe_for_evaluation","label":"Safe for evaluation","reason":"The server is suitable for evaluation, but remaining gaps should be resolved before broad production use."},"evidence_confidence":{"score":100.0,"label":"high","validation_age_hours":3.0,"live_check_count":18,"basis":{"evidence_bearing_validations":20,"affirmative_live_check_count":18,"validation_age_hours":3.0,"freshness_threshold_hours":24}},"active_alerts":[{"code":"instruction_tool_reference_mismatch","severity":"low","title":"Server instructions name unavailable tools"}],"active_alert_summary":{"critical":0,"high":0,"medium":0,"low":1,"high_or_critical":0,"total":1},"materialization":{"state":"partial","trust_core_complete":true,"fields_unavailable":["tool_security_inventory","security_posture_summary","write_action_governance","capability_taxonomy","remediations"],"materialized_at":"2026-09-29T00:46:09.676300+00:00"}},"trust_snapshot":{"schema_version":"verify.trust_snapshot.v1","snapshot_id":"trustsnap_8372c109b96e996d","generated_at":"2026-09-29T00:46:09.676300+00:00","trust_evaluated_at":"2026-09-29T00:46:09.676300+00:00","evidence_revision":"52562cd6fc9d68f3607dd67f","source":"current_snapshot","server":"ai.analyticslegends/sap-analytics","last_validated_at":"2026-09-28T21:46:19.872711+00:00","validation_age_hours":3.0,"freshness":{"schema_version":"verify.freshness_profile.v1","last_validated_at":"2026-09-28T21:46:19.872711+00:00","age_hours":3.0,"bucket":"verified_last_24h","label":"Verified in last 24h","badges":["verified_last_24h"],"freshness_sla_hours":720.0,"freshness_sla_status":"met","stale_score_suppressed":false,"display_score":67.19,"raw_score":67.19,"confidence_score":100.0,"confidence_weighted_score":67.2,"tier_status":[{"tier":"community","label":"Community","freshness_sla_hours":720,"met":true,"priority_revalidation":false},{"tier":"pro","label":"Pro","freshness_sla_hours":168,"met":true,"priority_revalidation":true},{"tier":"enterprise","label":"Enterprise","freshness_sla_hours":24,"met":true,"priority_revalidation":true}]},"current_status":"healthy","current_score":67.19,"display_score":67.19,"stale_score_suppressed":false,"production_trust_decision":{"schema_version":"verify.executive_verdict.v1","decision":"Allow with approval","why":"no blocking gaps found in current evidence","next_action":"export policy, require approval for writes, add authenticated validation","reason_count":1},"production_readiness_class":{"code":"safe_for_evaluation","label":"Safe for evaluation","reason":"The server is suitable for evaluation, but remaining gaps should be resolved before broad production use."},"evidence_confidence":{"score":100.0,"label":"high","validation_age_hours":3.0,"live_check_count":18,"basis":{"evidence_bearing_validations":20,"affirmative_live_check_count":18,"validation_age_hours":3.0,"freshness_threshold_hours":24}},"active_alerts":[{"code":"instruction_tool_reference_mismatch","severity":"low","title":"Server instructions name unavailable tools"}],"active_alert_summary":{"critical":0,"high":0,"medium":0,"low":1,"high_or_critical":0,"total":1},"materialization":{"state":"partial","trust_core_complete":true,"fields_unavailable":["tool_security_inventory","security_posture_summary","write_action_governance","capability_taxonomy","remediations"],"materialized_at":"2026-09-29T00:46:09.676300+00:00"}},"agent_commerce":{},"latest_claim":null,"maintainer_profile_slug":null,"watch_summary":{},"partial":true,"fields_unavailable":["tool_security_inventory","security_posture_summary","write_action_governance","capability_taxonomy","remediations"],"trust_evaluated_at":"2026-09-29T00:46:09.676300+00:00","evidence_revision":"52562cd6fc9d68f3607dd67f","active_alert_summary":{"critical":0,"high":0,"medium":0,"low":1,"high_or_critical":0,"total":1},"materialization":{"state":"partial","trust_core_complete":true,"fields_unavailable":["tool_security_inventory","security_posture_summary","write_action_governance","capability_taxonomy","remediations"],"materialized_at":"2026-09-29T00:46:09.676300+00:00"},"owner_opted_out":false,"observed_attention":{"schema":"verify.observed_attention.v1","window_days":30,"level":"none","label":"No observed attention","summary":"No recent machine-readable trust or discovery activity observed for this server.","segments":{"useful_ai_user":{"level":"none","observed":false,"description":"AI-assisted user sessions such as ChatGPT/User or Claude/User."},"machine_trust_evaluator":{"level":"none","observed":false,"description":"Synthetic sessions inspecting multiple trust surfaces such as report, policy, ledger, badge, trust-summary, or compare."},"possible_agent_or_script":{"level":"none","observed":false,"description":"Structured direct sessions with rapid profile, compare, report, policy, badge, or trust-surface fan-out."},"isolated_machine_surface":{"level":"none","observed":false,"description":"Aged-out direct synthetic singleton sessions that touched a machine-readable trust surface without becoming a broader evaluator."},"ai_crawler":{"level":"none","observed":false,"description":"Known AI crawler activity such as ClaudeBot, GPTBot, or similar crawlers."},"search_crawler":{"level":"none","observed":false,"description":"Search and SEO crawler activity."},"browser_like_automation":{"level":"none","observed":false,"description":"Browser-like synthetic sessions with rapid structured endpoint activity."},"confirmed_human":{"level":"none","observed":false,"description":"Confirmed browser-session human activity."}},"surfaces_observed":{"server_profile":false,"compare":false,"compare_json":false,"compare_api":false,"report_json":false,"policy":false,"ledger":false,"badge_metadata":false,"badge_svg":false,"trust_summary":false,"mcp_tool":false},"claim_prompt":{"recommended":false,"reason":"No claim prompt is recommended from observed attention in the current window."},"notes":["Observed attention is based on segmented first-party telemetry.","Crawler and evaluator activity is not treated as confirmed human demand.","Public levels are bucketed to avoid exposing raw traffic counts."]},"owner_activation":{"claim_recommended":false,"reason":"no_observed_attention"},"snapshot_id":"trustsnap_8372c109b96e996d"}],"rows":[{"label":"Snapshot ID","values":["trustsnap_8372c109b96e996d"]},{"label":"Status","values":["healthy"]},{"label":"Score","values":[67.19]},{"label":"Production readiness","values":["Safe for evaluation"]},{"label":"Production trust decision","values":["Allow with approval"]},{"label":"Recommended policy","values":["Block"]},{"label":"Observed Attention","values":["No observed attention"]},{"label":"Evidence confidence","values":[100.0]},{"label":"Freshness","values":["n/a"]},{"label":"Latency","values":["n/a"]},{"label":"Spec recency","values":[2.0]},{"label":"Session resume","values":[3.0]},{"label":"Step-up auth","values":[0.0]},{"label":"Transport compliance","values":[2.0]},{"label":"Utility coverage","values":[1.0]},{"label":"Publishability","values":[2.0]},{"label":"Connector replay","values":[4.0]},{"label":"Request association","values":[0.0]},{"label":"Action safety","values":[3.0]},{"label":"Registry presence","values":[4.0]},{"label":"Provenance divergence","values":[null]},{"label":"Client compatibility: ChatGPT","values":["unknown"]},{"label":"Client compatibility: Claude","values":["unknown"]},{"label":"Write-action publishing","values":["unknown"]},{"label":"Snapshot churn risk","values":["unknown"]},{"label":"Transport","values":["streamable-http"]},{"label":"Auth","values":["Unauthenticated / none"]},{"label":"Tools","values":[20]},{"label":"Prompts","values":[0]},{"label":"Resources","values":[0]},{"label":"OAuth","values":[false]},{"label":"DCR","values":[false]},{"label":"Taxonomy","values":[""]},{"label":"Recommended for","values":["none"]},{"label":"Top alerts","values":["Server instructions name unavailable tools"]}],"partial":true,"fields_unavailable":["tool_security_inventory","security_posture_summary","write_action_governance","capability_taxonomy","remediations"],"cache_note":"Compact compare fallback response; deep compare evidence is deferred to protect web capacity.","trust_evaluated_at":"2026-09-29T00:46:09.676300+00:00","materialization":{"state":"partial","trust_core_complete":true,"fields_unavailable":["tool_security_inventory","security_posture_summary","write_action_governance","capability_taxonomy","remediations"],"materialized_at":"2026-09-29T00:46:09.754840+00:00"}}