Manages environment variables for storing configuration and secrets.
Serves as the web server foundation for the MCP implementation, handling HTTP requests to the /mcp endpoint.
Included workflow for automated deployment to Azure Web App services.
Used for unit and integration testing of the MCP server components.
Required runtime environment for running the server (v18 or later recommended).
Provides OpenAPI specification for registering the MCP server as a custom connector in Microsoft Copilot Studio.
The project is built with TypeScript, providing type safety and modern JavaScript features.
Format used for the OpenAPI/Swagger definition that enables integration with Microsoft Copilot Studio.
Used for defining and validating the schema of tool arguments.
Dynamics 365 Finance & Operations MCP Server
This project is a TypeScript-based server that implements the Model Context Protocol (MCP) to provide a secure and efficient gateway to the Dynamics 365 Finance & Operations (F&O) OData API. It exposes various D365 F&O data entities and actions as a set of tools that can be consumed by Large Language Models (LLMs), Microsoft Copilot Studio, or other MCP-compatible clients.
The server handles authentication with Azure AD, including caching the bearer token to optimize performance by avoiding re-authentication on every API call.
Features
- MCP Compliant: Built using the official
@modelcontextprotocol/sdk
. - Authenticated: Securely connects to the D365 F&O OData API using the OAuth 2.0 client credentials flow.
- Efficient: Automatically caches the authentication token and refreshes it only when it's about to expire. It also caches the OData entity list for fast lookups.
- User-Friendly: The
odataQuery
tool uses a fuzzy-matching algorithm (fuse.js
) to find the correct entity, even if the user's input has the wrong case or is slightly misspelled. - Well-Structured: The project is organized by concern, separating the Express server, MCP tool definitions, API communication layer, and authentication logic.
- Tested: Includes a testing suite with Jest for unit and integration tests to ensure reliability and maintainability.
- Extensible: Easily add new tools to expose more D365 F&O entities or actions.
Prerequisites
- Node.js (v18 or later recommended)
- An Azure Active Directory (Azure AD) App Registration with permissions to access your Dynamics 365 F&O environment.
- Your D365 F&O environment URL.
Setup and Installation
Follow these steps to get the server up and running.
1. Get the Code
Clone this repository to your local machine.
2. Configure Environment Variables
This project uses a .env
file to manage secret credentials.
- Create a
.env
file by copying the example template: - Edit the
.env
file and populate it with your Azure AD and Dynamics 365 details.
3. Install Dependencies
Open a terminal in the project's root directory and run:
Running the Server
You can run the server in two modes:
Development Mode
For development, use the dev
script. This uses tsx
to run the server with hot-reloading, automatically restarting it when you make changes to the source code.
Production Mode
For a production environment, you should first build the TypeScript code into JavaScript and then run the compiled output.
- Build the project:This will compile the
src
directory into adist
directory. - Start the server:
Once running, the server will be available at http://localhost:3000
(or the port you specify in the .env
file). The MCP endpoint is http://localhost:3000/mcp
.
Testing Strategy
This project uses Jest as its testing framework. Tests are located alongside the source files they are testing (e.g., auth.test.ts
tests auth.ts
).
The testing strategy includes:
- Unit Tests: To test individual modules, like the
AuthManager
, in isolation. These tests use mocking to simulate external dependencies likefetch
. - Integration Tests: To test how different parts of the MCP server work together. These tests use the SDK's
InMemoryTransport
to simulate a client-server connection without making real network calls, allowing for fast and reliable verification of tool definitions and behaviors.
Running Tests
To run the entire test suite, execute the following command:
Project Architecture
The server code is organized into several files within the src/
directory to promote separation of concerns:
index.ts
: The main entry point of the application. It's responsible for setting up and starting the Express web server and handling incoming MCP requests.mcp-server.ts
: Defines the MCP server itself and registers all the available tools that wrap the Dynamics 365 API endpoints.api.ts
: Acts as a service layer or gateway for all communication with the external Dynamics 365 OData API. It contains themakeApiCall
helper function.auth.ts
: Contains theAuthManager
class, which is responsible for the entire authentication lifecycle, including fetching and caching the bearer token.entityManager.ts
: Contains theEntityManager
class, which handles fetching, caching, and fuzzy-matching OData entity names to improve usability.
Available Tools
This MCP server exposes the following tools. An MCP client can call these to interact with Dynamics 365.
Tool Name | Description | Arguments |
---|---|---|
odataQuery | Executes a generic GET request against any D365 OData entity. The entity name does not need to be case-perfect. It also smartly enables cross-company search if dataAreaId is part of the filter. | entity , select (opt), filter (opt), expand (opt), top (opt), crossCompany (opt) |
getEntityCount | Gets the total count of records for a given entity. | entity , crossCompany (opt) |
getODataMetadata | Retrieves the OData $metadata document for the service. | None |
createCustomer | Creates a new customer record in the CustomersV3 entity. | customerData (JSON object) |
updateCustomer | Updates an existing customer record. | dataAreaId , customerAccount , updateData (JSON object) |
createSystemUser | Creates a new system user record. | userData (JSON object) |
assignUserRole | Assigns a security role to a user. | associationData (JSON object) |
updatePositionHierarchy | Updates a position in the hierarchy. | positionId , hierarchyTypeName , validFrom , validTo , updateData (JSON object) |
action_initializeDataManagement | Executes a specific OData action to initialize the data management framework. | None |
Extending the Server (Adding a New Tool)
Adding a new tool is straightforward.
- Open
src/mcp-server.ts
. - Inside the
getServer
function, add a newserver.tool()
definition. - Follow the existing pattern:
- Provide a
toolName
. - Provide a
description
for the LLM. - Define the
arguments
schema usingzod
. - In the callback function, use the
context
parameter to accesssendNotification
and other request-specific data. Call themakeApiCall
helper fromapi.ts
with the correct method, URL, and body.
- Provide a
Example: Adding a tool to get Vendor Groups
Security Considerations
- Secrets Management: The
.env
file contains sensitive credentials (CLIENT_ID
,CLIENT_SECRET
, etc.). This file should never be committed to source control. Ensure your.gitignore
file includes.env
. - Azure Deployment: When deploying to Azure, use the Configuration > Application settings panel to store your secrets. These are securely injected as environment variables at runtime and are not stored in your code repository.
- Network Security: For production environments, consider placing the Azure Web App behind a firewall or in a Virtual Network (VNet) and using private endpoints to restrict access.
Deploying to Azure
You can deploy this application directly to an Azure Web App service. The repository includes a sample GitHub Actions workflow file at .github/workflows/main_fno-mcp.yml
that can be adapted for your deployment pipeline.
Step 1: Create an Azure Web App
First, you need to create the Web App resource in the Azure Portal.
- Go to the Azure Portal and click Create a resource.
- Search for "Web App" and click Create.
- Fill out the Basics tab with the following settings:
- Subscription: Choose your Azure subscription.
- Resource Group: Create a new one or select an existing one.
- Name: Give your app a globally unique name (e.g.,
fno-mcp-server-yourname
). This name will form part of your URL. - Publish: Select Code.
- Runtime stack: Select Node 22 LTS.
- Operating System: Select Linux.
- Region: Choose a region close to you.
- Configure the App Service Plan based on your needs (a Free F1 tier is sufficient for testing).
- Click Review + create, then Create to provision the resource. Make a note of the default URL (e.g.,
https://fno-mcp-server-yourname.azurewebsites.net
).
Step 2: Configure GitHub Deployment
Once the Web App is created, configure it to automatically deploy from your GitHub repository.
- Navigate to your newly created Web App resource in the Azure Portal.
- In the left-hand menu, under "Deployment", click on Deployment Center.
- For the Source, select GitHub.
- Authorize Azure to access your GitHub account if you haven't already.
- Configure the build settings:
- Organization: Select your GitHub username or organization.
- Repository: Select your
fno-mcp-server
repository. - Branch: Select
main
.
- Azure will detect the Node.js project and suggest a workflow. Review the settings and click Save. This will commit a workflow file to your repository in the
.github/workflows/
directory. Any subsequent pushes to yourmain
branch will automatically trigger a new deployment to your Azure Web App.
Step 3: Configure Environment Variables in Azure
Your deployed application needs access to the same secrets as your local environment.
- In your Web App's menu, go to Configuration > Application settings.
- Under "Application settings", click + New application setting to add each of the variables from your local
.env
file:TENANT_ID
CLIENT_ID
CLIENT_SECRET
DYNAMICS_RESOURCE_URL
PORT
(optional, Azure provides this automatically but you can set it to8080
)
- Click Save. The app will restart with the new settings.
Step 4: Configure Session Affinity (Required)
This MCP server is stateful. It maintains an in-memory transports
object to keep track of every active client session. For this to work correctly when the app is scaled across multiple instances, you must enable session affinity.
- In your Web App's menu, go to Configuration > General settings.
- Under the "Platform settings" tab, find the Session affinity setting.
- Set it to On.
- Click Save.
With these steps completed, your server will be running on Azure and will automatically update whenever you push changes to your main
branch.
Integrating with Microsoft Copilot Studio
Once your MCP server is deployed, you can register it as a Custom Connector to make its tools available to your copilot. This process is started in Copilot Studio and completed in Power Apps.
The process uses an OpenAPI specification file to describe your server's API.
1. Create the OpenAPI Definition File
First, create an OpenAPI (Swagger) definition that describes your server's single /mcp
endpoint. The key property x-ms-agentic-protocol: mcp-streamable-1.0
tells the platform that this endpoint speaks the Model Context Protocol.
Save the following YAML code as a file named swagger.yaml
on your local machine.
IMPORTANT: You must replace the host
value with the URL of your deployed Azure Web App.
2. Create the Custom Connector
- Navigate to your copilot in Microsoft Copilot Studio.
- Select Topics & Plugins in the left navigation.
- Select + Add a plugin.
- Select Add a custom connector. You will be taken to the Power Apps portal to create the connector.
- On the Custom Connectors page in Power Apps, select + New custom connector.
- From the dropdown, select Import an OpenAPI file.
- Provide a name for your connector (e.g., "D365 F&O MCP Connector").
- Click the Import button and select the
swagger.yaml
file you created in the previous step. - Click Continue.
- Review the imported settings (General, Security, Definition) and click Create connector.
Once the connector is saved, return to Copilot Studio. It will now be available as a tool you can enable for your copilot, allowing it to use the tools from your MCP server.
This server cannot be installed
A TypeScript-based server that implements the Model Context Protocol to provide a secure gateway to the Dynamics 365 Finance & Operations OData API, enabling LLMs and Copilot Studio to interact with D365 F&O data entities.
Related MCP Servers
- AsecurityAlicenseAqualityA Model Context Protocol server that enables LLMs to interact with Salesforce data through SOQL queries, SOSL searches, and various API operations including record management.Last updated -10121PythonMIT License
- -securityAlicense-qualityA Model Context Protocol server that enables interaction with Microsoft 365 services (Excel, Calendar, Mail, OneDrive, Teams, etc.) through the Graph API, allowing AI assistants to manage Microsoft 365 resources via natural language.Last updated -3,074175TypeScriptMIT License
- -securityFlicense-qualityA Model Context Protocol server for managing cloud servers, particularly DigitalOcean droplets, allowing users to identify providers via IP addresses and perform operations like power management, status monitoring, and resource usage tracking.Last updated -1Python
- -securityAlicense-qualityA Model Context Protocol server that provides access to Observe API functionality, enabling LLMs to execute OPAL queries, manage datasets/monitors, and leverage vector search for documentation and troubleshooting runbooks.Last updated -1PythonGPL 3.0