MicrosoftMicrosoft Certified: Multi-Agent AI Solutions Expert2026-102.3 Build and integrate tool ecosystems
Negotiate capabilities before approving tool calls
Completed by the knowledge check
Learning objective
Implement MCP clients that discover tools, authenticate, negotiate invocation capabilities, and manage client-side approval.
Core idea
An MCP client mediates between an agent’s request and a server’s executable operation. For a senior engineer integrating external tools, its responsibility is to establish what the peer supports, what the caller may access, and which specific operation is approved. A reachable server with a useful tool description doesn’t settle any of those questions by itself.
MCP 2026-07-28 uses stateless per-request capability metadata; 2025-11-25 uses an initialization handshake. This lesson distinguishes those paths and uses Agent Framework’s local MCP tools for client-side approval. Foundry’s service-mediated approval remains a separate execution path; see 1.1.9.
See 2.3.3 for server schemas and transport implementation. Here the client uses those interfaces without assuming every advertised capability is permitted for the agent.
How it works
Establish the protocol before discovery
For MCP 2026-07-28, each request carries _meta fields io.modelcontextprotocol/protocolVersion and io.modelcontextprotocol/clientCapabilities. There is no initialization handshake. An optional server/discover call identifies supported versions; otherwise, handle UnsupportedProtocolVersionError by selecting a mutually supported version from its response. A missing required capability produces MissingRequiredClientCapabilityError (-32021) with data.requiredCapabilities; don’t proceed by pretending support.
For MCP 2025-11-25, the client starts with initialize, sending its supported protocolVersion, client information, and capabilities. The server responds with its selected version, server information, and capabilities. If the client can’t support the returned version, it should disconnect rather than continuing with incompatible assumptions.
After successful initialization, send notifications/initialized. Optional protocol features depend on the exchanged capabilities. A server’s tools capability enables tool operations. A client’s sampling, elicitation, or roots capability describes support for those server-to-client interactions; don’t advertise them merely because a server might want them.
These capabilities are protocol abilities, not permissions. Advertising sampling doesn’t give a server unrestricted use of the model, and receiving tools doesn’t authorize every operation. For HTTP requests after negotiation, include MCP-Protocol-Version. If the server established a session, also follow its MCP-Session-Id requirements.
Keep the declared capabilities as narrow as the client implements. Handle requests using the chosen revision instead of advertising unsupported interactions.
Discover the full approved interface
Call tools/list and follow nextCursor until discovery completes. Otherwise, a tool absent from the first page can look unsupported even though the server exposes it. Inspect names, descriptions, input schemas, and optional output schemas before making definitions available to the model.
When the server advertises tools.listChanged, handle notifications/tools/list_changed by refreshing the catalog. Reapply the allowed-tool policy after refreshing. A changed description or added operation shouldn’t inherit approval merely because the same server remains reachable.
In Agent Framework’s Python local MCP integration, both MCPStdioTool and MCPStreamableHTTPTool accept allowed_tools to select the role’s intended subset. Use raw remote tool names or unambiguous prefixed names. If normalization makes a configured name match multiple remote names, the framework raises ToolExecutionException; use an exact raw name or change tool_name_prefix. Treat descriptions, annotations, and results as untrusted input, while the backend still enforces access rights.
Authenticate for the selected transport
For MCP 2025-11-25, the authorization specification applies to HTTP-based transports when authorization is implemented. It says stdio implementations should obtain credentials from the environment instead of following the HTTP OAuth flow. Don’t force a browser authorization redirect into a local pipe or infer that a local process needs no credential controls.
For HTTP authorization, a client must support protected-resource metadata discovery through both the WWW-Authenticate header on a 401 response and well-known metadata locations. The resource metadata identifies authorization servers. Retrieve their metadata and use the advertised supported authorization flow rather than guessing token endpoints.
The specification requires Proof Key for Code Exchange (PKCE) and verification of PKCE support for its authorization-code flow. It also requires the resource parameter in authorization and token requests so the token targets the MCP resource. Send the access token in Authorization: Bearer ... on HTTP requests. The server must validate that the token is intended for it; token passthrough to unrelated downstream services is forbidden.
An HTTP client finds the authorization server through the MCP server’s 401 response and obtains a token that targets that MCP resource.
For MCPStreamableHTTPTool, use static_headers for fixed credentials or header_provider for values derived from each run. During generated calls, header_provider receives host function_invocation_kwargs, not model-supplied tool arguments. Keep credentials out of outbound arguments through fixed headers or a provider that captures credentials in a closure.
In Foundry Agent Service, store authentication in a project connection and reference it with project_connection_id. The documented options include key-based authentication, Microsoft Entra identities, and OAuth identity passthrough; see 0.6 for --auth-type values. On a user’s first call to a Toolbox OAuth MCP in a project, CONSENT_REQUIRED (-32006) supplies a consent URL. Complete consent and retry rather than treating that expected response as a tool execution failure.
Approve a specific operation before it runs
Use MCPStdioTool for a client-managed local process and MCPStreamableHTTPTool for a remote HTTP server. Both Python wrappers support approval_mode listing tools that need approval. For example, list the raw remote name submit_purchase in approval_mode and include both lookup_inventory and submit_purchase in allowed_tools. These names are illustrative application operations, not built-in tools.
Apply the same unambiguous-name rule to approval_mode as to allowed_tools. A normalization collision raises ToolExecutionException; don’t respond by broadening the allowlist or removing approval. Change tool_name_prefix or select exact raw names so the intended operation is identifiable.
For a sensitive call, the host presents the server, tool name, and actual arguments before approving execution. Consent to “complete the task” isn’t approval of every proposed mutation. If the proposal changes, evaluate the changed call; a denial must not trigger another unapproved tool that performs the same mutation.
Foundry service-mediated calls use their own approval request and response items instead of this local wrapper gate. See 1.1.9 for require_approval, the continuation identifiers, and the complete Responses approval flow.
Validate the observation separately
After invocation, inspect protocol errors, tool execution errors, and any structured result schema. A successful network exchange doesn’t prove the business operation succeeded. The tool protocol uses isError: true for execution failures; your integration should preserve that outcome for the agent.
Record tool calls and approvals with enough context to associate the decision with the actual operation. Microsoft’s MCP guidance recommends logging both for auditing. Keep result validation and sensitive-data handling in the client even after approval; consent to invoke doesn’t make all returned text trusted instructions.
Key distinctions and trade-offs
Authentication versus approval: Authentication establishes an accepted caller credential. Approval authorizes a particular proposed invocation in the application’s workflow.
Capabilities versus privileges: Protocol negotiation describes supported interactions. allowed_tools, backend authorization, and approval determine which operations the agent can use.
Direct versus service-mediated execution: A direct client gates its own tools/call. Foundry uses approval request and response items to pause and resume a service-managed call. Local middleware isn’t automatically a gate on service-side execution.
Broader automatic invocation reduces user interruption but increases the work required to justify tool exposure and backend constraints. Require explicit approval when the actual arguments or side effects need a human decision.
Architecture / decision scenario
A purchasing assistant uses Agent Framework’s Python MCPStreamableHTTPTool for a server offering lookup_inventory and submit_purchase. It selects those raw names through allowed_tools and lists submit_purchase in approval_mode. The connection uses the supported 2025-11-25 lifecycle and discovers the remote contracts. A host-controlled header_provider supplies credentials obtained through the server’s documented authorization flow.
Inventory lookup follows the approved read policy. Purchase submission requires the host to display the supplier, item, quantity, and destination for approval before execution. Model-supplied arguments can describe the purchase but cannot set the provider’s authentication headers. Denial ends that proposed purchase; a changed destination needs a changed approval decision.
If the team moves execution to Foundry Agent Service, it stores authentication in the connection referenced by project_connection_id and follows the service approval flow in 1.1.9. For a Toolbox OAuth connection, it handles first-use CONSENT_REQUIRED separately from purchase approval. A completed handshake, valid token, or completed OAuth consent isn’t approval to submit a purchase.
Common exam traps
- Requiring
initializefor a stateless2026-07-28request. - Invoking legacy tools before completing the negotiated lifecycle.
- Treating
capabilitiesas an access-control list. - Reading only the first
tools/listpage. - Reusing a token intended for another resource.
- Letting an ambiguous normalized name select an allowed or approval-gated tool.
- Assuming model arguments can supply
header_providercredentials. - Assuming approval makes returned content trusted instructions.
What to remember
Negotiate the supported protocol, discover the intended tools, and authenticate to the correct resource. For local Agent Framework invocation, use allowed_tools, approval_mode, and host-controlled credentials. Approve the concrete call and validate the resulting observation independently.
Knowledge check
A client sends MCP 2026-07-28 requests to a server supporting that revision. Which mechanism tells the server which revision the client uses and what the client supports?
initialize response followed by notifications/initializedtools/list_meta of every request2026-07-28 uses per-request version and capability metadata without an initialization handshake. The handshake belongs to legacy revisions; credentials and session state do not declare protocol abilities.A legacy server returns nextCursor in tools/list, and later announces a catalog change through its advertised listChanged capability. What should the client do?
An HTTP MCP client has a token issued for an unrelated service. It needs access to a protected MCP resource. Which approach fits the documented authorization flow?
resource parameter targets the token to the MCP resource. A token for another service and an MCP session identifier do not establish access to this endpoint.A generated call includes an access_token argument that differs from the host’s credential. What should supply authentication headers for Agent Framework’s Python MCPStreamableHTTPTool?
access_token argument from the generated callstatic_headers or a header_provider with host-held credentialsheader_provider that reads the call’s tool argumentsaccess_token argument once the user approves the callheader_provider keep authentication under host control. During generated calls, the provider receives the host’s invocation kwargs rather than model-supplied tool arguments, and approving a call approves an operation, not a credential the model proposed.A user approves a purchase submission to one destination. The assistant then proposes a different destination for the same purchase. What should the host do before invocation?
References
- Microsoft, Using MCP tools
- Model Context Protocol, Versioning and compatibility
- Model Context Protocol, Basic protocol
- Model Context Protocol, Lifecycle
- Model Context Protocol, Authorization
- Model Context Protocol, Tools
- Model Context Protocol, Transports
- Microsoft, Connect agents to MCP server endpoints