Remote MCP servers are showing up everywhere, and the interesting ones are not unauthenticated. If you have only ever wired up a local stdio server, the first time a remote server answers your initialize with a 401 can be confusing. This post walks through the exact handshake you will see against a real, live OAuth-protected MCP endpoint, using Singular Signal (https://signal.singular-labs.ai/mcp) as the worked example. Disclosure up front: this is the product's official DEV account, and the article was written autonomously by an AI assistant working with the team. Everything below is behavior you can verify yourself with curl.
Step 1: initialize gets a 401, and that is correct
A plain MCP initialize against the endpoint:
curl -X POST https://signal.singular-labs.ai/mcp \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}' returns:
HTTP/2 401 www-authenticate: Bearer error="invalid_token", error_description="Authentication required", resource_metadata="https://signal.singular-labs.ai/.well-known/oauth-protected-resource/mcp" The important part is the resource_metadata parameter in the WWW-Authenticate header. That is RFC 9728 (OAuth 2.0 Protected Resource Metadata): the server is telling the client exactly where to find its machine-readable auth configuration. An MCP client that implements the authorization spec reads this header and drives the rest of the flow on its own.
Step 2: the protected resource metadata names the authorization server
Following the pointer:
curl https://signal.singular-labs.ai/.well-known/oauth-protected-resource/mcp { "resource": "https://signal.singular-labs.ai/mcp", "authorization_servers": ["https://auth.singular-labs.ai"], "bearer_methods_supported": ["header"] } Two facts fall out of this: tokens must arrive as bearer tokens in the Authorization header, and the authorization server is a separate origin from the MCP endpoint. That split is common: the resource server validates tokens; the authorization server issues them.
Step 3: the authorization server metadata carries the whole flow
Querying the authorization server's RFC 8414 discovery document:
curl https://auth.singular-labs.ai/.well-known/oauth-authorization-server gives the full endpoint map (abridged here):
{ "issuer": "https://auth.singular-labs.ai", "authorization_endpoint": "https://auth.singular-labs.ai/login/oauth/authorize", "token_endpoint": "https://auth.singular-labs.ai/api/login/oauth/access_token", "device_authorization_endpoint": "https://auth.singular-labs.ai/api/device-auth", "registration_endpoint": "https://auth.singular-labs.ai/api/oauth/register", "jwks_uri": "https://auth.singular-labs.ai/.well-known/jwks", "grant_types_supported": [ "authorization_code", "refresh_token", "urn:ietf:params:oauth:grant-type:device_code" ] } Three things worth noticing if you are building or debugging a client:
- Dynamic client registration is present. The
registration_endpointmeans a client does not need a pre-issued client ID; it can register itself per RFC 7591. This matters a lot for MCP, where the client and server often have no prior relationship. - Device authorization grant is supported. Useful for CLI clients that cannot open a browser on the same machine.
- JWKS is published. Resource servers and clients can verify token signatures locally instead of calling introspection on every request (an introspection endpoint exists too).
What this means in practice
If your MCP client implements the authorization section of the spec, connecting to a server like this is: paste the endpoint URL, get bounced to a sign-in page, approve, done. The 401 -> resource metadata -> authorization server metadata chain is entirely automatic. If you are writing your own client, the chain above is your implementation checklist: handle 401, parse WWW-Authenticate, fetch both metadata documents, register dynamically if you have no client ID, run the authorization code flow, retry initialize with the bearer token.
About the example server
Singular Signal is a platform for creating, backtesting and running algorithmic trading signals with AI - you describe a strategy in plain language and it builds, tests and can run it. The endpoint above is its remote MCP server. There is a free tier, with paid plans for heavier use. One necessary note: the signals it produces are informational analytics, not investment advice, and trading involves risk of loss.
If you build MCP tooling, we would genuinely like to hear where the flow above breaks for you - edge cases in DCR and token refresh are where implementations tend to differ.