Agent 365 SDK, observability, and network controls

OpenTelemetry spans with agent context, MCP tooling extensions, and Global Secure Access for agents.

🟦 Module 10 13 min read Not started

Why this matters

Everything up to this lesson has been about identity and policy. This lesson is about runtime: how you actually instrument an agent so its behaviour is observable, its tool calls are governed, its notifications flow through Microsoft 365 apps, and its network egress is filtered. The Agent 365 SDK is Microsoft's answer, delivered as a set of Python / .NET / JavaScript packages you drop into whatever agent framework you use (Microsoft Agent Framework, OpenAI Agents SDK, LangChain, Semantic Kernel, Azure AI Foundry).

Cross-ref: Module 4 (MCP authorization) covers MCP itself; this lesson shows how Agent 365 SDK's tooling packages plug MCP tools into your agent under admin control. Module 7 (Audit + provenance) is the vendor-neutral audit design; this lesson is Microsoft's OpenTelemetry-based implementation.

Learning objectives

  1. Understand what Agent 365 SDK is (and is not — it's not another agent framework).
  2. Map the SDK's five concern areas to Python / .NET / JavaScript packages.
  3. Add OpenTelemetry tracing to any agent framework via the correct extension package.
  4. Wire MCP tool registration through the SDK's governed catalogue.
  5. Enable Global Secure Access for Copilot Studio agent egress.

1. What the SDK is — and what it isn't

The Agent 365 SDK does not create or host agents. It enhances agents you've already built with:

  • Entra-backed identity (via the sidecar we saw in Lesson 10.3).
  • Notifications (Teams, Outlook, Word comments, emails) — receive and respond as a first-class Microsoft 365 participant.
  • Observability via OpenTelemetry — auditable, traceable spans for every agent invocation, tool execution, and LLM inference.
  • Governed MCP tool access — the agent invokes MCP servers listed in the enterprise catalogue, under admin control.
  • Enforcement of an IT-approved blueprint — every instance inherits compliance / governance / security policies.

It's not to be confused with two other similarly-named things:

  • Microsoft Agent Framework — a full agent runtime (like LangChain). The Agent 365 SDK wraps agents built with it.
  • Microsoft 365 Agents SDK — for building agents that host on Teams. Agent 365 SDK complements it (adds governance) rather than replacing.

Architecture stack:

+-----------------------------------------+
| Enterprise Capabilities                 |   <-- Agent 365 SDK
|  (identity, notifications, observability, |
|   governed MCP tooling)                 |
+-----------------------------------------+
| Agent Logic                             |   <-- your code
|  (prompts, workflows, reasoning)        |
+-----------------------------------------+
| LLM Orchestrator Runtime                |   <-- your framework
|  (Agent Framework / OpenAI SDK /        |
|   LangChain / Semantic Kernel /         |
|   Azure AI Foundry / custom)            |
+-----------------------------------------+

The SDK is a layer above whatever framework you already use.


2. Package matrix — Python (JavaScript / .NET analogues exist)

Search PyPI for the full list; these are the mainstays.

PackageConcern
microsoft-agents-a365-runtimeCore runtime — Power Platform API discovery, environment configuration, authentication scope resolution
microsoft-agents-a365-notificationsNotification / messaging extensions — Teams / Outlook / Word comments / emails routing and lifecycle
microsoft-agents-a365-observability-coreOpenTelemetry-based structured spans for agent invocation, tool execution, LLM inference
microsoft-agents-a365-observability-extensions-agent-frameworkOTel instrumentation for Microsoft Agent Framework
microsoft-agents-a365-observability-extensions-openaiOTel instrumentation for OpenAI Agents SDK
microsoft-agents-a365-observability-extensions-langchainOTel instrumentation for LangChain
microsoft-agents-a365-observability-extensions-semantic-kernelOTel instrumentation for Semantic Kernel
microsoft-agents-a365-toolingCore MCP tool-server management — discovery, registration
microsoft-agents-a365-tooling-extensions-agentframeworkMCP tool registration for Agent Framework agents
microsoft-agents-a365-tooling-extensions-openaiMCP tool registration for OpenAI Agents SDK
microsoft-agents-a365-tooling-extensions-semantickernelMCP tool registration for Semantic Kernel
microsoft-agents-a365-tooling-extensions-azureaifoundryMCP tool registration for Azure AI Foundry

Rule of thumb: pick runtime + notifications + observability-core + the framework-specific extensions for observability and tooling.

Node / .NET packages mirror the same shape. See the Agent 365 SDK overview for the current registry.


3. Observability — OpenTelemetry-native

Every agent operation the SDK sees generates a span with agent / tool / LLM context. These spans flow into any OTel-compatible backend:

  • Azure Monitor / Application Insights (natural default).
  • Grafana Tempo / Jaeger / Splunk / New Relic / Datadog — any OTel-compatible.

3.1 Minimum-viable Python wiring

python
# uv add microsoft-agents-a365-runtime microsoft-agents-a365-observability-core \
#        microsoft-agents-a365-observability-extensions-langchain \
#        opentelemetry-sdk opentelemetry-exporter-otlp

from microsoft.agents.a365.runtime import AgentRuntime
from microsoft.agents.a365.observability import init_observability
from microsoft.agents.a365.observability.extensions.langchain import instrument_langchain
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter

runtime = AgentRuntime.from_env()  # discovers Power Platform + agent identity from env
init_observability(
    service_name="agent.crm-helpdesk-v2",
    exporters=[OTLPSpanExporter(endpoint="https://otel-collector:4317")],
    resource_attrs={
        "agent.identity_oid": runtime.agent_identity.oid,
        "agent.blueprint_id": runtime.blueprint_id,
        "agent.environment": "prod",
        "agent.sponsor": "alice@mtn.co.za",
    },
)
instrument_langchain()   # auto-instruments LangChain chains / agents / tools

# ... your LangChain agent code — every invocation now emits OTel spans with agent context ...

Result — a span tree per user request:

agent.invoke  (10.2s)
├── llm.inference "claude-opus-4.7"  (2.1s)
│   ├── input: 4,231 tokens
│   └── output: 812 tokens
├── tool.call "mcp.mail.search"  (185 ms)
│   ├── mcp.server: "https://m365-mail-mcp.mtn.co.za"
│   ├── mcp.tool: "search"
│   └── auth.entra.identity: "agent.crm-helpdesk-v2"
├── llm.inference "claude-opus-4.7"  (1.4s)
└── tool.call "mcp.ticket.create"  (620 ms)
    └── ...

Every span is stamped with the agent identity, blueprint, sponsor, environment. Perfect for cost attribution, incident forensics, and audit correlation to sign-in / audit logs.

3.2 Framework mapping — pick your extension

Your frameworkObservability package
Microsoft Agent Frameworkmicrosoft-agents-a365-observability-extensions-agent-framework
OpenAI Agents SDKmicrosoft-agents-a365-observability-extensions-openai
LangChainmicrosoft-agents-a365-observability-extensions-langchain
Semantic Kernelmicrosoft-agents-a365-observability-extensions-semantic-kernel
Azure AI FoundryFoundry runtime auto-instruments; no separate extension needed
CustomUse microsoft-agents-a365-observability-core directly and emit spans yourself

3.3 What the auto-instrumentation covers

  • Agent invocation — user turn boundaries.
  • LLM inference — model, tokens in/out, latency, tool-call proposals.
  • Tool call — tool name, args (hashed), duration, outcome, MCP server / auth identity if applicable.
  • Error events — exceptions with framework stack traces.

Combined with sign-in + audit logs, you get the complete Module 7 picture from a Microsoft-native stack.


4. Tooling — governed MCP via the SDK

Cross-ref: Module 4 covers the MCP auth spec. Agent 365 SDK adds governed catalogue semantics on top.

4.1 The idea

Admins publish a list of approved MCP servers to the tenant. Agents built with the SDK see only those servers — they can't call an arbitrary MCP URL that a prompt-injected instruction tries to sneak in.

4.2 Registration pattern (LangChain example)

python
# uv add microsoft-agents-a365-tooling microsoft-agents-a365-tooling-extensions-agentframework
from microsoft.agents.a365.tooling import ToolCatalog
from microsoft.agents.a365.tooling.extensions.langchain import register_mcp_tools_langchain

catalog = ToolCatalog.for_agent(runtime.agent_identity.oid)
# fetches the approved MCP servers this agent's blueprint has access to

tools = register_mcp_tools_langchain(langchain_agent, catalog)

Under the hood the tool registration:

  1. Resolves the approved MCP servers for this agent identity from the tenant catalogue.
  2. For each server, invokes the sidecar (Lesson 10.3) to acquire a token targeted at that server's audience.
  3. Registers the MCP server's tools as LangChain tools with auto-refresh on expiry.
  4. Wraps every tool call in an OTel span with mcp.server + mcp.tool attributes.

Any prompt-injected attempt to call mcp.evil-tool at https://attacker.example.com gets hard-refused because the tool isn't in the registered catalogue. This is the vendor-neutral MCP whitelist pattern from Lesson 4.2, implemented natively.

4.3 Admin-side: publishing MCP servers to the catalogue

Admins register MCP servers in the M365 admin surface with:

  • Server URL + audience.
  • Description of what tools it exposes.
  • Which agent identity blueprints are allowed to use it.
  • Which scopes each caller can request.

Admin change → agents pick it up on next ToolCatalog.for_agent() call (or via a webhook if you enable one).


5. Notifications — agents as first-class M365 participants

The microsoft-agents-a365-notifications package lets agents:

  • Receive notifications when @mentioned in Teams, Outlook, or Word comments.
  • Send notifications back through the same channels (as themselves, or via their agent user account if one exists).
  • Handle lifecycle events — sponsor changed, licence revoked, tenant policy update.

5.1 Minimal example — reacting to a Teams @mention

python
from microsoft.agents.a365.notifications import NotificationRouter

router = NotificationRouter.from_env()

@router.on_mention(channel="teams")
async def on_teams_mention(event):
    text = event.message.text
    await router.reply(event, f"Working on it: {text[:50]}...")
    # ... run agent workflow ...
    await router.reply(event, "Done. See ticket TKT-1029.")

router.serve()  # long-poll or webhook, depending on deployment

The router uses the agent identity (or its user account, for user-shaped replies) for auth; no bespoke Teams bot registration required.


6. Global Secure Access — network controls for agents

Even with all the identity + observability in place, agents still make outbound HTTP calls to third-party APIs, model endpoints, custom connectors, MCP servers. Any of those can be:

  • Attacker-controlled (prompt-injected redirection).
  • Data-exfiltration channels.
  • Untrusted content sources.

Global Secure Access (GSA) — Microsoft's Secure Web Gateway — extends to agents. In Power Platform admin center you enable agent traffic forwarding per environment (or environment group), and every outbound call from Copilot Studio agents flows through GSA's globally-distributed proxy where you can apply:

  • Web content filtering — allow only approved domains.
  • Threat intelligence filtering — block known-bad IPs / URLs / TLD reputations.
  • Network file filtering — block suspicious file transfers.
  • TLS inspection — inspect payloads for DLP.

Applies to multiple agent traffic types:

  • HTTP Node traffic (from Copilot Studio flows).
  • Custom connectors.
  • MCP Server Connector traffic.

Policies configured in the baseline profile in GSA apply tenant-wide. Ideal pattern:

  • Allow-list your MCP catalogue and known Microsoft / partner endpoints.
  • Block social media / consumer-cloud storage.
  • Alert on any request to unusual TLDs.
  • Feed GSA logs into Sentinel next to your Entra sign-in + Purview activity.

6.1 Current scope

As of 2026-06, GSA agent forwarding covers Copilot Studio agents. Custom-code agents (Agent Framework, LangChain, OpenAI Agents SDK, Bedrock) running in Azure Container Apps / AKS / non-Azure should route their outbound egress via the Entra Internet Access client or a per-namespace egress policy. Roadmap: coverage will extend as SDK-hosted agents mature.


7. Reference pipeline — from user request to observability + audit

Take a full turn for the CRM helpdesk agent:

1. User @mentions helpdesk-bot in Teams
   → Notifications router receives event (auth: agent user account token)

2. Agent starts LangChain workflow
   → OTel: root span agent.invoke
   → Auth: sidecar issues OBO token for user's Mail.Read

3. Agent calls MCP tool "mail.search"
   → ToolCatalog verifies the MCP server is approved
   → OTel: span tool.call with mcp.server + mcp.tool + hashed args
   → GSA: outbound HTTP goes through GSA proxy, allowed per policy

4. LLM inference generates ticket draft
   → OTel: span llm.inference with tokens, model, latency

5. Agent calls MCP tool "ticket.create"
   → ToolCatalog verifies + tokens acquired
   → OTel span; audit log entry appears in Purview

6. Agent replies via Notifications router
   → Reply auth: agent user account (so it appears as helpdesk-bot in Teams)
   → OTel span notification.send

7. All spans exported to Azure Monitor / Splunk
   Sign-in logs: token acquisitions for user, agent identity, agent user account
   Audit logs: Purview records the mail search + ticket create
   Risk signals: ID Protection watches for anomalies

Every hop has: identity (Entra), observability (OTel), audit (Purview / Entra logs), network control (GSA). This is the complete Microsoft-native picture.


8. Common pitfalls

  1. Installing the wrong observability extension. Agent Framework's extension doesn't instrument LangChain. Match extension to framework.
  2. Manually calling MCP servers with httpx — bypasses the ToolCatalog and its governance. Always go through register_mcp_tools_*.
  3. Emitting all args uncensored to OTel. Args often contain PII. Hash + selectively redact (see Module 7 lesson 7.1).
  4. Exposing the sidecar port outside the pod. It's localhost:7000 — never route it to a load balancer.
  5. Assuming GSA covers custom-code agents automatically. It covers Copilot Studio agents. Custom agents need their egress routed explicitly.
  6. Not stamping resource attributes on OTel spans. Without agent.identity_oid on every span, correlating spans to sign-in / audit logs later is painful.
  7. Ignoring notification lifecycle events. Missing the sponsor-change event means the agent keeps quoting a departed sponsor to end users.
  8. Running two competing agent frameworks in the same process — Semantic Kernel and LangChain both auto-instrument globally, and their spans overlap. Pick one.

9. Hands-on lab (3 h)

Prereqs: agent identity from Lesson 10.2, sidecar from Lesson 10.3, Azure Monitor / a local OTel collector.

  1. Create a minimal LangChain agent that answers questions with a single tool ("search the web via a whitelisted MCP server").
  2. Install the four SDK packages (runtime, observability-core, observability-extensions-langchain, tooling-extensions-agentframework? — pick the LangChain tool ext).
  3. Wire init_observability and instrument_langchain. Run a test question; verify spans appear in your OTel backend with agent identity + blueprint attributes.
  4. Publish a test MCP server to the tenant catalogue (mock a simple one with FastMCP). Register it for your test agent's blueprint.
  5. Reload the agent; verify the tool now appears via ToolCatalog.for_agent(). Trigger the tool; check the OTel span for mcp.server, mcp.tool.
  6. Attempt to call an unregistered MCP server directly — verify the SDK refuses.
  7. Enable GSA traffic forwarding for a Copilot Studio environment. Deploy a Copilot Studio agent that calls a custom connector. Add a GSA web-filter rule blocking bad.example.com. Verify the agent's call is refused with a GSA-branded error.
  8. Add a notifications router; @mention the agent in Teams; verify it replies as the agent user account (Lesson 10.2 setup).

10. Self-check

  1. What does the Agent 365 SDK add on top of your existing agent framework?
  2. Name the four framework-specific observability extension packages.
  3. Why does going through ToolCatalog.for_agent() matter for security?
  4. Which channels does the notifications router cover?
  5. Which agent kinds does Global Secure Access currently cover?
  6. Which resource attributes should every OTel span carry to be useful for audit?

11. References

Sign in to save your progress and earn badges.