Connect by JBRH Open Connect

An MCP client cannot connect

Connect's MCP endpoint is POST /mcp and nothing else. Four refusals cover almost every failure: a GET or DELETE gets 405, a present but unrecognised Origin gets 403, a protocol version that disagrees between header and body gets JSON-RPC error -32020, and a workspace tool without an integration key is refused while the documentation tools need no credential at all.

Status
Available What this means
Audience
developer
Last verified
Product version
6.3.2

The four refusals#

SymptomStatusCauseFix
405, with Allow: POST405The client opened a GET stream or sent DELETE. Revision 2026-07-28 removed the standalone GET stream and protocol-level sessionsSend every message as a POST. Do not wait for a stream to carry anything
Origin not allowed403An Origin header was present and is not recognised. A client that sends no Origin at all is acceptedSend no Origin from a desktop client; from a browser, use an origin the server knows
Header does not match the body400, code -32020MCP-Protocol-Version, Mcp-Method or Mcp-Name disagreed with the bodySend the header and the body value from one source, or send only one of them
Unsupported protocol version400, with the supported listA revision this server does not speakUse one of the four supported revisions returned in the error data

The header-agreement rule is the one that surprises implementers, and the reason is worth knowing: a load balancer that routes on the header and a server that executes on the body must not be able to see two different requests. A mismatch is therefore a refusal rather than a preference for one of the two.

What the endpoint is#

POST /mcp HTTP/1.1
Host: connectbyjbrh.com
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28

{"jsonrpc":"2.0","id":1,"method":"tools/list",
 "params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28"}}}
Transport
Streamable HTTP, one endpoint, POST only.
Supported revisions
2026-07-28, and the three initialization-based revisions before it. An older client that sends initialize gets a normal result and its later requests are accepted without per-request metadata, because refusing them would cut off the connector directories that speak those revisions.
Sessions
None. Mcp-Session-Id is ignored and never minted, and Last-Event-ID is ignored because streams are not resumable. A client waiting to be given a session id waits for something that will not arrive.
Batches
Not accepted. Send one JSON-RPC message per request.
Size and rate
A body over 256 KB is refused, and the endpoint allows 120 calls per minute per client before answering 429.
Discovery
GET /.well-known/mcp.json describes the endpoint, its transport, the supported revisions and the public tool names.

Authentication, which is narrower than it looks#

The public documentation tools need no credential and touch no workspace: they read the same generated corpus the website serves. So a connection that fails while calling search_public_docs is not an authentication problem, whatever the client's error text says — there is nothing to authenticate against.

  • Ten public tools are available without a key: searching and fetching documentation pages, listing and getting a capability, getting a workflow, searching the glossary, getting a technology or a protocol page, the product status, and the changelog.
  • Workspace tools require an integration key and are scoped to that key's single workspace.
  • Workspace tools call the existing domain services, so autonomy, approval, suppression, sales limits, metering and the audit trail all still apply to anything an agent does through them.
  • There is deliberately no tool that runs a query, none that proxies an arbitrary internal route, and no write that bypasses the service owning the record.

What Connect completed#

Every one of these refusals is a complete, deliberate answer. The server validated the request, decided, and replied with a JSON-RPC error carrying a code and, where it helps, the data needed to correct the call — the list of supported revisions, for instance. Nothing was left open and no workspace was touched, which is why a refused request costs nothing and can be corrected and retried immediately.

What Connect did not complete#

It did not establish a session, because it never establishes one. It also does not negotiate downward mid-conversation: a request naming an unsupported revision is refused rather than answered under a different one. And it does not tell a browser-based client which origins are acceptable — an unrecognised origin is refused without enumerating the alternatives, since publishing that list would defeat the check.

What you can do#

  1. Fetch the discovery document first.

    Result It names the endpoint, the transport, the supported revisions and the public tools, so most configuration mistakes are visible before you send a single JSON-RPC message.

  2. Send tools/list as a plain POST with no Origin header.

    Result If that works, the transport and the version are fine and the problem is in whatever your client adds — an Origin, a session expectation, or a mismatched header.

  3. If you get -32020, remove the headers and rely on the body.

    Result The disagreement disappears. Add the headers back one at a time to find which one your client is filling in differently.

  4. If you get 429, slow down and retry.

    Result The limit is per client per minute; it is a rate refusal, not a block, and nothing needs to be reconfigured.

When to escalate#

Escalate when a correctly formed POST on a supported revision, with no Origin, is refused for a reason not in the table above — and quote the JSON-RPC error code, which is the part that identifies the check that fired. A workspace tool refusing an integration key that works elsewhere is also worth raising, since keys are scoped to one workspace and a scope mismatch reads as an authentication failure.

Questions#

My client keeps opening a GET stream and hanging. Is the server down?

No. The endpoint answers GET with 405 and an Allow: POST header, deliberately, because the revision it speaks removed the standalone GET stream. A client that waits on that stream is waiting for something the protocol no longer has.

Do I need credentials to read the documentation tools?

No. They are public and touch no workspace, which is also why they cannot leak anything: they read the same generated corpus the website serves, so they cannot answer differently from the published pages.

Why is a missing Origin allowed when a wrong one is refused?

Because a desktop client is not a browser and sends none. What the specification requires is that a *present* origin be validated, so that a page on any website cannot drive the server through a visitor's browser.