classify_entity
Determine the first CSRD reporting fiscal year and applicable ESRS standards based on employee count, turnover, and entity type. Supports compliance readiness assessment.
Instructions
Classify when the entity must first report under CSRD. Returns first reporting FY, report year, and ESRS standards required.
Behavior: This tool is read-only and stateless — it produces analysis output without modifying any external systems, databases, or files. Safe to call repeatedly with identical inputs (idempotent). Free tier: 10/day rate limit. Pro tier: unlimited. No authentication required for basic usage.
When to use: Use this tool when you need to assess, audit, or verify compliance requirements. Ideal for gap analysis, readiness checks, and generating compliance documentation.
When NOT to use: Do not use as a substitute for qualified legal counsel. This tool provides technical compliance guidance, not legal advice.
Args: employees (int): The employees to analyze or process. turnover_million_eur (float): The turnover million eur to analyze or process. balance_sheet_million_eur (float): The balance sheet million eur to analyze or process. listed (bool): The listed to analyze or process. public_interest_entity (bool): The public interest entity to analyze or process. api_key (str): The api key to analyze or process.
Behavioral Transparency: - Side Effects: This tool is read-only and produces no side effects. It does not modify any external state, databases, or files. All output is computed in-memory and returned directly to the caller. - Authentication: No authentication required for basic usage. Pro/Enterprise tiers require a valid MEOK API key passed via the MEOK_API_KEY environment variable. - Rate Limits: Free tier: 10 calls/day. Pro tier: unlimited. Rate limit headers are included in responses (X-RateLimit-Remaining, X-RateLimit-Reset). - Error Handling: Returns structured error objects with 'error' key on failure. Never raises unhandled exceptions. Invalid inputs return descriptive validation errors. - Idempotency: Fully idempotent — calling with the same inputs always produces the same output. Safe to retry on timeout or transient failure. - Data Privacy: No input data is stored, logged, or transmitted to external services. All processing happens locally within the MCP server process.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| employees | Yes | ||
| turnover_million_eur | Yes | ||
| balance_sheet_million_eur | No | ||
| listed | No | ||
| public_interest_entity | No | ||
| api_key | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- server.py:104-181 (handler)The main handler function for the 'classify_entity' tool. Decorated with @mcp.tool(), it accepts parameters (employees, turnover_million_eur, balance_sheet_million_eur, listed, public_interest_entity, api_key) and implements CSRD classification logic determining the first reporting fiscal year based on entity size, employee count, and other criteria. Returns a JSON string with classification results.
@mcp.tool() def classify_entity(employees: int, turnover_million_eur: float, balance_sheet_million_eur: float = 0, listed: bool = False, public_interest_entity: bool = False, api_key: str = "") -> str: """Classify when the entity must first report under CSRD. Returns first reporting FY, report year, and ESRS standards required. Behavior: This tool is read-only and stateless — it produces analysis output without modifying any external systems, databases, or files. Safe to call repeatedly with identical inputs (idempotent). Free tier: 10/day rate limit. Pro tier: unlimited. No authentication required for basic usage. When to use: Use this tool when you need to assess, audit, or verify compliance requirements. Ideal for gap analysis, readiness checks, and generating compliance documentation. When NOT to use: Do not use as a substitute for qualified legal counsel. This tool provides technical compliance guidance, not legal advice. Args: employees (int): The employees to analyze or process. turnover_million_eur (float): The turnover million eur to analyze or process. balance_sheet_million_eur (float): The balance sheet million eur to analyze or process. listed (bool): The listed to analyze or process. public_interest_entity (bool): The public interest entity to analyze or process. api_key (str): The api key to analyze or process. Behavioral Transparency: - Side Effects: This tool is read-only and produces no side effects. It does not modify any external state, databases, or files. All output is computed in-memory and returned directly to the caller. - Authentication: No authentication required for basic usage. Pro/Enterprise tiers require a valid MEOK API key passed via the MEOK_API_KEY environment variable. - Rate Limits: Free tier: 10 calls/day. Pro tier: unlimited. Rate limit headers are included in responses (X-RateLimit-Remaining, X-RateLimit-Reset). - Error Handling: Returns structured error objects with 'error' key on failure. Never raises unhandled exceptions. Invalid inputs return descriptive validation errors. - Idempotency: Fully idempotent — calling with the same inputs always produces the same output. Safe to retry on timeout or transient failure. - Data Privacy: No input data is stored, logged, or transmitted to external services. All processing happens locally within the MCP server process. """ allowed, msg, tier = check_access(api_key) if not allowed: return json.dumps({"error": msg, "upgrade_url": STRIPE_199}) if err := _rl(tier): return json.dumps({"error": err, "upgrade_url": STRIPE_199}) # Large = meets 2 of: >250 FTE, €50M turnover, €25M balance sheet size_criteria = sum([employees > 250, turnover_million_eur > 50, balance_sheet_million_eur > 25]) is_large = size_criteria >= 2 first_fy = None first_report_year = None if is_large and employees > 500 and public_interest_entity: first_fy, first_report_year = "FY2024", "2025" elif is_large: first_fy, first_report_year = "FY2025", "2026" elif listed: first_fy, first_report_year = "FY2026", "2027 (2-year opt-out possible to 2028)" out_of_scope = first_fy is None return json.dumps({ "in_scope": not out_of_scope, "first_reporting_fy": first_fy, "first_report_due_by": first_report_year, "size_classification": "large" if is_large else "medium/small", "meets_large_criteria": f"{size_criteria} of 3 (>250 FTE, >€50M turnover, >€25M balance sheet)", "standards_required": list(ESRS.keys()), "always_mandatory": ["ESRS 1", "ESRS 2", "ESRS E1 (Climate)"], "double_materiality_required": True, "assurance_required": "Limited assurance initially → reasonable assurance by 2028 (mandatory EU audit standard)", "penalty_note": "Member-state specific. France ANC: up to €3.75M per breach. Germany: up to €2M. UK listed non-EU parents still in scope for EU subsidiaries.", "next_step": "Run double_materiality_assessment to identify which topical ESRS apply beyond E1.", }, indent=2) - server.py:104-104 (registration)The tool is registered via the @mcp.tool() decorator on the classify_entity function. The FastMCP instance (named 'csrd-compliance') is created at line 93, and the decorator registers this function as an MCP tool callable as 'classify_entity'.
@mcp.tool() - server.py:48-103 (helper)The check_access helper function (line 48) and _rl rate limiter (line 58) are used by classify_entity to enforce authentication and daily rate limits before executing classification logic.
def check_access(api_key: str = ""): return _shared_check_access(api_key) FREE_DAILY_LIMIT = 10 _usage: dict[str, list[datetime]] = defaultdict(list) STRIPE_199 = "https://buy.stripe.com/14A4gB3K4eUWgYR56o8k836" STRIPE_1499 = "https://buy.stripe.com/4gM9AV80kaEG0ZT42k8k837" def _rl(tier: str = "free") -> Optional[str]: if tier in ("pro", "professional", "enterprise"): return None now = datetime.now(timezone.utc) cutoff = now - timedelta(days=1) _usage["anonymous"] = [t for t in _usage["anonymous"] if t > cutoff] if len(_usage["anonymous"]) >= FREE_DAILY_LIMIT: return f"Free tier limit ({FREE_DAILY_LIMIT}/day). Unlock full 12-ESRS sweep + iXBRL taxonomy + signed attestations: Pro £199/mo at {STRIPE_199}" _usage["anonymous"].append(now) return None # ── ESRS Standards (12 topical + 2 cross-cutting) ─────────────── ESRS = { "ESRS 1": {"title": "General requirements", "type": "cross-cutting"}, "ESRS 2": {"title": "General disclosures", "type": "cross-cutting"}, "ESRS E1": {"title": "Climate change", "type": "environmental", "required": True}, "ESRS E2": {"title": "Pollution", "type": "environmental"}, "ESRS E3": {"title": "Water and marine resources", "type": "environmental"}, "ESRS E4": {"title": "Biodiversity and ecosystems", "type": "environmental"}, "ESRS E5": {"title": "Resource use and circular economy", "type": "environmental"}, "ESRS S1": {"title": "Own workforce", "type": "social"}, "ESRS S2": {"title": "Workers in the value chain", "type": "social"}, "ESRS S3": {"title": "Affected communities", "type": "social"}, "ESRS S4": {"title": "Consumers and end-users", "type": "social"}, "ESRS G1": {"title": "Business conduct", "type": "governance"}, } ENFORCEMENT_PHASES = [ {"fy": "2024", "who": "Large public-interest entities (>500 employees)", "report_due": "2025"}, {"fy": "2025", "who": "Other large companies (meeting 2 of: >250 employees, €50M turnover, €25M balance sheet)", "report_due": "2026"}, {"fy": "2026", "who": "Listed SMEs", "report_due": "2027 (with possible 2-year opt-out to 2028)"}, {"fy": "2028", "who": "Non-EU parents with EU turnover >€150M + EU subsidiary/branch", "report_due": "2029"}, ] mcp = FastMCP( "csrd-compliance", instructions=( "MEOK AI Labs CSRD Compliance MCP. Automates audits against Directive (EU) 2022/2464 " "and the 12 European Sustainability Reporting Standards (ESRS). Ask me to classify " "when you must report, run a double materiality assessment, check Scope 1/2/3 " "emissions readiness, or map existing data to ESRS datapoints." ), )