Using Connect from any MCP client
Every call is a single JSON-RPC 2.0 object posted to https://connectbyjbrh.com/mcp. Under revision 2026-07-28 no handshake is required: put the protocol version in params._meta and send tools/list or tools/call straight away. An older client may still send initialize first and will be answered.
One call, end to end#
curl -sS https://connectbyjbrh.com/mcp \
-H 'Content-Type: application/json' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"search_public_docs",
"arguments":{"query":"call recording","limit":3},
"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28"}}}'No Origin header is sent, which is correct for anything that is not a browser. No cookie, token or session identifier is involved. The reply is one JSON object with a result containing both a text block and structuredContent.
The methods a client may send#
| Method | Params | Returns |
|---|---|---|
initialize | protocolVersion, client info | The agreed version, the server's capabilities, serverInfo, and instructions telling a model to check status before claiming a capability |
ping | — | An empty object |
tools/list | — | Ten tool descriptors with input schemas and annotations |
tools/call | name, arguments | A tool result, or a result with isError: true |
resources/list | — | Four resource descriptors |
resources/read | uri | The document, with its real media type |
resources/templates/list | — | An empty list — there are no templated resources |
prompts/list | — | Two prompt descriptors |
prompts/get | name, arguments | A single user message ready to send to a model |
logging/setLevel | any | An empty object; accepted and not acted on |
notifications/initialized | — | Nothing; HTTP 202 |
notifications/cancelled | — | Nothing; HTTP 202 |
Anything else raises method-not-found. The initialize result is worth reading even if you skip the handshake: its instructions field is the text that tells a model several Connect capabilities exist as foundation rather than as usable features, which is the single most useful correction a client can pass through to a model.
Writing a minimal client#
Decide whether to handshake. If your client is new, skip
initializeand include_metaon every request. If it is an existing client for an older revision, sendinitializeand use the version in the reply.Result Either path is accepted; mixing them is fine too.
Send optional headers only if you mirror them exactly.
MCP-Protocol-Version,Mcp-MethodandMcp-Namemust match the body, or the request is rejected with-32020.Result Sending none of the three is the simplest correct choice.
Parse the body before the status line. A response can be HTTP
200and still contain an error object — an unknown tool name arrives that way.Result Your client records failures accurately instead of counting a call to a non-existent tool as a success.
Handle
429by waiting. The limit is 120 requests per minute per address and noRetry-Afteris sent.Result A widening delay clears it; an immediate retry does not.
Cache what you fetch, keyed on the page's
updateddate.Result The corpus changes on a deploy, not per request, so a cached page stays correct until the date moves.
Reading a resource#
{"jsonrpc": "2.0", "id": 2, "method": "resources/read",
"params": {"uri": "https://connectbyjbrh.com/docs-data/status.json"}}The four resource URIs are absolute and are the same documents the website serves, so a client with an HTTP fetcher can read them directly instead — llms.txt for the map, docs-manifest.json for every page as JSON, docs-data/status.json for capability status, and the A2A card. Going through resources/read buys you the media type and one code path for everything; going direct buys you edge caching.
Questions#
Can I keep a connection open?
There is nothing to keep open. Each request is an independent POST, no session is minted, and the standalone stream this revision removed does not exist here. Use ordinary HTTP connection reuse if you want fewer handshakes.
What is the smallest useful call?
get_product_status with empty arguments. It returns the five status words, every documented capability with its status, and the corpus counts — enough to answer most capability questions without a second call.
How do I know a tool result is bad without reading the prose?
Check result.isError. A successful call also carries structuredContent, so a program can branch on the presence of that field rather than on the wording of a sentence.