From f211a75baf6adfcaad3c9c5e3750a832ceac839d Mon Sep 17 00:00:00 2001 From: Wils Dawson Date: Thu, 24 Sep 2026 12:59:16 -0700 Subject: [PATCH 1/4] feat(logic_extensions/http): post hooks inspect and override MCP content A remote MCP server's result can carry content blocks alongside its structured result, and MCP clients receive that text. A post hook that sees only `output` cannot redact or scan it. Add optional `content` to PostHookRequest and PostHookOverride, as MCP content blocks in wire shape. An absent override forwards the request's content unchanged, the same as `output`. The fields are additive and optional, so hook servers that ignore them keep working. Bump the contract to 1.2.0-beta. Co-Authored-By: Claude Opus 5.5 (1M context) --- logic_extensions/http/1.0/schema.yaml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/logic_extensions/http/1.0/schema.yaml b/logic_extensions/http/1.0/schema.yaml index 7592ce1..54a29ce 100644 --- a/logic_extensions/http/1.0/schema.yaml +++ b/logic_extensions/http/1.0/schema.yaml @@ -5,7 +5,7 @@ info: Webhook contract between Arcade Engine and external hook servers for tool execution control. **Note:** All endpoint paths are fully configurable. The paths shown (/pre, /post, etc.) are just defaults. You specify the actual paths when configuring your hooks in Arcade. The payloads described below remain the same. - version: 1.1.1-beta + version: 1.2.0-beta paths: /pre: @@ -309,6 +309,12 @@ components: description: Whether the tool succeeded output: description: The tool's output value (any JSON type — string, number, object, array, etc.) + content: + type: array + description: | + The content blocks a remote MCP server returned alongside its structured result, in MCP wire shape (text, image, audio, resource_link, resource), annotations and `_meta` included. MCP clients receive the text blocks as the unstructured side of the result. Absent when the server sent no content of its own, in which case clients receive `output` rendered as text. + items: + $ref: '#/components/schemas/ContentBlock' execution_code: type: string description: Status code from the server @@ -324,6 +330,24 @@ components: properties: output: description: Override the output value (any JSON type — string, number, object, array, etc.) + content: + type: array + description: | + Replace the content blocks. Omit to forward the request's `content` unchanged. A hook that rewrites `output` should rewrite `content` too, or the server's own text reaches the client as it was sent. + items: + $ref: '#/components/schemas/ContentBlock' + + ContentBlock: + type: object + description: | + An MCP content block in its wire shape. `type` selects the block's other fields, which follow the MCP specification: https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-result + required: + - type + properties: + type: + type: string + description: The block type, e.g. "text", "image", "audio", "resource_link", or "resource" + additionalProperties: true PostHookResult: type: object From 78e6ca0405bebef4cfc084fa7f40958ba42d1a26 Mon Sep 17 00:00:00 2001 From: Wils Dawson Date: Thu, 24 Sep 2026 15:00:14 -0700 Subject: [PATCH 2/4] docs(logic_extensions/http): state what post-hook content carries Spec-defined fields are forwarded, but a resource_link block may arrive without title, size, icons, or _meta, and fields outside the MCP specification may be dropped. `content` is also absent on error results, whose text arrives in `execution_error`. Co-Authored-By: Claude Opus 5.5 (1M context) --- logic_extensions/http/1.0/schema.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic_extensions/http/1.0/schema.yaml b/logic_extensions/http/1.0/schema.yaml index 54a29ce..af8e8c2 100644 --- a/logic_extensions/http/1.0/schema.yaml +++ b/logic_extensions/http/1.0/schema.yaml @@ -312,7 +312,7 @@ components: content: type: array description: | - The content blocks a remote MCP server returned alongside its structured result, in MCP wire shape (text, image, audio, resource_link, resource), annotations and `_meta` included. MCP clients receive the text blocks as the unstructured side of the result. Absent when the server sent no content of its own, in which case clients receive `output` rendered as text. + The content blocks a remote MCP server returned alongside its structured result, in MCP wire shape (text, image, audio, resource_link, resource). Fields the MCP specification defines are forwarded, annotations and `_meta` included, except that a `resource_link` block may arrive without its `title`, `size`, `icons`, or `_meta`. Fields outside the specification may be dropped. MCP clients receive the text blocks as the unstructured side of the result. Absent when the server sent no content of its own, in which case clients receive `output` rendered as text. Also absent on error results, whose error text arrives in `execution_error`. items: $ref: '#/components/schemas/ContentBlock' execution_code: From f011b602a7e58d4dfaac21798b9d7802ef84c8c6 Mon Sep 17 00:00:00 2001 From: Wils Dawson Date: Thu, 24 Sep 2026 15:14:10 -0700 Subject: [PATCH 3/4] docs(logic_extensions/http): empty content override; link the 2026-07-28 spec An empty `override.content` removes every upstream block, and MCP clients then receive `output` rendered as a single text block. The ContentBlock description now links the 2026-07-28 tools specification. Co-Authored-By: Claude Opus 5.5 (1M context) --- logic_extensions/http/1.0/schema.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logic_extensions/http/1.0/schema.yaml b/logic_extensions/http/1.0/schema.yaml index af8e8c2..39ed11e 100644 --- a/logic_extensions/http/1.0/schema.yaml +++ b/logic_extensions/http/1.0/schema.yaml @@ -333,14 +333,14 @@ components: content: type: array description: | - Replace the content blocks. Omit to forward the request's `content` unchanged. A hook that rewrites `output` should rewrite `content` too, or the server's own text reaches the client as it was sent. + Replace the content blocks. Omit to forward the request's `content` unchanged. An empty list removes every upstream block, and MCP clients then receive `output` rendered as a single text block. A hook that rewrites `output` should rewrite `content` too, or the server's own text reaches the client as it was sent. items: $ref: '#/components/schemas/ContentBlock' ContentBlock: type: object description: | - An MCP content block in its wire shape. `type` selects the block's other fields, which follow the MCP specification: https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-result + An MCP content block in its wire shape. `type` selects the block's other fields, which follow the MCP specification: https://modelcontextprotocol.io/specification/2026-07-28/server/tools#tool-result required: - type properties: From ec544e8c6492926ab465b7b177ee101db999fc39 Mon Sep 17 00:00:00 2001 From: Wils Dawson Date: Thu, 24 Sep 2026 16:38:18 -0700 Subject: [PATCH 4/4] docs(logic_extensions/http): describe post-hook content as protocol-neutral `content` is Arcade's protocol-neutral content-block format. It follows MCP's content-block model, so MCP tooling and documentation apply, and content a server returns in another protocol would be converted into it. Remote MCP servers are its only source today. The MCP link stays as the block definitions the format follows. Wording only. The JSON shape and every semantic are unchanged, and the version stays 1.2.0-beta. Co-Authored-By: Claude Opus 5.5 (1M context) --- logic_extensions/http/1.0/schema.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/logic_extensions/http/1.0/schema.yaml b/logic_extensions/http/1.0/schema.yaml index 39ed11e..a1fa036 100644 --- a/logic_extensions/http/1.0/schema.yaml +++ b/logic_extensions/http/1.0/schema.yaml @@ -312,7 +312,7 @@ components: content: type: array description: | - The content blocks a remote MCP server returned alongside its structured result, in MCP wire shape (text, image, audio, resource_link, resource). Fields the MCP specification defines are forwarded, annotations and `_meta` included, except that a `resource_link` block may arrive without its `title`, `size`, `icons`, or `_meta`. Fields outside the specification may be dropped. MCP clients receive the text blocks as the unstructured side of the result. Absent when the server sent no content of its own, in which case clients receive `output` rendered as text. Also absent on error results, whose error text arrives in `execution_error`. + The content blocks the tool's server returned alongside its structured result, in Arcade's protocol-neutral content-block format (see `ContentBlock`). Today the only source is remote MCP servers. Fields the block definitions include are forwarded, annotations and `_meta` included, except that a `resource_link` block may arrive without its `title`, `size`, `icons`, or `_meta`. Fields outside the block definitions may be dropped. Clients receive the text blocks as the unstructured side of the result. Absent when the server sent no content of its own, in which case clients receive `output` rendered as text. Also absent on error results, whose error text arrives in `execution_error`. items: $ref: '#/components/schemas/ContentBlock' execution_code: @@ -333,14 +333,14 @@ components: content: type: array description: | - Replace the content blocks. Omit to forward the request's `content` unchanged. An empty list removes every upstream block, and MCP clients then receive `output` rendered as a single text block. A hook that rewrites `output` should rewrite `content` too, or the server's own text reaches the client as it was sent. + Replace the content blocks, in the same format as the request's `content`. Omit to forward the request's `content` unchanged. An empty list removes every block, and clients then receive `output` rendered as a single text block. A hook that rewrites `output` should rewrite `content` too, or the server's own text reaches the client as it was sent. items: $ref: '#/components/schemas/ContentBlock' ContentBlock: type: object description: | - An MCP content block in its wire shape. `type` selects the block's other fields, which follow the MCP specification: https://modelcontextprotocol.io/specification/2026-07-28/server/tools#tool-result + A block in Arcade's protocol-neutral content-block format: `text`, `image`, `audio`, `resource_link`, or `resource`, with `annotations` and `_meta`. The format follows the MCP content-block model, so MCP tooling and documentation apply, and `type` selects the block's other fields as MCP defines them: https://modelcontextprotocol.io/specification/2026-07-28/server/tools#tool-result. Content a server returns in another protocol would be converted into this format. required: - type properties: