MCP diagnostics
MCP diagnostics tests your own MCP server, the one you build and deploy, as an MCP client would see it. A run tells you:
- whether the server is reachable;
- how it authenticates;
- which protocol version it negotiates;
- whether its tools, resources and prompts are well formed.
It never calls your tools. Every request and response is kept in a redacted transcript that you can export as a receipt.
This page is about testing a server you run. To give your AI assistant Hooklistener's own tools, see Setup or Connect with one prompt.
Where to find it
Open MCP diagnostics in the Operate section of the app's sidebar (https://app.hooklistener.com/mcp-diagnostics), or search for it with ⌘K. It used to be a tab under Real-time; old /realtime/mcp links redirect to the new pages.
MCP diagnostics is available on every plan, Free included. Runs belong to the organization: any member can start, cancel, rerun, export or delete them.
Run a diagnostic
- Click Run diagnostic.
- Enter the MCP endpoint URL, for example
https://api.example.com/mcp. - Choose the Authentication: No authentication, OAuth 2.1 (recommended), Bearer token or Custom headers. See Authentication.
- Click Run diagnostic.
The run is queued and the page updates live as each step completes.
The URL must point to a remote server that speaks Streamable HTTP:
- It must be reachable from the internet. Local stdio servers aren't supported. Neither are
localhost, private, loopback or link-local addresses, nor hosts that don't resolve to a public IP address. http://orhttps://, on any port. HTTPS is required when you supply credentials of any kind.- No query string (put credentials in headers), no
user:password@and no#fragment. At most 2,048 characters.
What a run checks
A run is read-only. It sends these requests in order:
-
Reachability. Hooklistener connects to the URL. Every request in a run goes to the same IP address, so session affinity holds behind round-robin DNS.
-
Initialize. It sends
initialize, offering protocol version2025-11-25, withclientInfonamedHooklistener MCP Diagnostics. The response must includeprotocolVersion,serverInfo.name,serverInfo.versionand acapabilitiesobject. -
Protocol version. The server may answer
2025-11-25,2025-06-18,2025-03-26or2024-11-05. Any other version fails the run, and the run stops there. -
Initialized notification. It sends
notifications/initialized. An error answer is a warning. -
Ping. It sends
ping. A server that doesn't implement it (-32601) gets Skipped, not a failure. -
Capability discovery. For each capability the server advertised, it calls
tools/list,resources/listandprompts/list. It followsnextCursorfor up to 10 pages and 500 items per list; past either limit the check is a warning. It also validates every descriptor:- Tools need a
nameand aninputSchemaobject with"type": "object", apropertiesobject and arequiredarray of strings. AnoutputSchema, if present, is checked the same way. - Resources need a
nameand auri. - Prompts need a
name, andargumentsmust be an array of objects with aname.
A capability the server didn't advertise is Skipped.
- Tools need a
-
Session cleanup. If
initializereturned anMcp-Session-Id, it sendsDELETEto end the session. A2xx, a404(already closed) or a405(the server doesn't let clients end sessions) all pass.
A run never calls tools/call, resources/read or prompts/get, and never answers sampling or elicitation requests from the server.
Each check is Passed, Warning, Failed or Skipped. The run's result is Failed if any check failed, Warning if any check warned, and Passed otherwise. Skipped checks don't lower the result.
Common failures
| Check | What it means |
|---|---|
| Authentication | The server answered 401 or 403. Without credentials the message is "The server requires authentication; add credentials or choose OAuth". The server's WWW-Authenticate header is quoted. |
| Initialize | The server answered 429 (its Retry-After is quoted), another HTTP error, or a response without the required fields |
| Reachability | Timeout, connection failure, an invalid or blocked target, a refused redirect, or a response over the size limit |
| Redirect (warning) | The URL redirected. Configure MCP clients with the final URL: many don't replay POST bodies across redirects. |
Streamable HTTP
Hooklistener tests the Streamable HTTP transport:
- Every request is a
POSTwithAccept: application/json, text/event-streamandContent-Type: application/json. Afterinitialize, requests also carryMcp-Session-Id(when the server issued one) andMCP-Protocol-Version. - A JSON response or an SSE stream are both accepted. An SSE response is read until the message that answers the request arrives. Any other
Content-Typefails. - No
Accept-Encodingis sent, so the server must not compress its responses. - Hooklistener never opens the optional
GETstream. The legacy HTTP+SSE transport (aGETthat announces anendpointevent) is not supported. - Up to 3 redirects are followed, to the same origin only (or from
httptohttpson the same host). The method and body are sent again.
Authentication
Bearer token
The token is sent as Authorization: Bearer <token>, up to 4,096 characters. It is encrypted at rest and kept with the run so that Rerun can reuse it. It never appears in the transcript or in logs.
Custom headers
Enter one header per line as Name: value, for example X-API-Key: …. Limits: up to 20 headers, 4 KB per value and 16 KB in total. Values are encrypted at rest and kept for reruns, and the run shows only the header names ("Supplied headers").
Hooklistener manages some headers itself, and they can't be set here: Accept, Authorization (use Bearer token), Connection, Content-Length, Content-Type, Host, MCP-Protocol-Version, Mcp-Session-Id, Proxy-Authorization, TE, Trailer, Traceparent, Tracestate, Transfer-Encoding and Upgrade.
OAuth 2.1
With OAuth 2.1 (recommended), Hooklistener discovers your server's OAuth configuration, then asks you to approve access in your browser. It uses the authorization code flow with PKCE and requests a token only for your MCP server.
When you submit the form:
-
Challenge. Hooklistener sends
initializewithout credentials and reads theWWW-Authenticatechallenge: itsresource_metadataURL andscope. -
Protected resource metadata (RFC 9728) comes from the challenge's URL, or from
/.well-known/oauth-protected-resource. Itsresourcemust be HTTPS, on the server's origin, with a path matching the endpoint. If the server acceptedinitializewithout credentials and publishes no metadata, the run fails and tells you to run it without OAuth. -
Authorization server metadata comes from RFC 8414 or OpenID Connect discovery. Hooklistener checks that:
- the
issuermatches exactly; - the authorization and token endpoints use HTTPS;
- PKCE with
S256is supported; - if the endpoints are on another origin than the issuer, the server supports the
issauthorization response parameter.
- the
-
Client registration, in this order of preference:
- the Pre-registered client ID (and optional Client secret) from Advanced client settings;
- Hooklistener's Client ID Metadata Document, if the server supports them;
- Dynamic Client Registration (RFC 7591), if the server has a registration endpoint.
If none is possible, the run fails: "The authorization server requires a pre-registered OAuth client ID".
-
Scopes. Hooklistener requests the Requested scopes you entered, or else the challenge's
scope, or else the resource'sscopes_supported.
Then a confirmation page, Continue to <host>, lists the MCP endpoint, the OAuth issuer, the authorization and token hosts, and the requested scopes. Check those hosts, then click Continue with OAuth. The authorization server opens in the same tab. Sign in and approve. Hooklistener exchanges the code, sending the PKCE verifier and the resource indicator (RFC 8707), and queues the run: "OAuth connected. Diagnostic queued."
Approve within 10 minutes, or the authorization expires; use Rerun to start it again. Only the member who started the authorization can finish it. If you leave the confirmation page, the run shows OAuth required with a Continue OAuth button.
Registering Hooklistener with your authorization server
If your authorization server needs Hooklistener registered ahead of time, use these values:
| Value | |
|---|---|
| Redirect URI | https://app.hooklistener.com/realtime/mcp/oauth/callback |
| Client ID Metadata Document | https://app.hooklistener.com/realtime/mcp/oauth/client-metadata.json |
| Client name | Hooklistener MCP Diagnostics |
| Grant types | authorization_code, refresh_token |
| Token endpoint authentication | none (public client), unless you give Hooklistener a client secret |
These URLs keep their /realtime/mcp/oauth path, from before MCP diagnostics moved out of Real-time, because authorization servers already know them.
What is stored
A successful approval creates an OAuth connection that belongs to the organization:
- Encrypted at rest: the access token, the refresh token and the client secret.
- Stored in plain text: the issuer, the endpoints, the client ID, the granted scope and the expiry.
- Dropped once the code is exchanged: the PKCE verifier and
state.
How connections are used:
- Rerun reuses the connection. Before each run, a token that expires within 60 seconds is refreshed.
- If the server answers
401or403during a run, Hooklistener refreshes once and runs the diagnostic again. - If the refresh is refused, the connection shows Needs reauth, and the next Rerun asks you to approve again.
- Each new OAuth diagnostic you start from the form creates its own connection.
The OAuth connections list on the MCP diagnostics page shows each connection's status: Active, Needs reauth, Failed or Pending. Disconnect revokes the stored tokens at the server's revocation endpoint (RFC 7009), if it has one, then deletes the connection. Runs that used it can't be rerun afterwards: Rerun answers "The OAuth connection is no longer available. Configure a new diagnostic.", and a run still queued for it stops with the same error. Start a new diagnostic to connect again.
Runs
Statuses
| Status | Meaning |
|---|---|
| OAuth required | Waiting for you to approve access. Use Continue OAuth. |
| Queued | Waiting for a worker |
| Running | In progress. The page updates as each step is recorded. |
| Passed | Every check passed or was skipped |
| Warning | At least one check warned and none failed |
| Failed | At least one check failed. This is a problem with your server. |
| Cancelled | You cancelled the run |
| Internal error | Hooklistener couldn't complete the run |
A run can also end with the banner The diagnostic could not complete, plus an error code. That means the run itself couldn't finish, not that your server failed a check. The causes are an OAuth setup or callback failure, an expired authorization, a worker timeout, or no worker picking the run up. Rerun to try again.
Actions
- Cancel: stops a run that is waiting for OAuth, queued or running.
- Rerun: starts a new run with the same URL and stored credentials. It offers the latest protocol version again. When OAuth setup failed, the button is Configure new instead.
- Export: downloads the receipt of a finished run.
- Delete: removes a finished run and its transcript.
Transcript
The Transcript shows each step in order:
- every request (OUT), with its headers and JSON-RPC message;
- every response (IN), with its HTTP status, duration, headers and decoded JSON-RPC messages;
- system events (SYS), such as transport errors or a cancellation.
OAuth discovery appears only as summary events. The individual metadata, registration and token requests are not recorded.
Credentials are redacted before anything is stored:
- Credential-like headers and JSON fields become
[REDACTED]:Authorization,CookieandSet-Cookie,Mcp-Session-Id, API keys, passwords, secrets and tokens. - The exact values of your bearer token, custom headers and OAuth tokens are replaced wherever they appear, even in other fields.
A transcript holds up to 200 events. Strings over 32 KB are cut, and an event over 256 KB keeps only its summary.
Receipt export
Export downloads mcp-diagnostic-<run id>.json, built from the redacted data:
{
"format": "hooklistener.mcp_diagnostic",
"version": 1,
"exported_at": "2026-10-13T09:12:44Z",
"run": {
"target_url": "https://api.example.com/mcp",
"auth_type": "oauth",
"status": "completed",
"result_status": "passed",
"requested_protocol_version": "2025-11-25",
"negotiated_protocol_version": "2025-06-18",
"server_info": { "name": "example-mcp", "version": "1.4.0" },
"capabilities": { "tools": {} },
"checks": [ … ],
"discovery": { … }
},
"transcript": [ … ]
}
The run also includes its id, the names of the custom headers, any error code and message, and its timestamps. Each transcript event has its sequence number, phase, direction, method, JSON-RPC id, HTTP status, duration, headers, payload and time. Only signed-in members of the organization can download a receipt. There is no public link: share the file itself.
Limits
| Limit | Value |
|---|---|
| Runs per hour, per organization | Free: 10. Pro, Production and Scale: 60. |
| Connect timeout | 5 seconds |
| Request timeout | 20 seconds per request |
| Run timeout | 45 seconds for the whole run |
| Response size | 1 MB per response |
| Discovery | 10 pages and 500 items per list |
| Redirects | 3, same origin only |
| URL | 2,048 characters |
| Bearer token | 4,096 characters |
| Custom headers | 20 headers, 4 KB per value, 16 KB in total |
Every run created in the last hour counts toward the hourly limit, including reruns and failed or cancelled runs. When the limit is reached, the page shows Hourly run limit reached and Run diagnostic is disabled until older runs leave the one-hour window.
Retention
- Finished runs and their transcripts are kept for 30 days, then deleted. A run's stored bearer token and custom headers are deleted with it.
- An OAuth connection that no run uses any more is revoked and deleted 30 days after its last update.
- Deleting a run deletes its transcript, but not the OAuth connection. Use Disconnect for that.