Moltline Studio Get a license

Blog

MCP HTTP Errors: What 400, 401 and 403 Mean at the Endpoint

Professional header image for educational tutorial: Reading Hosted MCP Errors: 400, 401, 403 at the Endpoint
curl -i -sS -X POST https://mcp.moltlinestudio.com/catalog -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"probe","version":"1.0"}}}'

Your agent's MCP call is failing and you cannot tell whether the fault is your JSON, your headers, your network, or your licence. The status line from a single curl request separates those four. A 400 points at your request body or method. A 401 means your credentials never arrived, or arrived malformed. A 403 means you authenticated and something upstream still blocked you.

That distinction matters on mcp.moltlinestudio.com/, which serves 22 servers and 160 tools over Streamable HTTP. 110 of those tools need no account, key, or signup, so most auth failures are local configuration, not missing entitlements. The other 50 are premium, and an unlicensed call returns premium_tool_requires_license in the tool result body, never as a status code.

Moltline's servers follow the 2025 revisions of the spec: they accept protocol versions up to 2025-11-25 and need initialize before any other method, so the examples below start there.

Start With One curl and Read the Status Line

Start with a single request that captures everything at once.

curl -i -sS -X POST https://mcp.moltlinestudio.com/catalog -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"probe","version":"1.0"}}}' | tee /tmp/mcp-response.txt

A healthy endpoint answers 200 with content-type: application/json and an mcp-session-id header; send that header on every later request. Without it, tools/list and tools/call get a 400 with Bad Request: Missing session ID in the JSON-RPC error.

Keep the full output in a file rather than scrolling it in a terminal, because the JSON-RPC payload sits below the headers and is easy to lose.

Before blaming the endpoint, confirm the server slug and tool name on the specific entry in the hosted server listing. A wrong slug returns a routing error, not a tool error.

Name the spec version you are testing against. The Streamable HTTP transport page labels 2026-07-28 as latest, and its header sections are where most client-side 400s originate. Inside a session on our endpoint, an MCP-Protocol-Version: 2026-07-28 header gets a 400 whose message lists the supported versions: 2024-11-05, 2025-03-26, 2025-06-18 and 2025-11-25.

If the headers still look correct, how the transport layer works covers what the endpoint validates before dispatch.

The Endpoint Layer Is Not the Tool Layer

A status code comes from whichever layer answered, not from the tool you called. A request reaches a hosted tool through a fixed sequence:

  1. Your MCP client

  2. Any network proxy

  3. The header check

  4. Streamable HTTP validation

  5. JSON-RPC dispatch

  6. The tool itself

Only the first four can return a 4xx. By stage five the request is well-formed and the transport has accepted it. Faults past that point belong to the tool itself, including choices like picking an image editing tool.

Four sections of the MCP transport specification define what the endpoint validates: Protocol Version Header, Standard Request Headers, Custom Headers from Tool Parameters, and Server Validation.

Scope: this mapping covers the hosted Streamable HTTP endpoint at mcp.moltlinestudio.com/. Local stdio transports and other hosts validate differently, and their error text will not match this one. With that map fixed, the first code to diagnose is 400.

HTTP 400 at an MCP Endpoint: Bad Body or Wrong Method

Inside that endpoint layer, 400 is the code you meet most often. The endpoint returns 400 when the request is malformed or the method is not the one that route accepts.

Rule out a malformed body first

  • "jsonrpc":"2.0" missing, or a "1.0" left in from an older client

  • id sent as a string where the schema expects a number

  • a trailing comma, or an unescaped quote inside an argument

At mcp.moltlinestudio.com these failures surface as a 400 in the status line, so fix the body before reading anything else. Surface the detail in your client instead of reading the raw status.

Wrong method comes second

  • tools/call or tools/list sent before initialize completes (on our endpoint: a 400 with Bad Request: Missing session ID)

  • tools/list spelled tool/list

  • a notification carrying an id

Batch arrays also need the correct Content-Type on the request.

Header-side 400s

These come from transport rules, not the tool:

  • a missing or mismatched MCP-Protocol-Version

  • an Accept header that omits text/event-stream

  • Content-Type: text/plain

The Streamable HTTP transport spec covers all three.

Arguments that fail validation do not produce a 400. They return 200 with an error object in the result, so bad tool params look healthy in your status-code logs. Client-side MCP wiring for Claude is usually where those header defaults get set.

HTTP 401: The Credentials Never Arrived, or Arrived Wrong

Where a 400 points at your request body, a 401 points at headers that never arrived in usable form.

The endpoint returns 401 when the request arrives without credentials it can use. Read any WWW-Authenticate header before you look at your key, because it names the scheme the endpoint expected.

Check causes in this order:

  • An HTTP proxy, or an SDK that does not forward custom headers, strips the auth header in transit.

  • An env var set in your shell but empty inside the agent runtime.

  • A key pasted with a trailing newline.

  • A scheme mismatch, such as Bearer sent as Token.

A 401 on one of the 110 free tools is a configuration bug, not an entitlement bug. Those tools need no account, key or signup, so there was nothing to reject. Entitlements arrive elsewhere, as premium tools and 402 handling explains.

A 401 with no tool name attached means the handshake failed, not the tool.

Rebuild the call in plain curl with the identical header value. If curl succeeds and the agent fails, the defect is in the client config, and endpoint debugging will not fix it. A blocked-but-authenticated request returns 403 instead.

HTTP 403: Authenticated, Then Blocked Before the Tool

A 403 means the request passed authentication and something behind it refused. The endpoint gives a 403 when it understood the request and declined to authorize it. Resending the same credentials changes nothing; a policy decision, not a credential check, produced the code.

Observed causes on hosted endpoints, as patterns rather than documented guarantees:

HTTP 403: Authenticated, Then Blocked Before the Tool
HTTP 403: Authenticated, Then Blocked Before the Tool
  • An egress allowlist that lists a general API host but not mcp.moltlinestudio.com.

  • A TLS-inspecting proxy that rewrites or re-signs the request in transit.

  • A WAF rule keyed to user-agent string or JSON request bodies.

Reading the 403 body

Check whether the body is JSON-RPC or an HTML error page. The endpoint at mcp.moltlinestudio.com answers in JSON, so an HTML body points at a proxy or gateway in front of it.

curl --noproxy '*' -i -sS -X POST https://mcp.moltlinestudio.com/catalog -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"probe","version":"1.0"}}}'

Compare that against the same request through the proxy, then run it from another network to test the egress hypothesis. Read Via, Server and X-Forwarded-* in the response headers; the hop that answered usually identifies itself, and that name is where the ticket goes. Licence failures never surface here; they arrive in the tool result, and what breaks in AI licensing covers that path.

Why a Licence Problem Never Arrives as an HTTP Status

A 403 answers in the status line. A missing licence does not.

The 50 premium tools return premium_tool_requires_license inside the tool result, under a normal HTTP 200. There is no 402, no 403 and no auth challenge. A licence problem is a tool result, not a transport error. Here is a captured response from the catalog server's premium get_full_kit tool, called in a session with no licence (trimmed; the content text repeats the same JSON as structuredContent):

{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"{...}"}],"structuredContent":{"error":"premium_tool_requires_license","tool":"get_full_kit","message":"...","upgrade_url":"https://moltlinestudio.com/#allaccess","price":{...},"x402":{"resource":"https://moltlinestudio.com/api",...},"x402_day_pass":{"resource":"https://moltlinestudio.com/api/premium/day-pass",...}},"isError":false}}

The envelope carries the usual jsonrpc and id fields, and the result names the requirement, the licence page and both x402 purchase resources. Your client should surface the string, not a status code.

Two ways to clear it:

  • 19 USDC on Base at buy a month of All-Access covers one month.

  • 2 USDC at https://moltlinestudio.com/api/premium/day-pass covers a day pass to the end of the next UTC day.

Agents pay over x402 with no human in the loop. Billing is never per call.

One trap sits beside this. mcp.moltlinestudio.com/api does not exist. A 404 there is a wrong URL, not a licence problem. If you see an HTTP 402 anywhere in this flow, something other than the MCP endpoint answered. Name that something in your bug report.

The table below puts all four signals side by side.

400 vs 401 vs 403 vs premium_tool_requires_license

With the licence case placed in the body, here is the whole family side by side.

Signal

HTTP status

Where it originates

What it is not

First thing to check

400 Bad Request

400

Client or transport layer: request syntax, JSON-RPC framing, transport header validation

A tool failure; the tool never executed

The raw request body and the MCP-Protocol-Version header

401 Unauthorized

401

Auth surface, at the header check

An entitlement problem on a free tool

Whether the Authorization header arrived at all

403 Forbidden

403

Policy layer: an allowlist, a proxy, or a WAF rule

A credential rejection

The Via header, and whether the body is JSON-RPC or HTML

premium_tool_requires_license

200

Entitlement lookup, inside the tool result body

A transport error

Whether you meant to call a premium tool, and whether the licence is live

Rule out the rows above yours: a bad MCP-Protocol-Version value produces a 400 that looks nothing like a licensing problem.

Scan to your code, stop, and fix that layer only.

Diagnosing by Symptom: A Short Checklist

The table tells you which layer failed. This checklist tells you what to capture so the answer is not a guess.

  1. Save the full curl -i output to a file.

  2. Read the status line and headers before the body.

  3. Grep the body for jsonrpc to confirm which layer answered. No match means the MCP server never replied.

  4. Check WWW-Authenticate on a 401.

  5. Check Via and Server on a 403.

curl -i -sS -X POST https://mcp.moltlinestudio.com/<server> > /tmp/mcp.txt
grep -i jsonrpc /tmp/mcp.txt

Match the failing request against a working one from the same machine. Change one variable at a time: method, then body, then headers, then network path. If the failure appears in only one client, the Claude Code plugin walkthrough shows how that client wires MCP.

Log the HTTP status separately from the JSON-RPC error code. One combined metric is why 400s and licence failures fire the same alert.

When the endpoint is genuinely at fault, capture four things: server slug, tool name, timestamp in UTC, and the raw response. Confirmed defects get fixed within 30 days.

Before calling a premium tool broken, check its public MCPize listing for grade and scope, then the tool entry at moltlinestudio.com/servers.html. An unlicensed call is a licence question, not a bug.

What to Fix First

With the checklist done, fix in this order.

  • 400: print the raw request before changing anything. Check MCP-Protocol-Version, Accept and Content-Type against the 2026-07-28 transport spec.

  • 401: the header did not arrive in a usable form. Rebuild the call in curl, compare header values, then fix the client config. On the 110 free tools there is no credential to blame.

  • 403: something outside the endpoint refused you. Read Via and Server, find the hop, then test with curl --noproxy '*'.

  • Licence: not an HTTP status. It is premium_tool_requires_license inside a 200. Fix it at https://moltlinestudio.com/api, not in your headers.

Start with one request you can reproduce. Capture the full response, then read the code. That order also holds when you compare an AI website builder with an MCP stack comparison.

Conclusion

Status codes tell you where a request died. JSON-RPC codes tell you what the endpoint decided. Keep the two apart and most of this debugging gets shorter.

  • 400 means your request shape is wrong. Print the raw body before touching anything else.

  • 401 means the credential never arrived in usable form. Rebuild the call in curl and compare headers.

  • 403 means a hop outside the endpoint blocked you. Read Via and Server, then test with curl --noproxy '*'.

  • premium_tool_requires_license arrives inside a 200. It is a licence question, not a defect.

Next step: reproduce one failing call, capture the full response, and check that tool's public MCPize grade before filing a report. The 110 free tools need no credential at all, so start there. If the tool sits in the other 50, open https://moltlinestudio.com/api and settle the $19/month All-Access licence in USDC on Base. One reproducible request beats an hour of guessing.