Connect a generic MCP client
Protocol details for any MCP client or custom agent - versions, headers, requests, results and errors.
Any client that speaks MCP over HTTP and can send a bearer token can use a PipMCP endpoint: Cursor, ChatGPT, agent frameworks or your own code. The endpoint page has ready-made snippets for Cursor and ChatGPT.
Cursor
{
"mcpServers": {
"my_api": {
"url": "https://mcp.pipmcp.com/<workspace>/<endpoint>",
"headers": { "Authorization": "Bearer pmcp_your_token" }
}
}
}
ChatGPT and other clients
Use the endpoint URL as the server URL and the access token as an API key or bearer token:
Server URL: https://mcp.pipmcp.com/<workspace>/<endpoint>
Authentication: Bearer token -> pmcp_your_token
Transport
- Send each JSON-RPC 2.0 message as an HTTP
POSTto the endpoint URL withContent-Type: application/json. - One message per request. Batches are rejected.
- Every request gets a single JSON response. There are no sessions: no
Mcp-Session-Idis issued, and no server-sent event stream is needed.GETandDELETEreturn405. - Notifications (messages without an
id) are accepted with202and an empty body. - Maximum request body: 1 MB.
- Authenticate every request with
Authorization: Bearer pmcp_….
Protocol versions
| Version | Status |
|---|---|
2026-07-28 |
Primary. Stateless, per-request metadata. |
2025-11-25 |
Compatibility |
2025-06-18 |
Compatibility |
2025-03-26 |
Compatibility |
MCP 2026-07-28
There is no initialize handshake. Every request carries the protocol version and client capabilities in params._meta, mirrored in headers:
| Header | Value |
|---|---|
MCP-Protocol-Version |
2026-07-28, same as _meta["io.modelcontextprotocol/protocolVersion"] |
Mcp-Method |
The JSON-RPC method, e.g. tools/call |
Mcp-Name |
For tools/call: the tool name from params.name |
_meta["io.modelcontextprotocol/clientCapabilities"] is required on every request (use {} if you have none). _meta["io.modelcontextprotocol/clientInfo"] is optional and shows up in the logs as the client name. Header values that are not plain ASCII may be sent base64-encoded as =?base64?…?=.
Supported methods: server/discover, tools/list, tools/call.
List tools:
curl https://mcp.pipmcp.com/<workspace>/<endpoint> \
-H "Authorization: Bearer pmcp_your_token" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2026-07-28" \
-H "Mcp-Method: tools/list" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}'
Call a tool:
curl https://mcp.pipmcp.com/<workspace>/<endpoint> \
-H "Authorization: Bearer pmcp_your_token" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2026-07-28" \
-H "Mcp-Method: tools/call" \
-H "Mcp-Name: search_customers" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search_customers","arguments":{"query":"Acme"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}'
If a header is missing or does not match the body, the request fails with -32020 (header mismatch). An unsupported version in _meta fails with -32022 and lists the supported versions in error.data.supported.
2025-era clients
Clients on 2025-11-25, 2025-06-18 or 2025-03-26 start with initialize as usual. The server answers with the requested version if it is supported, otherwise with 2025-11-25. Send the negotiated version in the MCP-Protocol-Version header on later requests (requests without the header are treated as 2025-03-26).
Supported methods: initialize, ping, tools/list, tools/call, plus resources/list, resources/templates/list and prompts/list, which return empty lists.
Tool results
A successful call returns the result as JSON text in content and as structured data in structuredContent:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"resultType": "complete",
"content": [{ "type": "text", "text": "{\n \"data\": [ ... ]\n}" }],
"structuredContent": { "data": [ ... ] }
}
}
Tool-level failures are returned as results with isError: true and a normalized error in structuredContent.error, so the agent can read and act on them:
{
"isError": true,
"content": [{ "type": "text", "text": "Error VALIDATION_FAILED: The upstream API rejected the customer record.\n- email: Email already exists\nSuggested action: Search for the customer before creating a new record." }],
"structuredContent": {
"error": {
"code": "VALIDATION_FAILED",
"message": "The upstream API rejected the customer record.",
"details": [{ "field": "email", "message": "Email already exists" }],
"suggested_action": "Search for the customer before creating a new record.",
"retryable": false
}
}
}
The error codes are listed in Tools and mappings.
Confirmation with elicitation
If a call needs confirmation and your client declared the elicitation capability in clientCapabilities (2026-07-28 only), the server returns:
{
"resultType": "input_required",
"inputRequests": {
"confirm": {
"method": "elicitation/create",
"params": {
"mode": "form",
"message": "Confirm: Delete customer. The \"Safe writes\" preset requires confirmation for risk level 3 actions.",
"requestedSchema": { "type": "object", "properties": { "confirm": { "type": "boolean", "title": "Run this action?" } }, "required": ["confirm"] }
}
}
},
"requestState": "eyJ0Ijoi..."
}
Ask the user, then repeat the same tools/call (same name and arguments) with two extra params:
{
"name": "delete_customer",
"arguments": { "customer_id": "c_123" },
"requestState": "eyJ0Ijoi...",
"inputResponses": { "confirm": { "action": "accept", "content": { "confirm": true } } },
"_meta": { "...": "..." }
}
requestState is signed, bound to your token, the tool and the exact arguments, valid for 10 minutes and usable once. Responding with "action": "decline" or "cancel" records the call as cancelled without running it.
Clients without elicitation get CONFIRMATION_REQUIRED instead; see Permissions and risk.
Protocol errors
| Code | HTTP | Meaning |
|---|---|---|
-32700 |
400 | Body is not valid JSON |
-32600 |
400 / 404 | Invalid request, batch sent, or endpoint not found |
-32601 |
404 / 200 | Method not found |
-32602 |
200 / 400 | Invalid params, unknown tool, or missing client capabilities |
-32020 |
400 | Header mismatch |
-32022 |
400 | Unsupported protocol version |
40100 |
401 | Missing or invalid access token |
40300 |
403 | Token lacks the scope, endpoint disabled, or Origin not allowed |
42900 |
429 | Rate limit exceeded; see Retry-After |
Browser clients
Requests from browsers must come from an allowed Origin. Server-to-server clients send no Origin header and are not affected.