Make stdio MCPs Editable#1219
Conversation
Greptile SummaryThis PR adds a full edit UI for stdio MCP sources, replacing the previous read-only view. When process-affecting fields change (command, args, env, cwd), the server runs a preflight tool-discovery check before committing the change in a transaction that also clears source-scoped policies, then does a best-effort tools refresh.
Confidence Score: 5/5Safe to merge; both findings are edge-case UX gaps, not correctness or data-safety regressions. The preflight → transaction → best-effort refresh pipeline is well-structured and thoroughly tested. Both findings are minor edge-case gaps that do not affect the primary edit flow. packages/plugins/mcp/src/sdk/plugin.ts — the zero-connections branch of refreshStdioConnections; packages/plugins/mcp/src/react/EditMcpSource.tsx — the missing retry UI for toolsRefreshFailed. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant UI as StdioEdit (UI)
participant API as configureServer API
participant Plugin as mcpPlugin
participant DB as Storage/Policies
participant Proc as stdio subprocess
UI->>API: POST /mcp/servers/:slug/config
API->>Plugin: configureServer(slug, config)
Plugin->>DB: get integration record
DB-->>Plugin: current config
alt process config unchanged
Plugin->>DB: integrations.update(config)
Plugin-->>API: toolsRefreshFailed false
else process config changed
Plugin->>Proc: preflightStdioConfig discoverTools
Proc-->>Plugin: tools list OK or error
alt preflight fails
Plugin-->>API: error
API-->>UI: 4xx
else preflight OK
Plugin->>DB: transaction removePolicies and update config
DB-->>Plugin: committed
Plugin->>Proc: refreshStdioConnections
Proc-->>Plugin: OK or failure
Plugin-->>API: toolsRefreshFailed true or false
API-->>UI: 200
end
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant UI as StdioEdit (UI)
participant API as configureServer API
participant Plugin as mcpPlugin
participant DB as Storage/Policies
participant Proc as stdio subprocess
UI->>API: POST /mcp/servers/:slug/config
API->>Plugin: configureServer(slug, config)
Plugin->>DB: get integration record
DB-->>Plugin: current config
alt process config unchanged
Plugin->>DB: integrations.update(config)
Plugin-->>API: toolsRefreshFailed false
else process config changed
Plugin->>Proc: preflightStdioConfig discoverTools
Proc-->>Plugin: tools list OK or error
alt preflight fails
Plugin-->>API: error
API-->>UI: 4xx
else preflight OK
Plugin->>DB: transaction removePolicies and update config
DB-->>Plugin: committed
Plugin->>Proc: refreshStdioConnections
Proc-->>Plugin: OK or failure
Plugin-->>API: toolsRefreshFailed true or false
API-->>UI: 200
end
end
Reviews (5): Last reviewed commit: "Don't use lossy args.join for StdioEdit,..." | Re-trigger Greptile |
…ld return the exact same value, otherwise emit a double-quoted escaped value
…t with those stored values
c2c0e59 to
775e9e3
Compare
… up in a weird state
… changes as process-affecting, fix some comments
Makes stdio MCP sources editable via the GUI.
I tried to match existing behavior so it should be pretty intuitive. After a STDIO MCP config is changed, we validate first with tool discovery (require successful
tools/list), then if that succeeds run a transaction to remove policies scoped to the integration and update the integration config.For legacy configs where there are no visible connections, connection
org/defaultwith templatenoneand empty values will be created.