Skip to content

OAuth flow requests only offline_access scope — all project-internal MCP endpoints return 403 #32

Description

@markushausammann

The MCP plugin (v0.1.0) can list organizations and projects but cannot read into any project. Every project-internal endpoint returns HTTP 403 with Unauthorized: collection_index_view failed permission check, regardless of the user's actual permissions.

Environment

  • Plugin: upsun/ai @ v0.1.0 (installed via Claude Code marketplace)
  • Claude Code host: macOS, Darwin 25.4.0
  • User: organization owner of the org being queried, full rights via the Upsun console and upsun CLI

Steps to reproduce

  1. Install the plugin and authenticate via the MCP's OAuth flow.
  2. Optionally also set UPSUN_API_TOKEN in the environment so the upsun-api-token header is populated.
  3. Call any project-internal MCP tool, e.g. list-environment, list-domain, list-certificate, list-activity, info-project.

Expected

Tool returns project data — same data the user can read via upsun environment:list etc.

Actual

HTTP 403 Forbidden
{
  "status": "error",
  "code": 403,
  "title": "Forbidden",
  "message": "Access was denied to this resource.",
  "detail": {
    "error": "Unauthorized: collection_index_view failed permission check"
  }
}

Reproduced against multiple projects under the same organization, ruling out a per-project ACL issue. list-organization and list-project work fine.

Root cause (suspected)

The OAuth authorize URL emitted by authenticate requests only scope=offline_access:

https://auth.upsun.com/oauth2/authorize?...&scope=offline_access&...

offline_access only grants refresh-token capability — no project-data scope is requested, so the resulting access token cannot read project resources.

Setting UPSUN_API_TOKEN (so the upsun-api-token header carries a valid personal API token) does not change the outcome — the header path appears to be ignored, or is gated by the same scope check.

Suggested fixes

  1. Have the OAuth client request the scopes needed to read project resources (e.g. project:read, or whatever the equivalent is on auth.upsun.com).
  2. Document and honor the upsun-api-token header as a working alternative to OAuth — at the moment its presence has no visible effect on project-content endpoint authorization.
  3. Surface the enable-write header in plugin.json as a configurable plugin option. Currently it is hardcoded "false" in .mcp.json and /plugin provides no UI to toggle it. (Lower priority than the read scope, since reads themselves are blocked first.)

Workaround

Use the upsun CLI directly (upsun login produces a session with full delegated rights). The plugin's upsun skill already recommends this — but the MCP tools should be usable on their own merit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions