Improve MCP settings auth flow, remote config support, and diagnostics UX (#953)
* feat: improve MCP settings auth workflow * fix: complete MCP settings auth flow * fix: harden MCP settings auth flow * fix: add MCP settings refresh control * fix: stabilize MCP authorization and status handling * fix: clarify MCP advanced remote options toggle * fix: improve MCP import and diagnostics * feat: improve MCP settings panel visual hierarchy and UX * fix: expose MCP auth actions in connected state * fix: remove MCP import snippet helper text * fix: address MCP review feedback * fix: correct MCP page transport layout after rebase
This commit is contained in:
@@ -18,6 +18,8 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
||||
} = dependencies;
|
||||
|
||||
let authLibrary = null;
|
||||
const pendingMcpAuthContextByState = new Map();
|
||||
const PENDING_MCP_AUTH_TTL_MS = 30 * 60 * 1000;
|
||||
const getAuthLibrary = async () => {
|
||||
if (!authLibrary) {
|
||||
authLibrary = await import('./auth.js');
|
||||
@@ -25,6 +27,24 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
||||
return authLibrary;
|
||||
};
|
||||
|
||||
const normalizePendingString = (value) => {
|
||||
if (typeof value !== 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const trimmed = value.trim();
|
||||
return trimmed || null;
|
||||
};
|
||||
|
||||
const pruneExpiredPendingMcpAuthContexts = () => {
|
||||
const now = Date.now();
|
||||
for (const [state, entry] of pendingMcpAuthContextByState.entries()) {
|
||||
if (!entry || typeof entry.expiresAt !== 'number' || entry.expiresAt <= now) {
|
||||
pendingMcpAuthContextByState.delete(state);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
app.get('/api/config/settings', async (_req, res) => {
|
||||
try {
|
||||
const settings = await readSettingsFromDiskMigrated();
|
||||
@@ -59,6 +79,76 @@ export const registerOpenCodeRoutes = (app, dependencies) => {
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/mcp/auth/pending', async (req, res) => {
|
||||
try {
|
||||
pruneExpiredPendingMcpAuthContexts();
|
||||
|
||||
const state = normalizePendingString(req.body?.state);
|
||||
if (!state) {
|
||||
return res.json({ success: true, context: null });
|
||||
}
|
||||
|
||||
const name = normalizePendingString(req.body?.name);
|
||||
if (!name) {
|
||||
return res.status(400).json({ error: 'MCP server name is required' });
|
||||
}
|
||||
|
||||
const entry = {
|
||||
name,
|
||||
directory: normalizePendingString(req.body?.directory),
|
||||
expiresAt: Date.now() + PENDING_MCP_AUTH_TTL_MS,
|
||||
};
|
||||
pendingMcpAuthContextByState.set(state, entry);
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
context: {
|
||||
name: entry.name,
|
||||
directory: entry.directory,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to store pending MCP auth context:', error);
|
||||
return res.status(500).json({ error: error.message || 'Failed to store pending MCP auth context' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/mcp/auth/pending', async (req, res) => {
|
||||
try {
|
||||
pruneExpiredPendingMcpAuthContexts();
|
||||
|
||||
const state = normalizePendingString(Array.isArray(req.query?.state) ? req.query.state[0] : req.query?.state);
|
||||
if (!state) {
|
||||
return res.json(null);
|
||||
}
|
||||
|
||||
const pendingMcpAuthContext = pendingMcpAuthContextByState.get(state) ?? null;
|
||||
if (!pendingMcpAuthContext) {
|
||||
return res.status(404).json({ error: 'No pending MCP auth context' });
|
||||
}
|
||||
|
||||
return res.json(pendingMcpAuthContext);
|
||||
} catch (error) {
|
||||
console.error('Failed to read pending MCP auth context:', error);
|
||||
return res.status(500).json({ error: error.message || 'Failed to read pending MCP auth context' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/mcp/auth/pending', async (req, res) => {
|
||||
try {
|
||||
const state = normalizePendingString(Array.isArray(req.query?.state) ? req.query.state[0] : req.query?.state);
|
||||
if (!state) {
|
||||
return res.json({ success: true });
|
||||
}
|
||||
|
||||
pendingMcpAuthContextByState.delete(state);
|
||||
return res.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('Failed to clear pending MCP auth context:', error);
|
||||
return res.status(500).json({ error: error.message || 'Failed to clear pending MCP auth context' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/provider/:providerId/source', async (req, res) => {
|
||||
try {
|
||||
const { providerId } = req.params;
|
||||
|
||||
Reference in New Issue
Block a user