Verify MCP server tokens with a direct API call first
You will test a token against its target API with a plain HTTP request before passing it into an MCP server or transport. This shows whether a failure comes from the token or from the MCP setup.
- Call API directlyConfirm the token works with a plain HTTP request
- Configure transportPass headers in the options object
- Read header in serverConfirm the server receives the Authorization header
- Remove debug loggingKeep credentials out of logs
Why it matters
When an MCP client sends a token and the server never receives it, the cause is often the transport setup rather than the token. In one TypeScript SDK case, the Authorization header never reached the server because the transport was built with three constructor arguments instead of two (issue 495 (opens external site)). Checking the token with a direct request first shows which layer is failing.
Steps
- Take the exact token your MCP config will use and call the target API with it from a plain HTTP client, outside any MCP code. Use one request to an endpoint that requires authentication.
- If the call returns 401 or 403, fix the token (expired, wrong scope, wrong audience) before you touch the MCP server.
- In the TypeScript SDK, pass the server URL as the first argument and put
sessionIdandrequestInit.headersinto one options object as the second argument (issue 495 (opens external site)):
const transport = new StreamableHTTPClientTransport(new URL(serverUrl), { sessionId: sessionId, requestInit: { headers: { Authorization: 'Bearer ' + token } } });
This fix was reported rather than officially verified, so confirm it against your own server.
4. Start the MCP server and make one tool call that needs the token. Confirm the server receives the Authorization header before you debug anything else.
5. For reading headers inside a tool, the examples in issue 750 (opens external site) use the fastmcp package, not the plain Python SDK. With fastmcp, define the tool with a Context parameter and read context.request_context.request.headers.get("example-header"). Reading headers directly in the plain Python SDK is tracked separately in issue #2098.
6. Once the call works, remove any temporary logging of requests before you ship.
Common mistakes
- Logging full fetch arguments while debugging. The Authorization header can end up in your logs (issue 495 (opens external site)), so log only status codes and header names.
- Using a dynamic client registration token as if it were an API token. The TypeScript SDK's initial access token request was closed with CIMD recommended as the alternative (opens external site), so plan your registration flow around that.
- Treating a reported fix as confirmed. Test it against your own server before relying on it.
Checklist guidance
Work through the checklist below before you rely on a configuration in production.
Checklist
0 of 7 done