SPB Git forge

spb/doc-api

Public
2commits 1branches 0releases
15.7 MBsize
maindefault branch
13 days agolast push
Python 88.3% TypeScript 7.6% Shell 4.1%
11.8 KB

# Tool and MCP security

Status: DOCUMENTED (xAI mcp tool LIVE_VERIFIED against a public MCP server on 2026-09-19 — require_approval: "never" silently accepted, no approval item ever produced; Gemini mcpServers on generateContent UNVERIFIED) Sources: https://developers.openai.com/api/docs/guides/tools-connectors-mcp (Approvals, Filtering tools, Authentication, Risks and safety) · https://developers.openai.com/api/docs/guides/secure-mcp-tunnels · https://platform.claude.com/docs/en/agents-and-tools/mcp-connector · https://platform.claude.com/docs/en/agents-and-tools/remote-mcp-servers · https://platform.claude.com/docs/en/api/messages · xAI: https://docs.x.ai/developers/tools/remote-mcp (server_url, server_label, allowed_tools, authorization, headers; "require_approval, connector_id not supported"), https://docs.x.ai/developers/tools/overview, https://docs.x.ai/developers/tools/function-calling, https://docs.x.ai/developers/tools/advanced-usage (max_turns, parallel_tool_calls), sources/xai/openapi/openapi.json (ModelTool mcp variant) · Gemini: https://ai.google.dev/gemini-api/docs/function-calling (#model-context-protocol-mcp, toolConfig.functionCallingConfig), https://ai.google.dev/api/generate-content (#Tool mcpServers[], #McpServer, #StreamableHttpTransport, #FunctionCallingConfig VALIDATED), https://ai.google.dev/api/interactions (mcp_server{name, url, headers, allowed_tools}), python-genai / js-genai READMEs (mcpToTool, automatic_function_calling.maximum_remote_calls) Last verified: 2026-09-19

# Two very different trust models

Client (function) tools Remote MCP / connectors
Who executes your code — the model only proposes name + arguments (Gemini: functionCall.args object; xAI/OpenAI: JSON string) the provider's infrastructure calls a third-party server; results flow back into the model without touching your code — OpenAI mcp, Anthropic mcp_servers, xAI mcp, Gemini tools[].mcpServers / Interactions mcp_server. Exception: Gemini's documented MCP path is SDK-side — the MCP client runs in your process and the wire only sees ordinary function calls
What can go wrong your executor trusts model arguments (injection into shell/SQL/paths) data you send is shared with a third party; the server can return injections; tool behaviour can change silently; your bearer tokens are forwarded by the provider (OpenAI authorization, Anthropic authorization_token, xAI authorization/headers, Gemini headers)
Provider controls schema strict (OpenAI/Anthropic; xAI implicit), tool_choice (Gemini functionCallingConfig.mode incl. VALIDATED), parallel_tool_calls / disable_parallel_tool_use OpenAI require_approval, allowed_tools, authorization; Anthropic tool_configuration.{enabled, allowed_tools}, https-only; xAI allowed_tools only (no approval flow); Gemini SDK automatic_function_calling.disable / maximum_remote_calls, Interactions allowed_tools

# xAI Responses — {"type":"mcp", …} tool

Field Security meaning
server_url (required; Streamable HTTP or SSE) · server_label (required; prefixes tool names in usage) · server_description identify the server; only trusted servers — xAI executes the call and injects the result into the model inside the same request
allowed_tools string[]; empty = every tool the server lists is injected into context (docs). Always set it
authorization · headers bearer token / extra headers forwarded to the MCP server by xAI: scope minimally, rotate, never reuse your xAI key here
require_approval, connector_id docs: not supported; live: require_approval: "never" was silently accepted. There is no mcp_approval_request item — every listed tool can run without a human step. Gate side-effecting tools by not allowlisting them (or expose them as client function tools you execute)
defer_loading alpha, 403
Output mcp_call {name, server_label, arguments, output, error} in output[]; output always present (no include needed) — treat as untrusted text (docs/tools/xai/mcp.md)
Also usable inside Batch and Speech-to-Speech requests — same trust model applies to voice agents; bound the agentic loop with max_turns

# Gemini — SDK-side MCP vs server-side mcpServers

  • SDK-side (documented, experimental): config.tools=[mcp_session] (Python) / mcpToTool(client) (JS). The SDK lists the server's tools, converts them to functionDeclarations, and on each functionCall calls the MCP server from your process (automatic_function_calling, default maximum_remote_calls 10). Credentials never reach Google; the injection surface is the tool list/descriptions and results (same as any client tool). Disable AFC (automatic_function_calling.disable=True) to inspect calls before execution; tools only (no MCP resources/prompts); the Live API has no automatic tool handling.
  • Server-side tools[].mcpServers[]{name, streamableHttpTransport{url, headers, timeout, sseReadTimeout, terminateOnClose}}: present in the REST reference and discovery only; headers (your tokens) would be forwarded from Google's side; UNVERIFIED on generateContent in this atlas — do not rely on it. The Interactions API documents tools:[{"type":"mcp_server","name","url","headers","allowed_tools"}] (Streamable HTTP only, names without -); set allowed_tools, use HTTPS, and remember Interactions store state by default (store: true).
  • Function calling controls: toolConfig.functionCallingConfig.mode AUTO | ANY | NONE | VALIDATED (+ allowedFunctionNames — a per-request tool allowlist); reset ANY to AUTO after the forced turn or the model calls forever; parametersJsonSchema for plain JSON Schema; behavior: NON_BLOCKING is Live-only.
  • Gemini 3 thought signatures: replay the model turn verbatim; a tampered signature → 400 "Corrupted thought signature." (integrity check on your side of the loop — do not "fix" histories by hand).

# OpenAI Responses — {"type":"mcp", …} tool

Field Security meaning
server_label, server_url or connector_id identify the server; only connect to servers you trust ("It is very important that developers trust any remote MCP server they use")
allowed_tools array of tool names the model may call — deny-by-default filtering at list time
require_approval "always" (default), "never", or { "never": {"tool_names":[…]} } — with approvals, the model emits an mcp_approval_request output item; you reply with `{"type":"mcp_approval_response","approval_request_id":…,"approve":true
authorization OAuth access token forwarded to the server. Documented behaviour: OpenAI does not store it, and it is not logged in stored responses — but you must scope it minimally and rotate it
server_description free text seen by the model; keep it factual
Logging with store: true (default), data sent to MCP servers is retained 30 days unless ZDR — the docs recommend logging shared data on your side and reviewing it
ZDR / data residency MCP is compatible, but data leaving to the MCP server is governed by that server's policies — your responsibility

Secure MCP Tunnels (secure-mcp-tunnels.md) let you expose a private MCP server to OpenAI without opening it to the Internet.

# Anthropic Messages — MCP connector (beta)

json
"mcp_servers": [{
  "type": "url", "url": "https://mcp.example.com/sse", "name": "example",
  "authorization_token": "<oauth access token>",
  "tool_configuration": {"enabled": true, "allowed_tools": ["read_issue", "search"]}
}]

Header anthropic-beta: mcp-client-2025-11-20 (legacy mcp-client-2025-04-04 still accepted). Rules from the docs: url must start with https://; OAuth tokens are obtained by you (the API consumer handles the OAuth flow — the MCP Inspector "Quick OAuth Flow" is the documented helper) and passed per request; allowed_tools restricts what the model can call; enabled: false disables a server without removing it. Results arrive as mcp_tool_use / mcp_tool_result blocks (is_error on failure). There is no server-side approval flow equivalent to OpenAI's require_approval — gate side-effecting MCP tools by not allowlisting them, or route them as client tools you execute yourself.

# Client (function) tools — all four providers

  • Schema strictness: OpenAI tools[].strict: true; Anthropic tools[].strict: true; xAI: tool schemas are always strictly enforced (the strict flag is accepted and ignored) and additionalProperties defaults to false; Gemini mode: VALIDATED validates calls against the declaration, otherwise best-effort. Strictness guarantees shape, not safety — a valid {"path": "../../etc/passwd"} is still valid.
  • Tool choice: force or forbid tools per request (tool_choice: "none" / {type:"none"} / Gemini mode: NONE) when reading untrusted content; per-request allowlists via OpenAI/xAI {type:"function", name} or Gemini allowedFunctionNames.
  • Parallel calls: OpenAI/xAI parallel_tool_calls: false, Anthropic disable_parallel_tool_use: true when tools have ordering-dependent side effects; Gemini parallel calls arrive as several functionCall parts — answer all of them in one Content, and note only the first carries a thoughtSignature.
  • Agentic loop bounds: xAI max_turns (server-side tools run inside one request — a runaway loop is billed per call: web_search/x_search/code_interpreter $5/1k), Gemini SDK maximum_remote_calls, your own max_rounds in the shared tool loop.
  • Anthropic programmatic tool calling: allowed_callers: ["code_execution_20250825"] — decide explicitly whether a tool may be invoked from generated code. Gemini 3 "tool combination" similarly lets server tools and your functions interleave (includeServerSideToolInvocations).
  • Descriptions are part of your prompt: keep them precise; never embed secrets (API URLs with tokens) in descriptions — on xAI the MCP server_description is also model-visible.
  • Validate in your executor (schema-validation.md, command-and-path-injection.md) and return errors with is_error: true (Anthropic) / explicit status text (OpenAI, xAI) / {"error": …} object (Gemini functionResponse.response) (untrusted-tool-outputs.md).

# Checklist

  • Every MCP server is inventoried with owner, URL, auth scope, and reviewed tool list.
  • OpenAI: allowed_tools set; require_approval left at always except for reviewed read-only tools; approval UI shows the exact arguments.
  • Anthropic: tool_configuration.allowed_tools set; https URLs only; beta header pinned; side-effecting MCP tools excluded or executed client-side with a human gate.
  • xAI: allowed_tools always set (empty = everything); only read-only tools on remote servers because there is no approval flow; authorization/headers scoped to that server; max_turns bounded.
  • Gemini: prefer SDK-side MCP (credentials stay local); disable automatic function calling when a human must approve; Interactions mcp_server.allowed_tools set; server-side mcpServers on generateContent not used until verified.
  • OAuth tokens for MCP scoped minimally, short-lived, rotated; never logged; never a provider API key.
  • Data sent to MCP servers logged on your side (per OpenAI recommendation) and reviewed periodically; xAI/Gemini MCP outputs treated as untrusted text.
  • Tool descriptions and lists pinned; alert on change.
  • Client tools: strict schemas (VALIDATED on Gemini) + executor-side validation + idempotency per call id.
  • tool_choice: none / mode: NONE (or no tools) when the request's only job is to read untrusted content.