> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bigdata.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Deep Research models

## Overview

We are excited to introduce a new Bigdata Remote MCP server with `search` and `fetch` tools that comply with OpenAI Deep Research model standards. These tools allow you to leverage Bigata.com's financial premium content to generate professional-grade research reports in under 30 minutes with full inline source attribution.

This guide describes how to use the new Remote MCP server `https://mcp.bigdata.com/deepresearch/` with OpenAI's o3-deep-research model to produce comprehensive equity research reports in PDF.

<Card title="GitHub Repository" icon="github" href="https://github.com/Bigdata-com/bigdata-docs-resources/tree/main/how_to_guides/mcp_deep_research_openai">
  Access the complete source code, requirements, and setup instructions.
</Card>

## Features

✅ Generates detailed equity research reports using Bigdata.com Search Service. <br />
✅ Provides visibility into all MCP requests and responses. <br />
✅ Displays a summary table of tool calls by type. <br />
✅ Tracks total response time. <br />
✅ Exports the final report as a professionally styled PDF. <br />

Example output:
Download the complete <Icon icon="file-pdf" /> <a href="https://github.com/Bigdata-com/bigdata-docs-resources/blob/68cc1f221bbcd8ce8fbf6eedbe78441471ce6d1d/mcp/api-integrations/research_report_20260115_154847.pdf" target="_blank" rel="noopener noreferrer">Micron Q2 FY2026 Earnings Preview PDF</a>

<img src="https://mintcdn.com/ravenpackinternational/Gm6Y381xwA7dNtJs/images/mcp/api-integrations/deep-research/research_report_20260115_154847.png?fit=max&auto=format&n=Gm6Y381xwA7dNtJs&q=85&s=0574d4abbebd758c5680c01852d56f42" alt="Micron Earnings Preview PDF" width="2687" height="1863" data-path="images/mcp/api-integrations/deep-research/research_report_20260115_154847.png" />

## Prerequisites

* Python 3.9 or higher
* An OpenAI API key with access to the `o3-deep-research-2025-06-26` model
* A Bigdata.com API key

### System Dependencies

WeasyPrint requires some system libraries for PDF generation.

<Tabs>
  <Tab title="Ubuntu/Debian">
    ```bash theme={null}
    sudo apt-get install libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf2.0-0
    ```
  </Tab>

  <Tab title="macOS">
    ```bash theme={null}
    brew install pango
    ```
  </Tab>

  <Tab title="Windows">
    Follow the [WeasyPrint installation guide](https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#windows) for Windows-specific instructions.
  </Tab>
</Tabs>

## Setup

<Steps>
  <Step title="Clone the repository">
    ```bash theme={null}
    git clone https://github.com/Bigdata-com/bigdata-docs-resources.git
    cd bigdata-docs-resources/how_to_guides/mcp_deep_research_openai
    ```
  </Step>

  <Step title="Create a virtual environment (recommended)">
    ```bash theme={null}
    python -m venv venv
    ```

    Activate the virtual environment:

    <Tabs>
      <Tab title="Linux/macOS">
        ```bash theme={null}
        source venv/bin/activate
        ```
      </Tab>

      <Tab title="Windows">
        ```bash theme={null}
        venv\Scripts\activate
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Install Python dependencies">
    ```bash theme={null}
    pip install -r requirements.txt
    ```
  </Step>

  <Step title="Configure API Keys">
    Copy the `.env_template` file to `.env`:

    ```bash theme={null}
    cp .env_template .env
    ```

    Open the `.env` file and replace the placeholder values with your actual API keys:

    ```
    OPENAI_API_KEY=your_openai_api_key_here
    BIGDATA_API_KEY=your_bigdata_api_key_here
    ```

    You can obtain your API keys from:

    * **OpenAI API Key:** [OpenAI Platform](https://platform.openai.com/api-keys)
    * **Bigdata API Key:** [Bigdata Platform](https://platform.bigdata.com/api-keys)

    <Warning>
      Never commit your `.env` file to version control. Add it to your `.gitignore` file.
    </Warning>
  </Step>
</Steps>

## Usage

### Run the script

```bash theme={null}
python deep-research-mcp.py
```

### Customizing the prompt

To change the prompt, edit the `input` parameter in the `client.responses.create()` call. The default prompt requests a Micron earnings preview.

## Code

```python highlight="36" theme={null}
from dotenv import load_dotenv
from openai import OpenAI
import os
import json
import time
from datetime import datetime
from collections import Counter
import markdown
from weasyprint import HTML, CSS

load_dotenv()

# Read Bigdata API key from environment
BIGDATA_API_KEY = os.getenv("BIGDATA_API_KEY")

client = OpenAI()

# Track response time
start_time = time.time()

resp = client.responses.create(
    model="o3-deep-research-2025-06-26",
    input="""You are a senior equity analyst preparing for an upcoming earnings call. Please provide a comprehensive earnings preview and analysis for Micron.

Cover:
- Recent developments and initiatives
- Industry trends and sector dynamics
- Bull/bear cases
- Key metrics to watch

Deliverable Format: Present findings as a concise, actionable brief suitable for investment professionals. Focus on business fundamentals, avoid speculation, and highlight areas of uncertainty or debate. Be decisive in your assessments while acknowledging alternative viewpoints. Add inline source attribution and use the Bigdata MCP.""",
    tools=[
        {
            "type": "mcp",
            "server_label": "bigdata",
            "server_url": "https://mcp.bigdata.com/deepresearch/",
            "headers": {
                "x-api-key": BIGDATA_API_KEY
            },
            "require_approval": "never",
        }
    ]
)

end_time = time.time()
elapsed_time = end_time - start_time

# Display MCP tool calls and responses
print("=" * 80)
print("MCP REQUESTS AND RESPONSES")
print("=" * 80)

mcp_call_count = 0
tool_calls_counter = Counter()

for item in resp.output:
    item_type = getattr(item, 'type', None)
    
    # MCP tool calls (requests to MCP server)
    if item_type == 'mcp_call':
        mcp_call_count += 1
        tool_name = getattr(item, 'name', 'N/A')
        tool_calls_counter[tool_name] += 1
        print(f"\n[MCP CALL #{mcp_call_count}]")
        print(f"  Server: {getattr(item, 'server_label', 'N/A')}")
        print(f"  Tool: {tool_name}")
        print(f"  Call ID: {getattr(item, 'id', 'N/A')}")
        if hasattr(item, 'arguments'):
            print(f"  Arguments: {item.arguments}")
    
    # MCP tool results (responses from MCP server)
    elif item_type == 'mcp_call_output':
        print(f"\n[MCP RESPONSE for call: {getattr(item, 'call_id', 'N/A')}]")
        output = getattr(item, 'output', None)
        if output:
            # Try to pretty-print if it's JSON
            try:
                parsed = json.loads(output) if isinstance(output, str) else output
                print(f"  Output: {json.dumps(parsed, indent=4)[:2000]}...")
            except (json.JSONDecodeError, TypeError):
                print(f"  Output: {str(output)[:2000]}...")
    
    # MCP list tools response
    elif item_type == 'mcp_list_tools':
        print(f"\n[MCP LIST TOOLS - Server: {getattr(item, 'server_label', 'N/A')}]")
        tools = getattr(item, 'tools', [])
        for tool in tools:
            tool_name = getattr(tool, 'name', 'N/A')
            tool_desc = getattr(tool, 'description', '')[:100]
            print(f"  - {tool_name}: {tool_desc}")

# Display summary with table
print(f"\n{'=' * 80}")
print("MCP CALLS SUMMARY")
print("=" * 80)

# Format elapsed time
if elapsed_time >= 60:
    minutes = int(elapsed_time // 60)
    seconds = elapsed_time % 60
    time_str = f"{minutes}m {seconds:.2f}s"
else:
    time_str = f"{elapsed_time:.2f}s"

print(f"\nTotal Response Time: {time_str}")
print(f"\nTotal MCP Calls: {mcp_call_count}")

if tool_calls_counter:
    print("\nCalls per Tool:")
    print("-" * 40)
    print(f"{'Tool Name':<30} {'Calls':>8}")
    print("-" * 40)
    for tool_name, count in tool_calls_counter.most_common():
        print(f"{tool_name:<30} {count:>8}")
    print("-" * 40)
    print(f"{'TOTAL':<30} {mcp_call_count:>8}")

print("=" * 80)

# Display final output
print("\n" + "=" * 80)
print("FINAL OUTPUT")
print("=" * 80)
print(resp.output_text)

# Convert markdown to PDF
print("\n" + "=" * 80)
print("GENERATING PDF")
print("=" * 80)

# Convert markdown to HTML
html_content = markdown.markdown(
    resp.output_text,
    extensions=['tables', 'fenced_code', 'toc']
)

# Add CSS styling for professional look
css_style = CSS(string='''
    @page {
        margin: 1in;
        size: letter;
    }
    body {
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
        font-size: 11pt;
        line-height: 1.6;
        color: #333;
    }
    h1 {
        color: #1a1a1a;
        border-bottom: 2px solid #333;
        padding-bottom: 0.3em;
        font-size: 24pt;
    }
    h2 {
        color: #2c2c2c;
        border-bottom: 1px solid #ccc;
        padding-bottom: 0.2em;
        font-size: 18pt;
        margin-top: 1.5em;
    }
    h3 {
        color: #444;
        font-size: 14pt;
        margin-top: 1.2em;
    }
    table {
        border-collapse: collapse;
        width: 100%;
        margin: 1em 0;
    }
    th, td {
        border: 1px solid #ddd;
        padding: 8px;
        text-align: left;
    }
    th {
        background-color: #f5f5f5;
        font-weight: bold;
    }
    tr:nth-child(even) {
        background-color: #fafafa;
    }
    code {
        background-color: #f4f4f4;
        padding: 2px 6px;
        border-radius: 3px;
        font-family: "Courier New", monospace;
        font-size: 10pt;
    }
    pre {
        background-color: #f4f4f4;
        padding: 1em;
        border-radius: 5px;
        overflow-x: auto;
    }
    blockquote {
        border-left: 4px solid #ccc;
        margin: 1em 0;
        padding-left: 1em;
        color: #666;
    }
    ul, ol {
        margin: 0.5em 0;
        padding-left: 2em;
    }
    li {
        margin: 0.3em 0;
    }
''')

# Wrap HTML content with proper document structure
full_html = f'''
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Research Report</title>
</head>
<body>
{html_content}
</body>
</html>
'''

# Generate PDF filename with timestamp
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
pdf_filename = f"research_report_{timestamp}.pdf"

# Create PDF
HTML(string=full_html).write_pdf(pdf_filename, stylesheets=[css_style])

print(f"\nPDF generated: {pdf_filename}")
```
