Skip to content

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 POST to the endpoint URL with Content-Type: application/json.
  • One message per request. Batches are rejected.
  • Every request gets a single JSON response. There are no sessions: no Mcp-Session-Id is issued, and no server-sent event stream is needed. GET and DELETE return 405.
  • Notifications (messages without an id) are accepted with 202 and 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.