feat: per-user (BYOK) MCP credentials#28
Open
krrish-berri-2 wants to merge 1 commit into
Open
Conversation
Adds LiteLLM-compatible per-user credentials so a single gateway can proxy MCP servers where each user brings their own upstream key (e.g. Gmail for an inbox-triage agent). Builds on the Postgres layer from #20. - config: `is_byok` on mcp_servers (+ byok_description/help_url); validation requires master_key + database_url and forbids a shared auth_value. - storage: users + verification-token + encrypted credential tables (AES-256-GCM, key = SHA-256(master_key)); static and OAuth2 token sets. - identity: master key = admin; database-backed keys = users. - endpoints (LiteLLM surface): POST /user/new, POST /key/generate, GET /v1/mcp/user-credentials, {POST,GET,DELETE} /v1/mcp/server/{id}/user-credential, {POST,DELETE} /v1/mcp/server/{id}/oauth-user-credential (+ /status). - injection: BYOK servers require a user key; the caller's decrypted token is built into the upstream auth header per request (missing -> 401). Tests: BYOK config validation, AES-GCM roundtrip, and a Postgres-gated integration test proving the stored token is injected upstream.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lets one gateway proxy MCP servers where each user brings their own upstream credential — the building block for a per-user inbox-triage agent (Gmail) driven by the Claude schedule skill. Mirrors LiteLLM's BYOK /
user-credentialsurface. Builds on the Postgres layer from #20.When a server is marked
is_byok, there is no sharedauth_value. Each user:POST /user/new),POST /v1/mcp/server/{id}/user-credential),Tokens are encrypted at rest (AES-256-GCM, key =
SHA-256(master_key)). The master key is admin, not a user, and cannot call BYOK servers directly.Config
Endpoints (LiteLLM-compatible)
/user/new,/key/generate/v1/mcp/user-credentials/v1/mcp/server/{id}/user-credential/v1/mcp/server/{id}/oauth-user-credential(+/status)Validation
cargo fmt --all --checkcargo clippy --all-targets -- -D warningscargo test(full suite, Postgres viaTEST_DATABASE_URL,--test-threads=1) — 39 tests green, incl. BYOK config validation, AES-GCM roundtrip, and a Postgres integration test that proves the stored token is injected upstream.Runtime evidence (live, real Gmail OAuth token)
Ran the gateway against a local upstream that logs the
Authorizationheader it receives.Header the upstream MCP server actually received (token truncated):
Same token, encrypted at rest in Postgres — 281 bytes of ciphertext; decoding as UTF-8 fails (
invalid byte sequence 0x84), confirming it is not stored in plaintext:Notes / deferred
main); migration0002adds user + credential tables to the samemigrate!dir.docs/mcp.md): OAuth token refresh, the browser/{server}/authorizeflow, API-key hashing, and the DB-managedPOST /v1/mcp/serverregistry. Path form is/mcp/{server}(existing), not LiteLLM's/{server}/mcp.