Back to Writing

Building Intelligent D365FO Agents with LangGraph and Model Context Protocol

Building intelligent agents that can interact with enterprise systems like Microsoft Dynamics 365 Finance & Operations (D365FO) has never been more accessible. With the combination of LangGraph and Model Context Protocol (MCP), we can create sophisticated agents that understand natural language requests and execute complex ERP operations seamlessly.

In this comprehensive tutorial, I'll walk you through creating a powerful D365FO agent that can query data, download documents, and perform multi-step operations while intelligently choosing between different AI models for optimal performance.

Contents

Understanding the Architecture

The foundation of our intelligent D365FO agent rests on three key components:

LangGraph Framework: Provides the orchestration layer for multi-step reasoning and tool execution. LangGraph excels at managing complex workflows where agents need to make decisions about which tools to use and in what sequence.

Model Context Protocol (MCP): Serves as the bridge between our agent and the D365FO system. MCP standardizes how AI applications connect to external data sources and tools, making it perfect for enterprise integrations.

Multi-Model Strategy: Different tasks require different strengths. We'll implement intelligent model selection where faster models handle simple queries while more powerful models tackle complex reasoning tasks.

Setting Up the Environment

Our tutorial begins with flexible model configuration supporting multiple providers:

# Multi-provider model configuration
def configure_model_provider():
    """Configure your preferred AI model provider"""

    # Option 1: OpenAI GPT-5
    if 'OPENAI_API_KEY' not in os.environ:
        api_key = getpass("Enter your OpenAI API key: ")
        os.environ['OPENAI_API_KEY'] = api_key
    model_id = "openai:gpt-5"

    # Option 2: Google Gemini 2.5 Flash
    # if 'GOOGLE_API_KEY' not in os.environ:
    #     api_key = getpass("Enter your Google AI API key: ")
    #     os.environ['GOOGLE_API_KEY'] = api_key
    # model_id = "google_genai:gemini-2.5-flash"

    # Option 3: Azure OpenAI
    # Configure Azure-specific endpoints and credentials
    # model_id = "azure_openai:gpt-5-mini"

    return model_id

The key insight here is model flexibility. Each provider offers different strengths:

  • OpenAI GPT-5: Excellent reasoning and complex task handling
  • Google Gemini 2.5 Flash: Optimized for speed and efficiency
  • Azure OpenAI: Enterprise-grade security and compliance

Model Selection Strategy

One of the most crucial decisions in building enterprise AI agents is choosing the right model for each task. Through extensive testing with the D365FO environment, I've found that different models excel in different scenarios:

For Quick Data Queries: Gemini 2.5 Flash provides excellent speed-to-accuracy ratio when retrieving simple information like invoice lists or customer data.

For Complex Document Operations: GPT-5 shows superior understanding of multi-step workflows, especially when chaining operations like "find recent invoices and download their PDFs."

For Enterprise Compliance: Azure OpenAI models offer the security and audit trails required in regulated environments.

Here's how we implement intelligent model selection:

def get_optimal_model_for_task(task_complexity, security_requirements):
    """Select the best model based on task requirements"""
    if security_requirements == "high":
        return "azure_openai:gpt-5-mini"
    elif task_complexity == "simple":
        return "google_genai:gemini-2.5-flash"
    else:
        return "openai:gpt-5"

Creating Custom Tools

While MCP provides excellent D365FO connectivity, the real power comes from combining MCP tools with custom tools tailored to your specific business needs.

Our custom document download tool demonstrates this perfectly:

class PDFDownloadInput(BaseModel):
    document_id: str = Field(description="The ID of the document to save")
    legal_entity: str = Field(description="The legal entity of the document")
    controller_name: str = Field(default="SalesInvoiceController")
    data_table: str = Field(default="CustInvoiceJour")
    data_field: str = Field(default="InvoiceId")
    document_type: str = Field(default="SalesInvoice")

async def download_srs_document(
    document_id: str,
    legal_entity: str,
    controller_name: str = "SalesInvoiceController",
    data_table: str = "CustInvoiceJour",
    data_field: str = "InvoiceId",
    document_type: str = "SalesInvoice",
    reports_directory: str = "./Reports",
    profile: str = "default"
) -> str:
    """Download and save D365FO documents as PDF files"""

    # Construct the action payload for D365FO
    controller_args = {
        "DataTableName": data_table,
        "DataTableFieldName": data_field,
        "DataTableFieldValue": document_id
    }

    # Execute the MCP tool to generate the document
    response = await d365fo_call_action_tool.ainvoke({
        "action_name": "RunCopilotReport",
        "entity_name": "SrsFinanceCopilots",
        "parameters": {
            "_contractName": "SrsCopilotArgsContract",
            "_controllerArgsJson": json.dumps(controller_args),
            "_controllerName": controller_name,
            "_legalEntityName": legal_entity,
            "_reportParameterJson": "{}"
        },
        "profile": profile
    })

    # Process and save the PDF
    if response.get("success"):
        pdf_content = base64.b64decode(response["result"]["value"])
        save_path = f"{reports_directory}/{document_type}_{document_id}_{legal_entity}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"

        with open(save_path, 'wb') as pdf_file:
            pdf_file.write(pdf_content)

        return save_path
    else:
        raise Exception(f"Failed to generate document for {document_id}")

This tool showcases the power of mixing custom logic with MCP capabilities:

  1. Input Validation: Pydantic models ensure proper parameter handling
  2. D365FO Integration: Direct MCP tool invocation for document generation
  3. File Management: Intelligent naming and organization of downloaded documents
  4. Error Handling: Graceful failure management with detailed error messages

Building the LangGraph Agent

The LangGraph agent brings everything together with sophisticated reasoning capabilities:

from langchain.agents import create_agent

# Combine MCP tools with custom tools
all_tools = tools + [download_srs_document_tool]

# Create the intelligent agent
agent = create_agent(
    model_id=model_id,
    tools=all_tools,
    system_prompt=SYSTEM_PROMPT
)

# System prompt optimized for D365FO operations
SYSTEM_PROMPT = """
You are a D365FO document download assistant. Your task is to help users find
and manage documents using the Microsoft Dynamics 365 Finance and Operations
(D365FO) tools and resources.

You excel at:
- Understanding natural language requests about D365FO operations
- Choosing the right tools for each task
- Executing multi-step workflows efficiently
- Providing clear status updates and results

Always prioritize accuracy and provide helpful context about your actions.
"""

Advanced Agent Capabilities

The real magic happens when we test complex scenarios that demonstrate the agent's intelligence:

Multi-Step Document Processing

# Complex request: "Find recent free text invoices and download their PDFs"
agent_response = await agent.ainvoke({
    "messages": "Find the 5 most recent free text invoices in USMF and download PDFs for each"
})

The agent intelligently:

  1. Queries the entity schema to understand available fields
  2. Searches for recent invoices using appropriate OData filters
  3. Downloads each document using the custom tool
  4. Provides comprehensive status updates throughout the process

Context-Aware Operations

# Natural language with business context
agent_response = await agent.ainvoke({
    "messages": "Download customer invoice CIV-000708 for legal entity USMF"
})

The agent demonstrates contextual understanding by:

  • Recognizing "CIV-000708" as a customer invoice ID
  • Automatically selecting the correct controller and table
  • Applying proper legal entity scoping
  • Using appropriate document formatting

Performance Optimization

Through extensive testing, several optimization patterns emerged:

Tool Selection Intelligence: The agent learns to choose between MCP tools and custom tools based on the task requirements. For simple data retrieval, it uses direct MCP queries. For complex document operations, it leverages custom tools.

Batch Processing: When handling multiple documents, the agent efficiently parallelizes operations while respecting D365FO rate limits.

Error Recovery: Sophisticated error handling allows the agent to retry failed operations with different approaches or tools.

# Example of intelligent error recovery
try:
    # Attempt direct document download
    result = await download_srs_document(invoice_id, legal_entity)
except Exception as e:
    # Fallback to alternative approach
    logger.warning(f"Direct download failed: {e}")
    # Try with different controller or parameters
    result = await download_with_fallback(invoice_id, legal_entity)

Production Considerations

Moving from tutorial to production requires several important considerations:

Security: Implement proper credential management, audit logging, and access controls. The MCP architecture supports these enterprise requirements.

Scalability: Design for concurrent operations and efficient resource utilization. Consider implementing connection pooling and request queuing.

Monitoring: Add comprehensive logging and metrics to track agent performance and system health.

Testing: Develop automated tests that cover both individual tool functionality and complex multi-step workflows.

The complete tutorial notebook is available at: LangGraph D365FO Agent using MCP & Custom Tool

Key Takeaways

This implementation demonstrates several crucial insights for enterprise AI development:

  1. Hybrid Tool Architecture: Combining MCP tools with custom tools provides maximum flexibility and capability
  2. Model Selection Matters: Different models excel at different tasks - choose wisely based on requirements
  3. Natural Language Interface: Well-designed agents can understand complex business requests and execute sophisticated workflows
  4. Error Handling is Critical: Enterprise systems require robust error handling and fallback mechanisms
  5. Documentation and Testing: Comprehensive examples and test cases are essential for reliable operations

The combination of LangGraph's orchestration capabilities with MCP's standardized connectivity creates a powerful foundation for enterprise AI applications. By mixing custom tools with MCP tools and selecting appropriate models for each task, we can build agents that truly understand and interact with complex business systems.

Whether you're automating document workflows, creating intelligent data analysis tools, or building comprehensive ERP assistants, this architecture provides a solid foundation for your enterprise AI initiatives.

Get in Touch

Need help implementing LangGraph agents with D365 F&O and MCP? Want to discuss enterprise AI architecture strategies or custom integration solutions?

Connect with me:

Whether you're looking for consulting services, training, or just want to discuss enterprise AI and automation strategies, I'd love to hear from you!

Share this article