Skip to content

App 2052/optionally sync mcp config with secrets#1001

Open
HeyItsChloe wants to merge 3 commits into
mainfrom
APP-2052/optionally-sync-mcp-config-with-secrets
Open

App 2052/optionally sync mcp config with secrets#1001
HeyItsChloe wants to merge 3 commits into
mainfrom
APP-2052/optionally-sync-mcp-config-with-secrets

Conversation

@HeyItsChloe
Copy link
Copy Markdown
Member

@HeyItsChloe HeyItsChloe commented Jun 1, 2026

  • A human has tested these changes.

Why

MCP server config and the Secrets store are entirely separate. When a user
installs an MCP server that requires credentials (API keys, tokens, etc.),
those values are written only into mcp_config and are therefore invisible
to the Automation Server when running automations. Users had to re-enter the
same credentials manually in Settings → Secrets, with no indication that this
step was necessary.

Summary

  • Adds an "Also save as secret" toggle to every envField in the MCP
    install modal. Password-type fields are pre-checked; non-password fields
    default to off. On successful install, checked fields are fire-and-forget
    upserted to the Secrets store so the Automation Server can access them
    immediately.

Issue Number

https://linear.app/all-hands-ai/issue/APP-2052/mcp-server-configuration-form-should-allow-setting-secrets-needed-by
#926

How to Test

  1. npm install && npm run dev
  2. Open the MCP page and click Install on any stdio-based server
    (e.g. Slack, Tavily).
  3. Confirm each envField shows an "Also save as secret" toggle.
    Password-type fields should be pre-checked; plain-text fields should be
    unchecked.
  4. Toggle fields on/off as desired, fill in credentials, and click Install.
  5. After the modal closes, navigate to Settings → Secrets and confirm the
    checked fields appear with the field label as their description.
  6. To verify the unhappy path: disconnect from the network, install a server
    with a checked toggle, and confirm the modal still closes and a toast
    error appears — no modal-level error is shown.

Video/Screenshots

https://github.com/user-attachments/assets/116ec279-fc28-484a-8165-d3e5c6fc4a80
Screenshot 2026-06-01 at 3 03 59 PM

Type

  • Bug fix
  • Feature
  • Refactor
  • Breaking change
  • Docs / chore

Notes

  • The secret save is intentionally fire-and-forget and runs after
    onClose(), so a Secrets API failure never blocks the MCP install flow.
  • SecretsService.createSecret is an upsert internally; re-installing a
    server overwrites the existing secret for that key name rather than
    creating a duplicate.
  • The toggle only appears on envFields (environment variables / credentials).
    argFields are CLI positional arguments and are not candidates for secret
    storage.
  • 35 / 35 unit tests pass; lint and TypeScript are clean.

🐳 Docker images for this PR

GHCR package: https://github.com/OpenHands/agent-canvas/pkgs/container/agent-canvas

Component Value
Image ghcr.io/openhands/agent-canvas
Architectures amd64, arm64
Agent Server ghcr.io/openhands/agent-server:1.24.0-python
Automation openhands-automation==1.0.0a5
Commit aadce623c2b6e78c924ba33c44d75bcfb89b2a40

Pull (multi-arch manifest)

# Multi-arch manifest — Docker automatically pulls the correct architecture
docker pull ghcr.io/openhands/agent-canvas:sha-aadce62

Run

docker run -it --rm \
  -p 8000:8000 \
  ghcr.io/openhands/agent-canvas:sha-aadce62

All tags pushed for this build

ghcr.io/openhands/agent-canvas:sha-aadce62-amd64
ghcr.io/openhands/agent-canvas:APP-2052-optionally-sync-mcp-config-with-secrets-amd64
ghcr.io/openhands/agent-canvas:pr-1001-amd64
ghcr.io/openhands/agent-canvas:sha-aadce62-arm64
ghcr.io/openhands/agent-canvas:APP-2052-optionally-sync-mcp-config-with-secrets-arm64
ghcr.io/openhands/agent-canvas:pr-1001-arm64
ghcr.io/openhands/agent-canvas:sha-aadce62
ghcr.io/openhands/agent-canvas:APP-2052-optionally-sync-mcp-config-with-secrets
ghcr.io/openhands/agent-canvas:pr-1001

About Multi-Architecture Support

  • Each tag (e.g., sha-aadce62) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., sha-aadce62-amd64) are also available if needed

HeyItsChloe and others added 2 commits June 1, 2026 13:19
…add tests

- useSaveFieldsAsSecrets: wrap returned fn in useCallback for stable identity,
  pass field.label as secret description, truncate key lists >3 in toasts,
  update JSDoc to document upsert behaviour
- SaveAsSecretToggle: replace hidden input with sr-only for AT accessibility,
  move data-testid to label, add aria-hidden to decorative track, replace
  div with button for keyboard-reachable info trigger with aria-label
- InstallServerModal: add stateRef to avoid stale closure in onSuccess
  callback, add comment explaining why argFields have no secret toggle
- translation.json: plural-safe English wording for MCP$SECRETS_SAVED
- tests: add use-save-fields-as-secrets.test.ts (9 tests), add
  save-as-secret-toggle.test.tsx (9 tests), extend install-server-modal
  with save-as-secret describe block (8 tests); 35/35 pass

Co-authored-by: openhands <openhands@all-hands.dev>
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agent-canvas Ready Ready Preview, Comment Jun 1, 2026 9:59pm

Request Review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

✅ Mock-LLM Docker E2E Test Results

12/12 passed

Commit: b3d2178a · Workflow run · Test artifacts

Status Test Duration
mock-llm-auth-modes.spec.ts › auth mode: non-public key rotation › recovers when localStorage has a stale session API key 3.8s
mock-llm-auth-modes.spec.ts › auth mode: public gate › shows the auth screen when no key is configured 1.2s
mock-llm-auth-modes.spec.ts › auth mode: public gate › rejects an incorrect key with an inline error 1.3s
mock-llm-auth-modes.spec.ts › auth mode: public gate › allows access after pasting the correct key 1.8s
mock-llm-auth-modes.spec.ts › auth mode: public gate › re-prompts when the server rotates its key (stale localStorage) 1.5s
mock-llm-automation.spec.ts › mock-LLM automation lifecycle › step 1: setup LLM profile and register automation trajectory 231ms
mock-llm-automation.spec.ts › mock-LLM automation lifecycle › step 2: create automation and dispatch run via the UI 27.8s
mock-llm-automation.spec.ts › mock-LLM automation lifecycle › step 3: verify automation and run on the automations page 4.2s
mock-llm-conversation.spec.ts › mock-LLM agent-server conversation › step 1: create an LLM profile pointing at the mock LLM server 4.2s
mock-llm-conversation.spec.ts › mock-LLM agent-server conversation › step 2: activate the mock-llm profile and verify settings API 4.3s
mock-llm-conversation.spec.ts › mock-LLM agent-server conversation › step 3: run a conversation with the mock LLM 4.4s
mock-llm-conversation.spec.ts › mock-LLM agent-server conversation › step 4: resume conversation from sidebar after navigating away 3.7s

Posted by the Mock-LLM E2E workflow · results are deterministic (scripted LLM responses)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

✅ Mock-LLM Docker E2E Test Results

12/12 passed

Commit: aadce623 · Workflow run · Test artifacts

Status Test Duration
mock-llm-auth-modes.spec.ts › auth mode: non-public key rotation › recovers when localStorage has a stale session API key 3.8s
mock-llm-auth-modes.spec.ts › auth mode: public gate › shows the auth screen when no key is configured 1.2s
mock-llm-auth-modes.spec.ts › auth mode: public gate › rejects an incorrect key with an inline error 1.4s
mock-llm-auth-modes.spec.ts › auth mode: public gate › allows access after pasting the correct key 1.8s
mock-llm-auth-modes.spec.ts › auth mode: public gate › re-prompts when the server rotates its key (stale localStorage) 1.5s
mock-llm-automation.spec.ts › mock-LLM automation lifecycle › step 1: setup LLM profile and register automation trajectory 463ms
mock-llm-automation.spec.ts › mock-LLM automation lifecycle › step 2: create automation and dispatch run via the UI 29.8s
mock-llm-automation.spec.ts › mock-LLM automation lifecycle › step 3: verify automation and run on the automations page 4.1s
mock-llm-conversation.spec.ts › mock-LLM agent-server conversation › step 1: create an LLM profile pointing at the mock LLM server 4.2s
mock-llm-conversation.spec.ts › mock-LLM agent-server conversation › step 2: activate the mock-llm profile and verify settings API 4.4s
mock-llm-conversation.spec.ts › mock-LLM agent-server conversation › step 3: run a conversation with the mock LLM 4.3s
mock-llm-conversation.spec.ts › mock-LLM agent-server conversation › step 4: resume conversation from sidebar after navigating away 3.7s

Posted by the Mock-LLM E2E workflow · results are deterministic (scripted LLM responses)

github-actions Bot added a commit that referenced this pull request Jun 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

📸 Snapshot Test Report

Warning

Snapshot comparison step crashed (timeout, OOM, or runner error) — diff results below may be incomplete or absent.
Check the CI logs for the full error output (look for the "Run snapshot comparison" step).

❌ 1 snapshot differ from the main branch baseline. Add the update-snapshots label to acknowledge intentional changes.

Category Count
🔴 Changed 1
🆕 New 0
✅ Unchanged 72
Total 73

How to resolve:

  • Unintentional diffs — the baselines on main may have moved since this branch was created. Merge the latest main into this branch and re-run CI.
  • Intentional changes — add the update-snapshots label. CI will pass and the new screenshots become the baseline when this PR merges.
🔴 Changed snapshots (1)

mcp-page

mcp-slack-install-2-modal

Expected (main) Actual (PR) Diff
expected actual diff
✅ Unchanged snapshots (72)

archived-conversation

  • conversation-panel-with-archived-badges
  • conversation-view-archived
  • conversation-view-sandbox-error

automations

  • automations-delete-modal
  • automations-list-active-inactive
  • automations-no-automations
  • automations-search-no-results

backends-extended

  • backend-add-blank-disabled
  • backend-add-cloud-advanced-open
  • backend-add-cloud-no-key-disabled
  • backend-add-cloud-with-key-enabled
  • backend-add-form-partially-filled
  • backend-add-invalid-url-disabled
  • backend-add-local-ready
  • backend-add-name-only-disabled
  • backend-add-two-column-layout
  • backend-add-whitespace-host-disabled
  • backend-after-switch
  • backend-cancel-nothing-saved
  • backend-dropdown-two-backends
  • backend-edit-prefilled
  • backend-manage-after-removal
  • backend-manage-two-listed
  • backend-remove-cancelled
  • backend-remove-confirmation
  • backend-switch-overlay

backends

  • backend-add-modal
  • backend-manage-modal
  • backend-selector-open

changes-tab

  • changes-deleted-file
  • changes-diff-viewer
  • changes-empty

collapsible-thinking

  • reasoning-content-collapsed
  • reasoning-content-expanded
  • think-action-collapsed
  • think-action-expanded

mcp-page

  • mcp-custom-server-1-editor-open
  • mcp-custom-server-2-url-filled
  • mcp-custom-server-3-all-filled
  • mcp-custom-server-4-installed
  • mcp-custom-server-editor
  • mcp-empty-installed
  • mcp-search-filtered
  • mcp-slack-install-1-marketplace
  • mcp-slack-install-3-filled
  • mcp-slack-install-4-installed

onboarding

  • onboarding-step-0-choose-agent
  • onboarding-step-1-check-backend
  • onboarding-step-2-setup-llm
  • onboarding-step-3-say-hello

projects-workspace-browser

  • projects-workspace-browser

settings-page

  • add-backend-modal
  • analytics-consent-modal
  • home-screen
  • settings-app-page
  • settings-page

settings-secrets

  • secrets-add-form-filled
  • secrets-add-form
  • secrets-after-save
  • secrets-delete-confirm
  • secrets-list

settings-verification

  • condenser-settings
  • verification-settings-off
  • verification-settings-on

sidebar

  • sidebar-collapsed
  • sidebar-conversation-panel
  • sidebar-filter-menu

skills-page

  • skills-empty
  • skills-loaded
  • skills-no-match
  • skills-search-filtered
  • skills-type-filter

Generated by the Snapshot Tests workflow. This comment was created by an AI agent (OpenHands) on behalf of the repo maintainers.

@HeyItsChloe
Copy link
Copy Markdown
Member Author

"Save As A Secret" Toggle render conditions: a field renders the toggle if and only if it was an envField at init time.

WILL render:
stdio envFields — every field in template.envFields[]
- starts CHECKED when field.type === "password"
- starts UNCHECKED when field.type === "text" (or any other value)

WILL NOT render:
stdio argFields — never given a savedAsSecret key
- shttp / sse api_key — no savedAsSecret entry is created for shttp/sse transports at all
- command, url — readonly/disabled display fields, never in state

@HeyItsChloe HeyItsChloe marked this pull request as ready for review June 1, 2026 22:55
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