Repository navigation
Conversation
An MCP upload plan tells the agent to PUT each file with the bearer it used
on /mcp ("reuse_the_mcp_bearer_credential"). With a hosted OAuth provider
(generic OIDC or WorkOS), /mcp accepts the end-user access token, but the
upload URL is under /api, whose bearer check accepts only managed API keys.
So an agent signed in only through OAuth could plan an upload but never
write its files, and could not publish.
The staged-upload file write (PUT /api/v1/uploads/:uploadId/files/:token)
now authenticates its bearer exactly as /mcp does. That is a superset of the
API-credential path for that route: the same local token and managed keys,
plus the hosted access token for the exact <origin>/mcp resource. Upload
ownership is unchanged, because StagedUploadService still binds every file
to the principal that created the plan. Every other API route keeps the
API-credential contract.
Tests (generic OIDC):
- an OIDC access token plans, uploads and publishes over MCP
(fails before this change with 401 on the file write);
- the same token gets 401 on other API routes (api-keys, REST upload
creation), cannot write another principal's upload, and wrong-audience,
ID, and expired tokens are refused on the file write.
|
Verified against a real deployment: Keycloak 26.5, Helm chart v0.1.2, Postgres, S3-compatible object storage. The image was v0.1.2 plus this commit.
Separately, unrelated to this PR: v0.1.2's |
Problem
With a hosted OAuth provider (generic OIDC or WorkOS),
/mcpaccepts the end-user access token for<origin>/mcp.artifact_create_uploadthen returns upload URLs under/api/v1/uploads/.../files/...and tells the agent toPUTeach file withreuse_the_mcp_bearer_credential. But/apibearer auth (authenticateApiBearer) accepts only managedas_key_keys and the local token, so thatPUTfails with401 A valid Artifact Server API key is required.So an agent connected only through OAuth can plan an upload but never publish. We hit this on a self-hosted Keycloak deployment (v0.1.2): an OAuth device-grant token with the exact
/mcpaudience got throughinitialize,tools/list,artifact_capabilitiesandartifact_create_upload, then got a 401 on the filePUT.Change
The staged-upload file write (
PUT /api/v1/uploads/:uploadId/files/:storageToken, the URL the MCP upload plan hands out) now authenticates its bearer exactly as/mcpdoes (authenticateMcpBearer):<origin>/mcpresource, with the same issuer, audience, token-type and expiry checks.StagedUploadServicestill binds every file to the principal that created the plan./apiroute keeps the API-credential contract.Docs:
docs/deployment.md(generic OIDC section) anddocs/mcp.md(publish steps) now state that the uploadPUTuses the MCP bearer.Requirement IDs
MCP-013 (self-hosted MCP through a generic OIDC issuer). The new tests carry no ID prefix, because MCP-013-B/F are already claimed in
oidc-mcp-authorization.test.tsandcheck-conformance-test-ids.rballows one test per ID.Tests
New, in
tests/conformance/oidc-mcp-authorization.test.ts:an OIDC access token uploads and publishes the files of its own MCP upload plan: plans over MCP,PUTs with the OIDC token, commits. Fails without this change (401 on thePUT).an OIDC access token opens no other API route, no other principal's upload, and no wrong resource:GET /api/v1/api-keysandPOST /api/v1/uploads;/mcp-of-another-origin, ID-token and expired tokens get 401 on the file write.Ran:
pnpm lint,pnpm typecheck: pass.ruby scripts/check-conformance-test-ids.rb: "Valid conformance test mapping: 256 acceptance tests have one implementation test."pnpm exec vitest runon the oidc-mcp-authorization, staged-upload-lifecycle, mcp-modern-http, workos-mcp-authorization and installation-identity suites: 34/34 pass.vitest run: 328/331. The 3 failures are intests/cli/*and are unrelated:local-cli.test.ts > opens the managed application at a credential-free URLfails identically on unmodified v0.1.2 in this environment.Not run:
pnpm verify:iteration(needs Docker image pulls not available here) andtest:oidc(real Keycloak harness). I did verify the behaviour against a real Keycloak 26.5 deployment with the patched image; details in a follow-up comment.Deployment effects
None beyond the above: no migration and no configuration change. Operators of OIDC/WorkOS installations get OAuth-only MCP publishing.