Skip to content

What the policy touches

Section 3 · From docs/MCP_PRIVACY.md on GitHub

3.1 Data paths

The layer (cloudg/mcp/layer.py) runs the caller's output pipeline over everything that carries data out, and the input pipeline over everything that carries data in. Every adapter (native, mcp SDK, fastmcp) goes through the layer, so the transport makes no difference.

Direction Path What is transformed
out Tool result returned as a plain value (the catalog's case) The JSON-ready value, as structuredContent. The text content is rendered from the transformed value.
out Tool result returned as a ToolResult structured, each TextContent.text, the text of each EmbeddedResource holding TextResourceContents, each ResourceLink (uri, name, title, description), and result.meta as a whole.
out Resource links attached through ctx.links uri, name, title, description.
out Tool errors The message text of every isError result (handler exceptions, NotFoundError, access denials, rate limits, bad arguments) and its _meta["cloudg/error_data"].
out Resource reads JSON values and plain strings; for handlers that return TextResourceContents, each item's text.
out Prompts Each message's TextContent.text, the text of an EmbeddedResource holding TextResourceContents, and ResourceLink fields.
out Completions Each suggested value, wrapped as {<argument name>: value} before the pipeline runs so that key rules recognise it (a bare list of strings has no keys, and names are only caught by key rules).
in Tool arguments The whole arguments object, recursively.
in Resource template variables The variables parsed from the URI (so cloudg://assets/<pseudonymised ARN> resolves).
in Prompt arguments All arguments.
in Completions The partial value and the context arguments.

What is not transformed:

  • Binary resource contents (BlobResourceContents) and image content.
  • Tool, resource and prompt definitions: names, descriptions, input schemas, annotations, and the server instructions. These come from code, never from cloud data.
  • The prompt result's description field.
  • Layer bookkeeping in _meta: cloudg/transforms (added after the pipeline ran), cloudg/duration_ms, cloudg/error_code, cloudg/cache, cloudg/retries.
  • Keys the redactor skips by default: _meta, _annotations, cursor, next_cursor.

3.2 outputSchema is withheld

Masking, dropping and projection change the shape of structuredContent, and MCP clients reject a result that does not validate against the tool's advertised outputSchema. CloudGMCPLayer.tools_wire() therefore leaves outputSchema out of a tool's tools/list entry whenever that caller's output pipeline for the tool is non-empty. In practice the schema is advertised only under open, or for a tool whose transform_hints skip every transform (preview_transform). Measured on the catalog, get_asset carries an outputSchema under open and none under any other built-in profile.

3.3 The life of a tool call

  1. get_tool(name, principal) looks the tool up. If the policy denies it and hide_denied is true, the call fails with Unknown tool: <name> (a protocol error, code -32602), exactly as if the tool did not exist. The policy records the attempt as a not_found decision (section 15.1).
  2. The middleware chain runs, outermost first (with cloudg mcp serve: the audit log, metrics, the concurrency limit and the cache, each when configured). Resource reads, prompts and completions go through the same chain.
  3. policy.check_call() decides access, applies rate limits and records the decision (section 7, 9, 15). A denial or rate limit becomes an isError result.
  4. The input pipeline runs over the arguments: secret guard first, then the depseudonymiser. If it refuses the call, the decision recorded in step 3 is changed to rejected.
  5. Arguments are validated against the handler signature.
  6. The handler runs (sync handlers in a worker thread) under the tool's timeout.
  7. The output pipeline runs over the result. The text rendering is capped at max_output_chars (200,000 by default) with ... [truncated by cloudg mcp layer].
  8. Attached resource links are transformed and appended.
  9. The transform report is attached as _meta["cloudg/transforms"].

Resource reads and prompts follow the same order, except that a denied resource or prompt raises instead of returning an isError result.

When cloudg mcp serve stops, it calls policy.save_vault() so that pseudonyms issued during the session are written to the vault file, if the policy has one (section 13.5).