Type to search 97 articles.

    Practical engineering guidance

    Securing MCP servers in the enterprise: discovery, permissions and monitoring

    A practical Microsoft guide to discovering MCP servers, controlling their identities and tools, monitoring activity and testing containment.

    Series: Security hardening

    • AI security
    • Microsoft Defender
    • Microsoft Entra ID

    Model Context Protocol (MCP) gives an AI client a standard way to discover and invoke tools. Those tools may read files, query databases, call cloud APIs or change production systems. The important security question is therefore not whether an MCP server can answer a prompt. It is which identity calls it, which tools that identity can invoke, what those tools can reach and whether the activity can be reconstructed afterwards.

    This guide builds a practical control path for Microsoft environments:

    1. discover local and remote MCP servers;
    2. record ownership and intended access;
    3. protect remote servers with Microsoft Entra ID;
    4. separate read-only tools from actions that change state;
    5. constrain remote traffic where Global Secure Access is available;
    6. monitor agent and tool activity; and
    7. test blocking, revocation and investigation.

    It complements Securing enterprise AI agents: a hands-on Microsoft implementation guide, which covers agent identities, managed identity federation, Conditional Access, Defender and Purview in more depth.

    Work through discovery before enforcement. Blocking an unknown integration can interrupt development or operations, while allowing an unknown integration preserves an unmeasured path to data and tools.

    Architecture and trust boundaries

    Treat an MCP deployment as five separate security boundaries:

    Boundary Question to answer
    Client or agent Which user or workload identity starts the request?
    MCP server Who operates it, how is it updated and how is it authenticated?
    Tool Is it read-only, write-capable, privileged or destructive?
    Downstream system Which files, APIs, databases, tenants or subscriptions can it reach?
    Evidence Where are requests, tool decisions, approvals and results recorded?

    Do not approve a server only because its individual tools look harmless. Multiple servers share the same agent context, and untrusted tool descriptions or results can influence how an agent uses another trusted server. Keep credential, filesystem and network contexts separate where the trust level differs.

    Step 1: build the MCP register

    Start with one row for every discovered server. Do not place tokens, connection strings or secret values in the register.

    $Inventory = @(
        [pscustomobject]@{
            ServerName       = 'Example read-only inventory server'
            Publisher        = 'Example publisher'
            Owner            = 'Platform Engineering'
            Transport        = 'Streamable HTTP'
            Endpoint         = 'https://mcp.example.invalid'
            Authentication   = 'Microsoft Entra ID'
            Tools            = 'inventory.read'
            DataClassification = 'Internal'
            ChangeCapability = 'Read only'
            ApprovalRequired = $false
            ReviewDate       = '2026-10-01'
            Status           = 'Pilot'
        }
    )
    
    $Inventory |
        Export-Csv -Path '.\mcp-server-register.csv' -NoTypeInformation

    For each entry, establish:

    • the publisher and supported update path;
    • the accountable business and technical owners;
    • whether the server is local or remote;
    • its executable, package or endpoint;
    • the identity used by the client and by downstream calls;
    • every exposed tool, resource and prompt template;
    • the highest data classification it can reach;
    • whether any tool changes state; and
    • the expiry date for pilot or exception approval.

    The register is an approval record, not an automated discovery result. Reconcile it against endpoint and network evidence in the next steps.

    Step 2: discover local agents and MCP configurations

    Microsoft Defender for Endpoint can discover supported local AI agents and associated local or remote MCP configurations on onboarded Windows and macOS devices. Microsoft currently documents coverage for command-line agents, desktop clients, agentic IDEs and selected extensions.

    In the Microsoft Defender portal:

    1. Confirm the devices are onboarded to Defender for Endpoint and Defender Antivirus is active.
    2. Enable the documented AI-agent discovery or runtime-protection prerequisites for your licensed environment.
    3. Open Assets > AI agents.
    4. Review the agent, device and user relationship.
    5. Open each supported agent and review its associated MCP server configurations.
    6. Compare the server name, type, endpoint and local launch command with the approved register.
    7. Record any unapproved server as a finding; do not silently add it to the approved list.

    Use Advanced Hunting as a supporting check when the dedicated inventory is unavailable. This heuristic finds process command lines that mention MCP; it is not a complete MCP inventory and it can return false positives.

    DeviceProcessEvents
    | where Timestamp > ago(30d)
    | where ProcessCommandLine has_any (
        "mcp",
        "modelcontextprotocol"
    )
    | project
        Timestamp,
        DeviceName,
        AccountName,
        FileName,
        FolderPath,
        ProcessCommandLine,
        InitiatingProcessFileName
    | order by Timestamp desc

    Summarise recurring activity without treating execution count as proof of approval:

    DeviceProcessEvents
    | where Timestamp > ago(30d)
    | where ProcessCommandLine has_any (
        "mcp",
        "modelcontextprotocol"
    )
    | summarize
        FirstSeen = min(Timestamp),
        LastSeen = max(Timestamp),
        Executions = count(),
        Users = make_set(AccountName, 20)
        by DeviceName, FileName
    | order by LastSeen desc

    Configuration discovery and process telemetry answer different questions. A configured server may never have run, while a running server may be launched dynamically without a persistent configuration file.

    Step 3: classify tools before granting access

    Classify each tool according to its maximum effect, not its friendly name.

    Class Example Default control
    Read Retrieve an approved inventory Log and allow for assigned users
    Sensitive read Search mail, source code or security findings Explicit scope, data controls and monitoring
    Write Create a ticket or change a record Human confirmation and narrow target scope
    Privileged Change identity, security or cloud configuration Separate identity and approval outside the model
    Destructive Delete, revoke, disable or rotate Deny by default; break-glass workflow if justified

    Do not combine broad read and destructive operations under one permission such as tools.execute. Define scopes or app roles that represent the real boundary, for example:

    • inventory.read;
    • incidents.read;
    • tickets.create; and
    • changes.execute.approved.

    The model’s instruction is not authorization. The MCP server must enforce the caller’s identity, scope, target and approval state before invoking the downstream operation.

    Step 4: protect a remote MCP server with Microsoft Entra ID

    For a remote HTTP MCP server, treat the server as an OAuth-protected API. Microsoft documents an authorization model based on OAuth 2.1, resource indicators and protected resource metadata.

    In Microsoft Entra admin center:

    1. Open Entra ID > App registrations > New registration.
    2. Create a dedicated registration for the MCP server.
    3. In the manifest, set the requested access-token version to 2.
    4. Under Expose an API, set the Application ID URI to the server’s exact canonical HTTPS URL.
    5. Add granular delegated scopes for interactive clients.
    6. Add application roles for autonomous agent identities where required.
    7. Grant only the client identities that are approved to call the server.

    The relevant manifest section should use v2 access tokens:

    {
      "api": {
        "requestedAccessTokenVersion": 2
      }
    }

    Example identifier URIs must exactly match the resource values used by clients:

    {
      "identifierUris": [
        "https://mcp.example.com",
        "https://mcp.example.com/mcp"
      ]
    }

    Use fictional domains in documentation and substitute the approved production endpoints only in the tenant configuration.

    On every request, use supported authentication middleware to validate:

    • the token signature;
    • issuer (iss);
    • tenant (tid);
    • audience (aud);
    • expiry;
    • delegated scopes (scp) or application roles (roles); and
    • the subject’s authorization for the requested tool.

    Do not create custom token-validation logic. A valid signature alone does not prove that the token was issued for this MCP server or that the caller may execute a particular tool.

    The server must also publish OAuth protected-resource metadata and return an appropriate WWW-Authenticate challenge for an unauthenticated request. Validate that behavior without supplying credentials:

    $Response = Invoke-WebRequest `
        -Uri 'https://mcp.example.com/mcp' `
        -Method Get `
        -SkipHttpErrorCheck
    
    [pscustomobject]@{
        StatusCode = $Response.StatusCode
        Challenge  = $Response.Headers['WWW-Authenticate']
    }

    Expected result: HTTP 401 and a challenge that points the client to the protected-resource metadata. Do not print or decode live access tokens in an article, support transcript or shared terminal log.

    Step 5: remove embedded credentials

    An MCP configuration file must not contain a reusable production secret. Prefer, in order:

    1. managed identity for an Azure-hosted client or server;
    2. workload identity federation;
    3. a certificate held in an appropriate managed store; or
    4. a short-lived development secret stored outside source control.

    Search a repository for accidentally tracked configuration without printing matched values:

    git ls-files |
        Where-Object {
            $_ -match '(?i)(mcp|agent|settings|config)' -and
            $_ -match '\.(json|jsonc|yaml|yml|toml)$'
        }

    Then run the repository’s approved secret scanner and GitHub secret scanning. Avoid a generic command that prints complete matching lines into a shared console. If a real credential is found, rotate or revoke it before considering history cleanup.

    For Azure-hosted components, use a managed identity and assign only the downstream role required by the tool. A shared identity across unrelated MCP servers increases the blast radius and makes attribution weaker.

    Step 6: isolate local servers

    A local stdio MCP server inherits the security context of the process that starts it. Apply controls at the operating-system and client boundary:

    • run it as a standard user;
    • limit filesystem access to an approved working directory;
    • do not expose administrative shells as general tools;
    • use application control to restrict executable and script origins;
    • separate trusted and experimental servers into different environments;
    • restrict outbound destinations where practical;
    • keep production credentials out of the developer session; and
    • require explicit confirmation for write or destructive operations.

    Do not assume a network MCP firewall covers local stdio traffic. Microsoft’s current Global Secure Access MCP inspection applies to supported remote HTTP transports and does not inspect local MCP servers.

    Step 7: constrain remote MCP traffic

    Where licensed and appropriate, the Global Secure Access MCP firewall can apply identity-aware inspection to supported remote MCP traffic. At the time of review this capability is in preview, requires TLS inspection and covers streamable HTTP and Server-Sent Events rather than local stdio.

    Use a staged deployment:

    1. Enable the Internet Access forwarding profile for a pilot group.
    2. Configure TLS inspection according to organisational policy and legal requirements.
    3. Install and validate the Global Secure Access client.
    4. Review Global Secure Access > Monitor > Generative AI Insights to discover servers and tools.
    5. Create an MCP policy with a default action appropriate to the pilot.
    6. Add allow rules for reviewed server URLs and required primitives only.
    7. Link the MCP policy to a security profile.
    8. Apply it through Conditional Access to the pilot group.
    9. Test an allowed tool and a deliberately blocked tool.
    10. Review the traffic logs before broad deployment.

    For a mature environment, the target state is usually an approved-server allow list with explicit exceptions. Move to that state only after discovery has produced a reliable inventory.

    Step 8: monitor tool activity

    Retain enough evidence to answer:

    • who or what invoked the tool;
    • which server and tool were selected;
    • when and from which device or workload;
    • which target resource was requested;
    • whether approval was required and granted;
    • whether the call succeeded, failed or was blocked; and
    • which downstream change or data access resulted.

    For supported Microsoft 365 agent tooling, Microsoft documents MCP invocation activity in CloudAppEvents. Begin with the documented action type and inspect the returned schema in your own tenant before building production detections:

    CloudAppEvents
    | where Timestamp > ago(7d)
    | where ActionType == "ExecuteToolByGateway"
    | project Timestamp, AccountDisplayName, Application, ActionType, RawEventData
    | order by Timestamp desc

    Do not place RawEventData into public examples until you have established whether it contains tenant, user, prompt, resource or tool-argument data. In production, project only the fields required for the detection and apply the appropriate retention and access controls.

    Create detections for:

    • a previously unseen MCP server;
    • a newly exposed privileged or destructive tool;
    • invocation from an unexpected device, identity or geography;
    • unusual invocation volume;
    • denied calls followed by repeated retries;
    • access outside the approved target scope; and
    • tool calls immediately after new consent or credential creation.

    Step 9: validate the controls

    Use synthetic data and a non-production target for the first exercise.

    Test Expected evidence
    Call without a token 401; no tool execution
    Token for another audience Rejected before tool execution
    Valid identity without the required scope or role 403; denial logged
    Read-only identity calls a write tool Denied outside the model response
    Unapproved remote server Blocked by policy where supported
    Approved server invokes an approved read tool Allowed and logged
    Prompt or tool output requests an unrelated privileged action No privileged action; security event available
    Agent identity disabled or access revoked Subsequent calls fail after control propagation

    Record the timestamp, test identity, server, tool, expected result, actual result and evidence location. A policy screenshot alone does not prove enforcement.

    Step 10: exercise containment

    For a suspected compromised MCP server:

    1. disable the server or remove it from the approved client configuration;
    2. block its remote endpoint where the network control supports it;
    3. disable or restrict the calling workload identity;
    4. revoke exposed credentials and tokens according to the identity type;
    5. preserve endpoint, identity, network and tool-call evidence;
    6. identify downstream systems the tools could reach;
    7. review changes and data access during the exposure window; and
    8. restore access only after ownership, package integrity, permissions and monitoring are revalidated.

    The containment plan needs separate actions for the client identity, the MCP server and the downstream credential. Disabling only one component may leave another access path usable.

    Production checklist

    • Every MCP server has an owner, purpose and review date
    • Local and remote discovery is reconciled with the approved register
    • Every tool is classified by data access and change capability
    • Remote servers require supported OAuth authentication
    • Token audience, tenant, expiry, scope or role are validated before tool execution
    • Production secrets are absent from MCP configuration and source control
    • Trusted and experimental servers do not share credential contexts
    • Write, privileged and destructive tools require controls outside the model
    • Remote policies are tested with allowed and blocked calls
    • Local stdio limitations are documented
    • Tool activity reaches an access-controlled monitoring platform
    • Containment has been exercised with synthetic data

    What the controls do not prove

    An inventory does not prove that every agent is supported by discovery. Entra authentication does not prove that a tool is safe. A network policy does not inspect local stdio servers. Purview and Defender coverage depends on the actual integration path, licensing and telemetry. A successful test does not guarantee that later package or tool-description changes are harmless.

    Keep approval time-bound, review package and publisher changes, and reassess whenever a server adds a tool or gains access to a new data source.

    References