Skip to content

[dotnet-port-api] Add hosted MCP tool approval mode - #1155

Open
PratikDhanave (PratikDhanave) wants to merge 1 commit into
microsoft:mainfrom
PratikDhanaveFork:fix/mcp-approval-mode
Open

PratikDhanave (PratikDhanave) wants to merge 1 commit into
microsoft:mainfrom
PratikDhanaveFork:fix/mcp-approval-mode

Conversation

@PratikDhanave

Copy link
Copy Markdown
Contributor

Implements #1138.

hostedtool.MCPServer had no approval-mode control, so every hosted MCP tool call required an mcp_approval_request round-trip — the Responses API defaults require_approval to "always" when omitted, and there was no way to request auto-approval.

Change

  • Add MCPApprovalMode (MCPApprovalAlways / MCPApprovalNever) and an ApprovalMode field on hostedtool.MCPServer, mirroring the .NET HostedMcpServerTool.ApprovalMode.
  • Forward it as require_approval on the OpenAI Responses request. The zero value leaves the provider default (always), so existing behavior is unchanged.

Scoped to the two simple settings (always/never); the per-tool approval filter form can follow separately.

Test

  • TestResponsesMCPServerApprovalMode: never"require_approval":"never", always"always", unset → field omitted. The never case fails before the change (field absent), passes after.

hostedtool.MCPServer had no way to control approval, so every hosted MCP tool
call required an mcp_approval_request round-trip (the Responses API defaults
require_approval to "always"). Add an ApprovalMode field
(MCPApprovalAlways/MCPApprovalNever) mirroring .NET HostedMcpServerTool.
ApprovalMode, and forward it as require_approval on the Responses request. The
zero value preserves the provider default.

Implements microsoft#1138.
Copilot AI lite review requested due to automatic review settings September 22, 2026 05:17
@github-actions github-actions Bot added area:provider Changes files in the provider area area:provider/openai Changes files in the provider / openai area area:tool Changes files in the tool area size:medium At most 100 changed lines across at most 5 files labels Sep 22, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The implementation is backward-compatible and the new behavior is covered by focused tests.

Review effort: Lite
Findings: None

What changed in this PR

Adds hosted MCP approval-mode control and forwards it through the OpenAI Responses provider while preserving existing defaults.

Changes:

  • Adds MCPApprovalAlways and MCPApprovalNever.
  • Serializes non-zero approval modes as require_approval.
  • Adds coverage for always, never, and unset modes.
File Description
tool/​hostedtool/​hostedtool.go Defines the approval-mode API.
provider/​openaiprovider/​responses.go Forwards approval mode to Responses requests.
provider/​openaiprovider/​responses_test.go Tests request serialization behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions github-actions Bot added kind:code Changes production behavior or code kind:tests Changes tests, fixtures, or test infrastructure labels Sep 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Scope: public API, user-visible behavior

Changed Go contract: hostedtool.MCPServer.ApprovalMode (new field) and new exported type hostedtool.MCPApprovalMode with constants MCPApprovalAlways / MCPApprovalNever; provider/openaiprovider now forwards it as require_approval on the OpenAI Responses request when set.

Upstream evidence reviewed:

  • .NET: HostedMcpServerTool.ApprovalMode (nullable HostedMcpServerToolApprovalMode), referenced via dotnet/src/Microsoft.Agents.AI.Declarative/Extensions/McpServerToolExtensions.cs and McpServerToolApprovalModeExtensions.cs, and exercised in dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/OpenAIResponsesIntegrationTests.cs (CreateResponse_WithHostedMcpTool_ForwardsToolToResponsesProviderAsync) and the ResponseAgent_Hosted_MCP sample (dotnet/samples/02-agents/ModelContextProtocol/ResponseAgent_Hosted_MCP/Program.cs), which sets AlwaysRequire/NeverRequire explicitly.
  • Python: OpenAIChatClient.get_mcp_tool(approval_mode=...) in python/packages/openai/agent_framework_openai/_chat_client.py (lines ~1447-1533), which maps "always_require"/"never_require" strings to require_approval: "always"/"never", or a dict (always_require_approval/never_require_approval tool-name lists) to the specific-tool require_approval object form.

Result: aligned (with a disclosed, intentional scope reduction)

Both upstream implementations support three forms: always/never for all tools, and a per-tool "specific" filter (.NET HostedMcpServerToolApprovalMode.RequireSpecific(...), Python approval_mode dict with always_require_approval/never_require_approval tool-name lists). This PR only ports the always/never forms and explicitly calls that out in the description ("Scoped to the two simple settings... the per-tool approval filter form can follow separately"), leaving hostedtool.MCPServer.ApprovalMode as a string-based MCPApprovalMode rather than a richer type that could later add a specific-tools variant. This is a reasonable incremental step rather than a silent gap:

  • Naming (MCPApprovalMode, MCPApprovalAlways/MCPApprovalNever) is a faithful, idiomatic Go rendering of HostedMcpServerToolApprovalMode.AlwaysRequire/NeverRequire.
  • Default behavior matches: the Go zero value ("") omits require_approval entirely, same as .NET's nullable ApprovalMode being null and Python's approval_mode=None — all three leave the Responses API default ("always") in effect, so no default/behavior divergence is introduced.
  • No feature-gating concern: this isn't a case of upstream shipping a default-disabled option while Go enables new behavior unconditionally — the new field is purely opt-in and additive.

One suggestion for a Go-side follow-up (not a blocking parity issue): since MCPApprovalMode is a plain string type, adding the specific-tools form later (e.g. a struct/interface value) may require a breaking field-type change. Worth keeping in mind when the per-tool filter form referenced in issue #1138 is implemented, to avoid an awkward migration.

No examples/ changes accompany this PR; none of the linked .NET/Python samples' scenario coverage is otherwise affected.

Generated by Go API Consistency Review Agent · copilot · auto · 58.5 AIC · ⌖ 5.11 AIC · ⊞ 9.2K ·

@github-actions github-actions Bot added the public-api-change Pull Request changes public APIs label Sep 22, 2026
Headers map[string]string
// ApprovalMode controls whether calls to this MCP server require approval.
// The zero value leaves the provider default (which, for the OpenAI Responses
// API, requires approval for every call). Mirrors the .NET

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't mention .net in public docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:provider/openai Changes files in the provider / openai area area:provider Changes files in the provider area area:tool Changes files in the tool area kind:code Changes production behavior or code kind:tests Changes tests, fixtures, or test infrastructure public-api-change Pull Request changes public APIs size:medium At most 100 changed lines across at most 5 files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants