Skip to content

[bug] OpenAPI object JSON bodies always send Content-Type application/json, dropping vendor +json types #1930

Description

@dsivaasi

Executor version

Executor Cloud (hosted, 2026-09-03). Cloud MCP at https://executor.sh/<org>/mcp.

How do you run Executor?

Executor Cloud

Operating system

Linux

Integration involved

Built-in OpenAPI plugin (packages/plugins/openapi/src/sdk/invoke.ts). Observed on a JSON:API integration (application/vnd.api+json).

What happened

Writes (POST/PATCH) against a JSON:API server return HTTP 415. The server requires Content-Type: application/vnd.api+json. Executor sends application/json.

Callers cannot override it. OpenAPI header parameters named Content-Type are ignored (OAS). Tool arguments headers / header / params are rejected as unknown arguments. contentType is only exposed when the spec declares multiple requestBody media types.

Root cause is in applyRequestBody:

if (isJsonContentType(contentType)) {
  if (typeof bodyValue === "string") {
    return sent(HttpClientRequest.bodyText(request, bodyValue, contentType));
  }
  return sent(HttpClientRequest.bodyJsonUnsafe(request, bodyValue));
}

isJsonContentType is true for any +json type (including application/vnd.api+json). Object/structured bodies then go through bodyJsonUnsafe without the declared media type, so the wire header becomes application/json. String bodies correctly keep the vendor type via bodyText.

updateSpec cannot set integration headers (it preserves existing ones). addSpec can set static headers, which would override after the body is applied — but there is no MCP/UI path to add those headers later.

Patching the spec so requestBodies declare application/vnd.api+json does not fix the normal calling convention (object body), because of the bodyJsonUnsafe branch above.

What you expected

When the selected requestBody media type is application/vnd.api+json (or any +json vendor type), the outbound Content-Type should be that type, not application/json.

Suggested fix: serialize object JSON bodies with the declared media type, e.g. HttpClientRequest.bodyText(request, JSON.stringify(bodyValue), contentType) (or pass the type into bodyJsonUnsafe if the client supports it).

Static integration headers (addSpec.headers) should also be editable after create (updateSpec or configure), so JSON:API Accept/Content-Type can be set without deleting the integration.

Steps to reproduce

  1. Add an OpenAPI integration whose POST requestBody content is application/vnd.api+json (JSON:API).
  2. Connect a credential and call a write tool with a structured body object (the generated TypeScript shape).
  3. Observe the upstream Content-Type: application/json and HTTP 415.
  4. Passing headers: { "Content-Type": "application/vnd.api+json" } on the tool call fails with unknown arguments.
  5. A string body plus a spec that already declares application/vnd.api+json does send the vendor type (bodyText path) — object bodies do not.

Diagnostics / logs

No secrets. Hosted Cloud. Upstream 415 body is the usual JSON:API unsupported media type. Reads on the same connection succeed (no request body).

Code: packages/plugins/openapi/src/sdk/invoke.ts (isJsonContentType, applyRequestBody). isJsonContentType already intends to treat +json as JSON for serialization; the missing piece is preserving the declared type on the header.

Before you submit

  • I searched the open issues for a duplicate.
  • I removed all keys, tokens, and credentials from this report.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions