motiondivision / motiondivision/ai-kit

Unauthenticated GET returns 200 without the MCP Accept header, hiding the 401 OAuth challenge

Open
#2 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
8
Forks
1
PR merge metrics
No merged PRs in 30d

Description

Summary

Since the fix for #1, both protected-resource metadata documents resolve correctly. A related gap remains one layer up: an unauthenticated GET https://mcp.motion.dev/plus sent without MCP accept types returns 200 and a JSON server description, with no WWW-Authenticate header. The 401 OAuth challenge is only reachable when the request carries Accept: application/json, text/event-stream (or is a POST).

Clients whose OAuth discovery probe is a plain GET therefore never see the challenge. Some of them parse that 200 body as RFC 9728 protected-resource metadata and fail confusingly, because the description document has no resource field.

Reproduction

$ curl -sS -o /dev/null -w '%{http_code}\n' https://mcp.motion.dev/plus
200

$ curl -sS -o /dev/null -w '%{http_code}\n' \
    -H 'Accept: application/json, text/event-stream' https://mcp.motion.dev/plus
405

$ curl -sS https://mcp.motion.dev/plus | jq 'keys'
["description","docs","name","protocolVersion","tools","transport"]

No WWW-Authenticate header is present on the 200. The challenge does appear on a POST:

$ curl -sS -o /dev/null -D - -X POST https://mcp.motion.dev/plus \
    -H 'Accept: application/json, text/event-stream' -H 'Content-Type: application/json' \
    -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}'
HTTP/2 401
www-authenticate: Bearer realm="motion", resource_metadata="https://mcp.motion.dev/.well-known/oauth-protected-resource/plus"

The base server behaves the same way (no-Accept=200, with-Accept=405), though it matters less there since it serves tools unauthenticated.

Impact

Codex CLI is a concrete case. codex mcp login motion-plus fails with:

Error: Metadata error: Protected resource metadata missing required resource field

Codex's discovery probe is a plain GET with no Accept header (openai/codex#37830), so it receives the 200 description document and parses it as protected-resource metadata. The error names a metadata document that was never fetched, which sent me a long way down the wrong path before I compared the two responses.

Forcing the accept types makes login succeed on the first attempt:

[mcp_servers.motion-plus]
url = "https://mcp.motion.dev/plus"
http_headers = { "Accept" = "application/json, text/event-stream" }

That is a client-side workaround for a specific client. Any other client that probes with a plain GET hits the same wall.

Expected

An unauthenticated request to a protected MCP endpoint should return 401 with WWW-Authenticate regardless of the Accept header, so auth discovery can find the challenge by the documented path.

If the descriptive JSON is worth keeping, serving it from a separate unprotected URL (or gating it behind an explicit Accept: application/json alone) would preserve it without masking the challenge.

Environment

  • Codex CLI 0.149.1, macOS 26.5.1 arm64
  • Signed-in Motion account without Motion+ (correcting an earlier version of this issue that said otherwise). The OAuth flow itself completes; entitlement is separate and does not affect anything above, since the reproduction is unauthenticated.
  • Verified 2026-08-24, after #1 was closed. Both /.well-known/oauth-protected-resource and /.well-known/oauth-protected-resource/plus return 200 with a valid resource field.
  • The 200/405 split reproduced 5 times out of 5.

Happy to test a fix.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the unauthenticated request handling for the /plus MCP endpoint and reproduce the no-Accept, MCP-Accept, and POST curl cases described here. Done means an unauthenticated GET receives 401 with the documented WWW-Authenticate challenge regardless of Accept, without masking the existing protected-resource metadata behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
api, authentication
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.