Skip to main content
Glama
ivossos

FCCS MCP Agentic Server

by ivossos

generate_report_script

Create Python script templates for custom FCCS reporting to query financial data by accounts, entities, periods, years, and scenarios, generating HTML, PDF, or CSV outputs.

Instructions

Generate a Python script template for custom FCCS reporting / Gerar script Python para relatorio customizado

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
script_nameYesName of the script file (without .py extension)
report_typeNoType of report (default: HTML)
descriptionNoDescription of what the report does
accountsNoList of account names to query
entitiesNoList of entity names to query
periodsNoList of periods to query (e.g., ['Jan', 'Feb', 'Dec'])
yearsNoList of years to query (e.g., ['FY24', 'FY25'])
scenariosNoList of scenarios to query (e.g., ['Actual', 'Budget'])

Implementation Reference

  • Async handler function registered for the tool, which delegates to the script generator function.
    async def generate_report_script(
        script_name: str,
        report_type: str = "HTML",
        description: str = "Custom FCCS report",
        accounts: Optional[list[str]] = None,
        entities: Optional[list[str]] = None,
        periods: Optional[list[str]] = None,
        years: Optional[list[str]] = None,
        scenarios: Optional[list[str]] = None
    ) -> dict[str, Any]:
        """Generate a Python script template for custom FCCS reporting / Gerar script Python para relatorio customizado.
    
        Args:
            script_name: Name of the script file (without .py extension).
            report_type: Type of report - HTML, PDF, or CSV (default: HTML).
            description: Description of what the report does.
            accounts: List of account names to query.
            entities: List of entity names to query.
            periods: List of periods to query (e.g., ['Jan', 'Feb', 'Dec']).
            years: List of years to query (e.g., ['FY24', 'FY25']).
            scenarios: List of scenarios to query (e.g., ['Actual', 'Budget']).
    
        Returns:
            dict: Path to generated script and summary.
        """
        return _generate_report_script(
            script_name=script_name,
            report_type=report_type,
            description=description,
            accounts=accounts,
            entities=entities,
            periods=periods,
            years=years,
            scenarios=scenarios
        )
  • Core implementation that generates a complete Python script template for running FCCS reports, including data collection, HTML generation, etc.
    def generate_report_script(
        script_name: str,
        report_type: str = "HTML",
        description: str = "Custom FCCS report",
        accounts: Optional[list[str]] = None,
        entities: Optional[list[str]] = None,
        periods: Optional[list[str]] = None,
        years: Optional[list[str]] = None,
        scenarios: Optional[list[str]] = None
    ) -> dict[str, Any]:
        """Generate a Python script template for custom FCCS reporting.
        
        Args:
            script_name: Name of the script file (without .py extension).
            report_type: Type of report - HTML, PDF, or CSV (default: HTML).
            description: Description of what the report does.
            accounts: List of account names to query.
            entities: List of entity names to query.
            periods: List of periods to query (e.g., ['Jan', 'Feb', 'Dec']).
            years: List of years to query (e.g., ['FY24', 'FY25']).
            scenarios: List of scenarios to query (e.g., ['Actual', 'Budget']).
        
        Returns:
            dict: Path to generated script and summary.
        """
        try:
            # Ensure script name ends with .py
            if not script_name.endswith('.py'):
                script_name = f"{script_name}.py"
            
            # Default values
            accounts = accounts or ["FCCS_Net Income"]
            entities = entities or ["FCCS_Total Geography"]
            periods = periods or ["Dec"]
            years = years or ["FY25"]
            scenarios = scenarios or ["Actual"]
            
            script_base_name = script_name.replace('.py', '')
            
            # Build script content using string concatenation to avoid f-string nesting issues
            script_lines = [
                f'"""Generate {description}."""',
                '',
                'import asyncio',
                'import sys',
                'from pathlib import Path',
                'from datetime import datetime',
                'from typing import Optional, Dict, List',
                '',
                '# Add parent directory to path',
                'sys.path.insert(0, str(Path(__file__).parent.parent))',
                '',
                'from fccs_agent.config import load_config',
                'from fccs_agent.agent import initialize_agent, close_agent',
                'from fccs_agent.tools.data import smart_retrieve',
                'from fccs_agent.utils.cache import load_members_from_cache',
                '',
                '',
                'async def get_account_value(',
                '    account: str,',
                '    entity: str,',
                '    period: str,',
                '    year: str,',
                '    scenario: str = "Actual"',
                ') -> Optional[float]:',
                '    """Get account value for specific dimensions."""',
                '    try:',
                '        result = await smart_retrieve(',
                '            account=account,',
                '            entity=entity,',
                '            period=period,',
                '            years=year,',
                '            scenario=scenario',
                '        )',
                '        if result.get("status") == "success":',
                '            data = result.get("data", {})',
                '            rows = data.get("rows", [])',
                '            if rows and rows[0].get("data"):',
                '                value = rows[0]["data"][0]',
                '                return float(value) if value is not None else None',
                '    except Exception as e:',
                '        print(f"[ERROR] Failed to get {account} for {entity}: {e}")',
                '    return None',
                '',
                '',
                'async def collect_data() -> Dict:',
                '    """Collect data for the report."""',
                '    print("Collecting data...")',
                '    data = {}',
                '    ',
                f'    accounts = {repr(accounts)}',
                f'    entities = {repr(entities)}',
                f'    periods = {repr(periods)}',
                f'    years = {repr(years)}',
                f'    scenarios = {repr(scenarios)}',
                '    ',
                '    for account in accounts:',
                '        for entity in entities:',
                '            for period in periods:',
                '                for year in years:',
                '                    for scenario in scenarios:',
                '                        key = f"{account}|{entity}|{period}|{year}|{scenario}"',
                '                        value = await get_account_value(account, entity, period, year, scenario)',
                '                        data[key] = {',
                '                            "account": account,',
                '                            "entity": entity,',
                '                            "period": period,',
                '                            "year": year,',
                '                            "scenario": scenario,',
                '                            "value": value',
                '                        }',
                '                        if value is not None:',
                '                            print(f"[OK] {account} - {entity} - {period} {year} ({scenario}): ${value:,.2f}")',
                '    ',
                '    return data',
                '',
                '',
                'def generate_html_report(data: Dict) -> str:',
                '    """Generate HTML report."""',
                '    timestamp = datetime.now().strftime(\'%Y%m%d_%H%M%S\')',
                f'    filename = f"{script_base_name}_{{timestamp}}.html"',
                '    ',
                '    # Build HTML content',
                '    html_parts = ["""<!DOCTYPE html>',
                '<html>',
                '<head>',
                '    <meta charset="UTF-8">',
                f'    <title>{description}</title>',
                '    <style>',
                '        body { font-family: Arial, sans-serif; margin: 40px; background-color: #f5f5f5; }',
                '        .container { background-color: white; padding: 40px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }',
                '        h1 { color: #1f4788; border-bottom: 3px solid #1f4788; padding-bottom: 10px; }',
                '        h2 { color: #2c5aa0; margin-top: 30px; }',
                '        table { width: 100%; border-collapse: collapse; margin: 20px 0; }',
                '        th { background-color: #1f4788; color: white; padding: 12px; text-align: left; }',
                '        td { padding: 10px; border: 1px solid #ddd; }',
                '        tr:nth-child(even) { background-color: #f9f9f9; }',
                '        .positive { color: #2d5016; font-weight: bold; }',
                '        .negative { color: #8b0000; font-weight: bold; }',
                '        .footer { margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd; color: #666; font-size: 12px; }',
                '    </style>',
                '</head>',
                '<body>',
                '    <div class="container">',
                f'        <h1>{description}</h1>',
                '        <p><strong>Generated:</strong> {datetime.now().strftime(\'%B %d, %Y %H:%M:%S\')}</p>',
                '        <h2>Report Data</h2>',
                '        <table>',
                '            <thead>',
                '                <tr>',
                '                    <th>Account</th>',
                '                    <th>Entity</th>',
                '                    <th>Period</th>',
                '                    <th>Year</th>',
                '                    <th>Scenario</th>',
                '                    <th style="text-align: right;">Value ($)</th>',
                '                </tr>',
                '            </thead>',
                '            <tbody>',
                '"""]',
                '    ',
                '    # Add data rows',
                '    for key, item in data.items():',
                '        value = item.get("value")',
                '        value_class = "positive" if value and value >= 0 else "negative"',
                '        value_display = f"${value:,.2f}" if value is not None else "N/A"',
                '        html_parts.append(f"""',
                '                <tr>',
                '                    <td>{item[\'account\']}</td>',
                '                    <td>{item[\'entity\']}</td>',
                '                    <td>{item[\'period\']}</td>',
                '                    <td>{item[\'year\']}</td>',
                '                    <td>{item[\'scenario\']}</td>',
                '                    <td style="text-align: right;" class="{value_class}">{value_display}</td>',
                '                </tr>',
                '""")',
                '    ',
                '    html_parts.append("""',
                '            </tbody>',
                '        </table>',
                '        <div class="footer">',
                '            <p><strong>FCCS Custom Report</strong></p>',
                '            <p>Data from Oracle EPM Cloud Financial Consolidation and Close (FCCS)</p>',
                '            <p>Generated: {datetime.now().strftime(\'%Y-%m-%d %H:%M:%S\')}</p>',
                '        </div>',
                '    </div>',
                '</body>',
                '</html>',
                '""")',
                '    ',
                '    html_content = "".join(html_parts)',
                '    ',
                '    # Save file',
                '    filepath = Path(filename)',
                '    with open(filepath, "w", encoding="utf-8") as f:',
                '        f.write(html_content)',
                '    ',
                '    return str(filepath.absolute())',
                '',
                '',
                'async def generate_report():',
                '    """Main function to generate the report."""',
                '    print("=" * 80)',
                f'    print("GENERATING {description.upper()}")',
                '    print("=" * 80)',
                '    print()',
                '    ',
                '    try:',
                '        config = load_config()',
                '        await initialize_agent(config)',
                '        print("[OK] Connected to FCCS")',
                '        print()',
                '        ',
                '        # Collect data',
                '        data = await collect_data()',
                '        print()',
                '        print(f"[OK] Collected {len(data)} data points")',
                '        print()',
                '        ',
                '        # Generate report',
                '        print("Generating report...")',
                '        report_path = generate_html_report(data)',
                '        ',
                '        print()',
                '        print("=" * 80)',
                '        print(f"[SUCCESS] Report generated: {report_path}")',
                '        print("=" * 80)',
                '        print()',
                '        ',
                '        await close_agent()',
                '        ',
                '    except Exception as e:',
                '        print(f"\\n[ERROR] {e}")',
                '        import traceback',
                '        traceback.print_exc()',
                '        sys.exit(1)',
                '',
                '',
                'if __name__ == "__main__":',
                '    asyncio.run(generate_report())',
                ''
            ]
            
            script_content = '\n'.join(script_lines)
            
            # Save script to scripts directory
            scripts_dir = Path("scripts")
            scripts_dir.mkdir(exist_ok=True)
            
            script_path = scripts_dir / script_name
            with open(script_path, "w", encoding="utf-8") as f:
                f.write(script_content)
            
            return {
                "status": "success",
                "data": {
                    "script_path": str(script_path.absolute()),
                    "filename": script_name,
                    "message": "Python script template generated successfully",
                    "note": f"Script saved to {script_path}. Run with: python {script_path}"
                }
            }
            
        except Exception as e:
            return {
                "status": "error",
                "error": f"Failed to generate script: {str(e)}"
            }
  • Input schema definition for the tool in TOOL_DEFINITIONS.
        "name": "generate_report_script",
        "description": "Generate a Python script template for custom FCCS reporting / Gerar script Python para relatorio customizado",
        "inputSchema": {
            "type": "object",
            "properties": {
                "script_name": {
                    "type": "string",
                    "description": "Name of the script file (without .py extension)",
                },
                "report_type": {
                    "type": "string",
                    "enum": ["HTML", "PDF", "CSV"],
                    "description": "Type of report (default: HTML)",
                },
                "description": {
                    "type": "string",
                    "description": "Description of what the report does",
                },
                "accounts": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "List of account names to query",
                },
                "entities": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "List of entity names to query",
                },
                "periods": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "List of periods to query (e.g., ['Jan', 'Feb', 'Dec'])",
                },
                "years": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "List of years to query (e.g., ['FY24', 'FY25'])",
                },
                "scenarios": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "List of scenarios to query (e.g., ['Actual', 'Budget'])",
                },
            },
            "required": ["script_name"],
        },
    },
  • Tool handler registration in the central TOOL_HANDLERS dictionary.
    "generate_report_script": reports.generate_report_script,
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the tool generates a 'template' but doesn't clarify what that means operationally: Does it create a file? Where is it saved? What permissions are needed? Is it a one-time generation or can it be modified? The description lacks details about the tool's behavior, output format, or any side effects.

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

Conciseness4/5

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

The description is brief and front-loaded with the primary purpose in the first part ('Generate a Python script template for custom FCCS reporting'). The Portuguese translation adds redundancy but doesn't significantly harm clarity. It avoids unnecessary elaboration, though it could be more structured by explicitly mentioning it's a template generator versus a direct report tool.

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

Completeness2/5

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

Given the complexity (8 parameters, no annotations, no output schema), the description is insufficient. It doesn't explain what the generated script does, how to use it, or what the output looks like. For a tool that creates code templates, more context is needed about the template's structure, dependencies, or intended execution environment. The description leaves too many open questions for effective use.

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

Parameters3/5

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

The input schema has 100% description coverage, with all 8 parameters clearly documented in the schema itself. The description adds no additional parameter information beyond what's in the schema (e.g., it doesn't explain relationships between parameters like 'accounts' and 'entities', or provide examples beyond the enum). With high schema coverage, the baseline score of 3 is appropriate as the description doesn't compensate but also doesn't detract.

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

Purpose4/5

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

The description clearly states the tool's purpose: 'Generate a Python script template for custom FCCS reporting' (with Portuguese translation). It specifies the verb ('generate'), resource ('Python script template'), and domain ('custom FCCS reporting'). However, it doesn't explicitly differentiate from sibling tools like 'generate_report' or 'generate_consolidation_process_report', which might also produce reports but through different mechanisms.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites, typical use cases, or how it differs from other report-generation tools in the sibling list (e.g., 'generate_report' might produce immediate reports while this creates script templates). There's no 'when-not-to-use' or comparison information.

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

Install Server

Other Tools

Latest Blog Posts

MCP directory API

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

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ivossos/fccs-mcp-ag-server'

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