1. Conduid
  2. Security
  3. D365FSC Security MCP
MCP server · Security

D365FSC Security MCP

A .NET based MCP server that connects to Dynamics 365 Finance & Supply Chain and allows to for queries focused around user security

Unclaimed security
34Low

Scored 4 months ago · breakdown

About D365FSC Security MCP

D365FSC Security MCP is an MCP server in the Security category: a .NET based MCP server that connects to Dynamics 365 Finance & Supply Chain and allows to for queries focused around user security. It has been installed 0 times through Conduid.

Install

Clone
git clone https://github.com/ameyer505/D365FSC-Security-MCP

This server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.

Ask AI

Ask AI about D365FSC Security MCP

Powered by Claude · Grounded in docs

I know everything about D365FSC Security MCP. Ask me about installation, configuration, usage, or troubleshooting.

Security checks

  • ·README presentNot checked yet.
  • ·License declaredNot checked yet.
  • ·Tests presentNot checked yet.
  • ·Dependencies pinnedNot checked yet.
  • ·No dynamic code executionNot checked yet.
  • ·Scoped permissionsNot checked yet.

README

D365 F&SC Security Analysis via MCP + Programmatic Tool Calling

Companion code for the blog post series "Using Claude AI to Analyze D365 F&SC Security Data".

Post Approach Best For
Part 1 Manual copy/paste into Claude chat One-off analysis, no setup
Part 2 Claude API + OData via C# console app Automated, repeatable queries
Part 3 (this repo) MCP Server + Programmatic Tool Calling Interactive analysis + batch efficiency

Solution Structure

D365ClaudeIntegration.sln
│
├── D365McpServer/                   # The MCP server
│   ├── D365McpServer.csproj
│   ├── appsettings.json             # D365 connection config
│   ├── Program.cs                   # Host setup, stdio transport, DI wiring
│   ├── Models/
│   │   ├── D365Config.cs            # Config binding model
│   │   └── D365Models.cs            # OData response models
│   ├── Services/
│   │   └── D365ODataService.cs      # MSAL auth + OData query execution
│   └── Tools/
│       └── D365SecurityTools.cs     # [McpServerTool] definitions
│
├── D365ProgrammaticClient/          # Programmatic tool calling demo
│   ├── D365ProgrammaticClient.csproj
│   ├── appsettings.json             # Anthropic API key + MCP server path
│   └── Program.cs                   # Batch user analysis with shared role schema
│
└── claude_desktop_config_snippet.json   # Claude Desktop wiring

Package Versions

D365McpServer

Package Version
ModelContextProtocol 1.1.0
Microsoft.Extensions.Hosting 9.0.0
Microsoft.Extensions.Http 9.0.0
Microsoft.Identity.Client 4.67.2
Microsoft.Extensions.Configuration.Json 9.0.0
Microsoft.Extensions.Configuration.Binder 9.0.0

D365ProgrammaticClient

Package Version
Anthropic.SDK 5.10.0
ModelContextProtocol 1.1.0
Microsoft.Extensions.Configuration.Json 9.0.0
Microsoft.Extensions.Configuration.Binder 9.0.0

Note on Anthropic.SDK vs the official Anthropic package: Anthropic.SDK (by tghamm) is the community-built SDK used throughout this series for continuity with Parts 1 and 2. As of package version 10+, a separate Anthropic NuGet package became the official Anthropic C# SDK with a different API surface. This repo intentionally stays on Anthropic.SDK 5.x.


Prerequisites

  • .NET 9 SDK
  • A D365 F&SC environment (sandbox is fine)
  • An Azure AD App Registration with D365 API permissions (same setup as Part 2)
  • Claude Desktop — for interactive MCP use
  • An Anthropic API key — for the programmatic client

Setup: D365McpServer

1. Configure D365 Connection

Edit D365McpServer/appsettings.json:

{
  "D365": {
    "TenantId": "your-azure-ad-tenant-id",
    "ClientId": "your-app-registration-client-id",
    "ClientSecret": "your-client-secret",
    "ResourceUrl": "https://your-env.sandbox.operations.dynamics.com",
    "ApiVersion": "7.0"
  }
}

2. Build and Publish

cd D365McpServer
dotnet build -c Release
dotnet publish -c Release -o ./publish

3. Configure Claude Desktop

Add to your Claude Desktop config file:

  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "d365-security": {
      "command": "C:\\path\\to\\D365McpServer\\publish\\D365McpServer.exe",
      "args": [],
      "env": {}
    }
  }
}

Fully restart Claude Desktop after saving. Verify the server connected via Settings → Developer → MCP Servers — it should show a green status indicator. MCP server logs are written to stderr and can be found in %APPDATA%\Claude\logs\ on Windows.

4. Test Interactively

Open a new Claude Desktop conversation and try:

Show me all active users in the USMF company, then pull the role
assignments for the first 3 users you find.

Claude will discover and call your MCP tools automatically.


Setup: D365ProgrammaticClient

1. Configure

Edit D365ProgrammaticClient/appsettings.json:

{
  "Anthropic": {
    "ApiKey": "sk-ant-...",
    "Model": "claude-sonnet-4-6"
  },
  "McpServer": {
    "ExecutablePath": "C:\\path\\to\\D365McpServer\\publish\\D365McpServer.exe"
  }
}

2. Update the User List

In D365ProgrammaticClient/Program.cs, update the usersToAnalyze array with real user IDs from your environment.

3. Run

cd D365ProgrammaticClient
dotnet run

Results are written to analysis-results.json in the build output directory.


MCP Tools Exposed

Tool Description
GetUsers List D365 users, optionally filtered by company and/or enabled status
GetSecurityRoles Retrieve the full security role catalog
GetUserRoleAssignments Get all role assignments for a specific user
RunODataQuery Execute any arbitrary OData query (power user escape hatch)

How Programmatic Tool Calling Saves Tokens

When Claude calls tools interactively via Claude Desktop, the full tool schema is sent on every API call. For batch operations this adds up fast.

The programmatic client avoids this by:

  1. Fetching the tool schema once via ListToolsAsync() and reusing it across all calls
  2. Pre-fetching the role catalog once directly via CallToolAsync("GetSecurityRoles"), then injecting it as prompt context rather than letting Claude call the tool on each iteration
  3. Registering only the tools Claude needs for the batch — omitting GetUsers and GetSecurityRoles from the schema entirely reduces per-call input tokens

Rough token comparison for a 20-user batch:

Approach Estimated Input Tokens
Interactive (schema on every call) ~16,000
Programmatic (schema once + pre-fetched catalog) ~4,000

The savings grow linearly with user count and schema complexity.


Enterprise Option: HTTP/SSE Transport

The blog post uses stdio for simplicity — Claude Desktop spawns the server as a local process. For a centrally hosted team deployment, switch to HTTP/SSE by replacing .WithStdioServerTransport() in D365McpServer/Program.cs with:

.WithHttpServerTransport(options => options.Port = 5050)

Then point Claude Desktop at the URL instead of an executable:

{
  "mcpServers": {
    "d365-security": {
      "url": "http://your-server:5050/sse"
    }
  }
}

Host in Azure Container Apps behind Azure API Management for auth, rate limiting, and centralized audit logging — giving your entire D365 security team access through a single managed integration without needing local credentials.


Build Troubleshooting

This section documents every breaking change encountered building this solution against the current package versions. Hopefully this saves you from the same debugging loop.

Solution Structure (CS8802)

Both projects must be in their own subdirectories under the .sln file. If you see CS8802: Only one compilation unit can have top-level statements, the most likely cause is stale files from a previous session being picked up by the compiler. Ensure only one Program.cs exists per project folder.

ModelContextProtocol 1.1.0 — Breaking Changes from 0.2.x

Area Old API New API
Client creation McpClientFactory.CreateAsync() McpClient.CreateAsync()
Transport namespace ModelContextProtocol.Protocol.Transport ModelContextProtocol.Client
Client type IMcpClient (interface) McpClient (concrete class)
Tool schema access tool.InputSchema tool.ProtocolTool.InputSchema (returns JsonElement)
Tool result text ContentBlock.Text Cast to TextContentBlock first (see below)

Reading text from a tool result:

CallToolAsync returns IList<ContentBlock>. The base ContentBlock class does not expose .Text — you must cast to the TextContentBlock subtype. Use the fully-qualified name to avoid ambiguity with Anthropic.SDK.Messaging.TextContent:

var text = result.Content
    .OfType<ModelContextProtocol.Protocol.TextContentBlock>()
    .FirstOrDefault()?.Text ?? "{}";

Converting MCP tool definitions to Anthropic.SDK tools:

McpClientTool.ProtocolTool.InputSchema is a JsonElement. Parse it to JsonNode for the Function constructor:

var schemaNode = JsonNode.Parse(t.ProtocolTool.InputSchema.GetRawText()) ?? new JsonObject();
var tool = (Common.Tool) new Function(t.Name, t.Description ?? string.Empty, schemaNode);

Anthropic.SDK 5.x — Breaking Changes from 3.x

Area Old type New type
Text response content TextBlock TextContent
Tool call request from Claude ToolUseBlock ToolUseContent
Tool result back to Claude ToolResultBlock ToolResultContent
Tool list parameter IList<Messaging.Tool> IList<Common.Tool>
Tool definition new Tool { Name, Description, InputSchema } new Function(name, description, JsonNode)

ToolResultContent.Content is List<ContentBase>, not string:

Even though the Anthropic API accepts a plain string for tool results at the protocol level, the C# SDK requires a typed list:

// Incorrect — does not compile
new ToolResultContent { ToolUseId = id, Content = "result text" }

// Correct
new ToolResultContent
{
    ToolUseId = id,
    Content   = new List<ContentBase> { new TextContent { Text = "result text" } }
}

Message.Content is List<ContentBase>, not string:

// Incorrect — does not compile
new Message { Role = RoleType.User, Content = "your prompt" }

// Correct — use the constructor overload
new Message(RoleType.User, "your prompt")

Anthropic.SDK 5.x — NU1015 Package Error

If you see NU1015: The following PackageReference item(s) do not have a version specified, bump Anthropic.SDK to 5.10.0 or later. Earlier 3.x versions have a transitive dependency conflict with .NET 9 that triggers this error.

DotnetToolReference Error

If you see Package 'mcpclient x.x.x' has a package type 'DotnetTool' that is not supported, your .csproj has a stale <DotnetToolReference> entry from a previous session. Remove it — the .csproj files in this repo do not contain one.

README mirrored from the source repository 4 months ago. The original is authoritative.

Questions

About D365FSC Security MCP

How do I install D365FSC Security MCP?

Run git clone https://github.com/ameyer505/D365FSC-Security-MCP, then add the server to your MCP client's configuration. Conduid has recorded 0 installs, so the command is known to work with current clients.

Is D365FSC Security MCP safe to use with an AI agent?

Its trust score is 34 out of 100 (low). Conduid hasn't run static security checks on this repository yet, so review the source yourself before granting it credentials. It has no ConduID identity yet, so agent calls to it are not receipted.

Is D365FSC Security MCP still maintained?

Conduid hasn't recorded a commit date for this repository yet. Check the repository directly for recent activity.