MCP implementation reference

Testing an authenticated MCP server with MCP Inspector

How to use Inspector to prove that discovery, the OAuth flow, scopes, and audience binding actually work on your MCP server, instead of testing only the tools.

Updated July 2026Implementation guidemcp inspector
Built for

Engineers verifying a remote MCP server before handing it to users.

Decision supported

Whether your server's authentication behaves correctly against a real client rather than against curl.

The control gap

Inspector is usually used to list tools and call one. That exercises the least interesting half of a remote server. The half that fails in production is discovery, consent, scope enforcement, and audience checking, and Inspector can drive all of it because it is a real MCP client with an OAuth implementation. Testing with a hand-made bearer token skips exactly the paths that break.

What good looks like

A recorded session showing the 401 challenge, the discovery documents, the consent screen, the successful call, and the deliberate failures, all produced by a client rather than by a script.

  • Connect with no credential first, and read the challenge Inspector reports rather than assuming it exists.
  • Complete the OAuth flow from a clean profile so registration and consent are exercised, not replayed.
  • Test a narrowed scope explicitly, and confirm a write tool fails with an insufficient-scope response.
  • Point Inspector at one endpoint using a token obtained for another, and confirm the rejection.

A production workflow

  1. Start Inspector and enter the MCP endpoint URL with authentication left empty.
  2. Observe the 401 and the resource_metadata pointer, then let Inspector follow discovery and registration.
  3. Complete consent, list tools, and call one read-only tool.
  4. Repeat with a reduced scope and with a foreign token, recording both failures.

Copy this

Run these in order. The interesting output is the failures in steps 4 and 5, because a server that passes 1 to 3 can still fail both.

npx @modelcontextprotocol/inspector

1. Transport: Streamable HTTP
   URL: https://endram.com/mcp/billing-tools
   Auth: none
   EXPECT: 401, and a resource_metadata URL in the reported challenge

2. Let Inspector follow discovery
   EXPECT: it fetches /.well-known/oauth-protected-resource/mcp/billing-tools
           then /.well-known/oauth-authorization-server
           then registers dynamically and opens the consent screen

3. Consent, then List Tools, then call one read-only tool
   EXPECT: success, and a decision record on the server naming your user

4. Reconnect requesting scope "mcp:connect tools:read" only,
   then call a state-changing tool
   EXPECT: 403 with WWW-Authenticate insufficient_scope, scope="tools:call"

5. Reuse the token from step 3 against a different endpoint on the same host
   EXPECT: 401 invalid_token, because the audience does not match

Server-side, each of the five steps should have produced a log line.
A step that produced nothing is a gap in evidence, not a pass.

Step 5 is worth automating. It is the check that most often regresses quietly, because adding a second MCP endpoint to an existing deployment is exactly when a shared audience gets introduced.

Evidence to require

  • The Inspector session output for each step, kept with the release it tested.
  • Server-side records for the same five steps, matched by timestamp.
  • The scope set granted at consent, compared with the scope set requested.
  • The rejection reason recorded for the foreign-audience attempt.

Buyer checklist

  • Has anyone connected to this server with an unauthenticated client and read the actual challenge?
  • Does a reduced-scope consent genuinely block writes, or only hide the tools?
  • Is there a server-side record for every failed attempt, not only successful calls?
  • Would a second endpoint added next quarter share this one's audience?

Practical answers

Common implementation questions

Can Inspector replace a real client for acceptance testing?

For the protocol and authentication surface, yes. It performs discovery, registration, and the code flow the way a shipping client does. It does not tell you how a specific client renders consent or handles elicitation.

Should Inspector be exposed on a shared host?

No. Run it locally and bind to loopback. It is a debugging client holding live credentials, and it has no business being reachable from the network.

What if the server has no OAuth yet?

Inspector still connects with a static header, which is fine for early development. Just be clear that a passing session in that mode has tested the tools and none of the authorization behaviour.

Continue the evaluation

Related controls