Skip to content

feat!: support credentials per user for tools (with example implementation)#5

Merged
ciaransweet merged 2 commits into
mainfrom
credentials-per-user
Jun 12, 2026
Merged

feat!: support credentials per user for tools (with example implementation)#5
ciaransweet merged 2 commits into
mainfrom
credentials-per-user

Conversation

@ciaransweet

Copy link
Copy Markdown
Contributor

Per-user credentials for MCP toolsets

Tools can now act on behalf of the calling user instead of a shared
service identity. Credentials ride the MCP transport as HTTP headers —
they never appear in the model context, tool arguments, chat history or
traces.

How it works

  • Toolsets declare the headers they read via a CREDENTIAL_HEADERS
    export (validated by the contract test). Tools read values at call time
    with the new mcp_runtime.credentials helpers.
  • The platform advertises declarations through each service's
    /health and the index, so clients know which toolset needs which
    credential — and send each one only to the connections that declare
    it, never to unrelated toolsets.
  • Agents apply credentials per call, not per agent: the example agent
    is built once and injects the current user's headers at request time
    (user_credentials context manager + per-connection httpx client
    factories) — the shape a multi-user deployment needs. The Chainlit UI
    auto-generates a settings field for every advertised header.
  • mcp-cli gains curl-style -H/--header for driving credential
    tools from the terminal.

BREAKING: cds toolset now authenticates as the calling user

The shared CDS_API_KEY Secret is gone. Retrieve-API tools read the
caller's key from the x-cds-token header (sent upstream as
PRIVATE-TOKEN); clients are created per tool call so no state can leak
between users. search_datasets (public catalogue) still works without
credentials.

After deploy: callers must supply their own CDS key, and the unused
cds-credentials Secret can be deleted from the cluster.

Also included

  • toolsets/credential-demo — a minimal stubbed example (whoami) of
    the pattern, with credential-presence logging.
  • Friendlier connection failures in the agent CLI/UI (clear message plus
    a hint when the URL is missing its /mcp path, instead of an
    ExceptionGroup traceback).
  • Async fix: index/connection discovery no longer blocks the event loop

@j08lue j08lue left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this (passing credentials, via headers, to an MCP service to use inside tools) a pattern that exists elsewhere?

Not sure how else you'd do it. 😄 Just curious whether this is already something other clients than our bespoke frontend would support.

This would also work with a token from an auth redirect flow that the frontend performs against CDS IAM or so, right?

Comment thread packages/mcp-agent/src/mcp_agent/web.py
@ciaransweet

Copy link
Copy Markdown
Contributor Author

Is this (passing credentials, via headers, to an MCP service to use inside tools) a pattern that exists elsewhere?

Not sure how else you'd do it. 😄 Just curious whether this is already something other clients than our bespoke frontend would support.

This would also work with a token from an auth redirect flow that the frontend performs against CDS IAM or so, right?

As mentioned in slack, for history:

on your comment, it seems yes, the get_http_headers() expecting things like user keys is the common approach, the more bespoke part is the discoverability we have, but there doesn't appear to be a spec well adopted for advertising these kind of things.

What is a standard that we're not using (mainly because we don't need it) is there's an OAuth authorization model for MCP, but as we're not using an OAuth provider for any bits yet, we don't need it

@ciaransweet
ciaransweet force-pushed the credentials-per-user branch from 7dd0f81 to e260c3b Compare June 12, 2026 12:28
@ciaransweet
ciaransweet merged commit dcbab7e into main Jun 12, 2026
7 checks passed
@ciaransweet
ciaransweet deleted the credentials-per-user branch June 12, 2026 13:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants