Skip to content

Commit 2523f41

Browse files
sharpninjaCopilot
andcommitted
Fix Web UI auth recovery and startup
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent d895959 commit 2523f41

16 files changed

Lines changed: 1424 additions & 322 deletions

src/McpServer.Web/Adapters/AgentApiClientAdapter.cs

Lines changed: 117 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ public AgentApiClientAdapter(WebMcpContext context, ILogger<AgentApiClientAdapte
2020

2121
public async Task<ListAgentDefinitionsResult> ListDefinitionsAsync(CancellationToken cancellationToken = default)
2222
{
23-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
24-
var response = await client.Agent.ListDefinitionsAsync(cancellationToken).ConfigureAwait(true);
23+
var response = await _context.UseControlApiClientAsync(
24+
static (client, ct) => client.Agent.ListDefinitionsAsync(ct),
25+
cancellationToken)
26+
.ConfigureAwait(true);
2527
var items = response.Items
2628
.Select(item => new AgentDefinitionSummaryItem(item.Id, item.DisplayName, item.IsBuiltIn))
2729
.ToList();
@@ -32,8 +34,10 @@ public async Task<ListAgentDefinitionsResult> ListDefinitionsAsync(CancellationT
3234
{
3335
try
3436
{
35-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
36-
var definition = await client.Agent.GetDefinitionAsync(agentType, cancellationToken).ConfigureAwait(true);
37+
var definition = await _context.UseControlApiClientAsync(
38+
(client, ct) => client.Agent.GetDefinitionAsync(agentType, ct),
39+
cancellationToken)
40+
.ConfigureAwait(true);
3741
return MapDefinition(definition);
3842
}
3943
catch (McpNotFoundException ex)
@@ -45,40 +49,48 @@ public async Task<ListAgentDefinitionsResult> ListDefinitionsAsync(CancellationT
4549

4650
public async Task<AgentMutationOutcome> UpsertDefinitionAsync(UpsertAgentDefinitionCommand command, CancellationToken cancellationToken = default)
4751
{
48-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
49-
var result = await client.Agent.UpsertDefinitionAsync(
50-
new AgentDefinitionRequest
51-
{
52-
Id = command.Id,
53-
DisplayName = command.DisplayName,
54-
DefaultLaunchCommand = command.DefaultLaunchCommand,
55-
DefaultInstructionFile = command.DefaultInstructionFile,
56-
DefaultModels = command.DefaultModels,
57-
DefaultBranchStrategy = command.DefaultBranchStrategy,
58-
DefaultSeedPrompt = command.DefaultSeedPrompt
59-
},
60-
cancellationToken).ConfigureAwait(true);
52+
var result = await _context.UseControlApiClientAsync(
53+
(client, ct) => client.Agent.UpsertDefinitionAsync(
54+
new AgentDefinitionRequest
55+
{
56+
Id = command.Id,
57+
DisplayName = command.DisplayName,
58+
DefaultLaunchCommand = command.DefaultLaunchCommand,
59+
DefaultInstructionFile = command.DefaultInstructionFile,
60+
DefaultModels = command.DefaultModels,
61+
DefaultBranchStrategy = command.DefaultBranchStrategy,
62+
DefaultSeedPrompt = command.DefaultSeedPrompt
63+
},
64+
ct),
65+
cancellationToken)
66+
.ConfigureAwait(true);
6167
return new AgentMutationOutcome(result.Success, result.Error);
6268
}
6369

6470
public async Task<AgentMutationOutcome> DeleteDefinitionAsync(DeleteAgentDefinitionCommand command, CancellationToken cancellationToken = default)
6571
{
66-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
67-
var result = await client.Agent.DeleteDefinitionAsync(command.AgentType, cancellationToken).ConfigureAwait(true);
72+
var result = await _context.UseControlApiClientAsync(
73+
(client, ct) => client.Agent.DeleteDefinitionAsync(command.AgentType, ct),
74+
cancellationToken)
75+
.ConfigureAwait(true);
6876
return new AgentMutationOutcome(result.Success, result.Error);
6977
}
7078

7179
public async Task<AgentSeedOutcome> SeedDefaultsAsync(CancellationToken cancellationToken = default)
7280
{
73-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
74-
var result = await client.Agent.SeedDefaultsAsync(cancellationToken).ConfigureAwait(true);
81+
var result = await _context.UseControlApiClientAsync(
82+
static (client, ct) => client.Agent.SeedDefaultsAsync(ct),
83+
cancellationToken)
84+
.ConfigureAwait(true);
7585
return new AgentSeedOutcome(result.Seeded);
7686
}
7787

7888
public async Task<ListWorkspaceAgentsResult> ListWorkspaceAgentsAsync(ListWorkspaceAgentsQuery query, CancellationToken cancellationToken = default)
7989
{
80-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
81-
var response = await client.Agent.ListWorkspaceAgentsAsync(query.WorkspacePath, cancellationToken).ConfigureAwait(true);
90+
var response = await _context.UseControlApiClientAsync(
91+
(client, ct) => client.Agent.ListWorkspaceAgentsAsync(query.WorkspacePath, ct),
92+
cancellationToken)
93+
.ConfigureAwait(true);
8294
var items = response.Items.Select(MapWorkspaceAgentItem).ToList();
8395
return new ListWorkspaceAgentsResult(items, response.TotalCount);
8496
}
@@ -87,8 +99,10 @@ public async Task<ListWorkspaceAgentsResult> ListWorkspaceAgentsAsync(ListWorksp
8799
{
88100
try
89101
{
90-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
91-
var item = await client.Agent.GetWorkspaceAgentAsync(query.AgentId, query.WorkspacePath, cancellationToken).ConfigureAwait(true);
102+
var item = await _context.UseControlApiClientAsync(
103+
(client, ct) => client.Agent.GetWorkspaceAgentAsync(query.AgentId, query.WorkspacePath, ct),
104+
cancellationToken)
105+
.ConfigureAwait(true);
92106
return MapWorkspaceAgentDetail(item);
93107
}
94108
catch (McpNotFoundException ex)
@@ -100,96 +114,110 @@ public async Task<ListWorkspaceAgentsResult> ListWorkspaceAgentsAsync(ListWorksp
100114

101115
public async Task<AgentMutationOutcome> UpsertWorkspaceAgentAsync(UpsertWorkspaceAgentCommand command, CancellationToken cancellationToken = default)
102116
{
103-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
104-
var result = await client.Agent.UpsertWorkspaceAgentAsync(
105-
command.AgentId,
106-
new AgentWorkspaceRequest
107-
{
108-
AgentId = command.AgentId,
109-
Enabled = command.Enabled,
110-
AgentIsolation = command.AgentIsolation,
111-
LaunchCommandOverride = command.LaunchCommandOverride,
112-
ModelsOverride = command.ModelsOverride,
113-
BranchStrategyOverride = command.BranchStrategyOverride,
114-
SeedPromptOverride = command.SeedPromptOverride,
115-
MarkerAdditions = command.MarkerAdditions ?? string.Empty,
116-
InstructionFilesOverride = command.InstructionFilesOverride
117-
},
118-
command.WorkspacePath,
119-
cancellationToken).ConfigureAwait(true);
117+
var result = await _context.UseControlApiClientAsync(
118+
(client, ct) => client.Agent.UpsertWorkspaceAgentAsync(
119+
command.AgentId,
120+
new AgentWorkspaceRequest
121+
{
122+
AgentId = command.AgentId,
123+
Enabled = command.Enabled,
124+
AgentIsolation = command.AgentIsolation,
125+
LaunchCommandOverride = command.LaunchCommandOverride,
126+
ModelsOverride = command.ModelsOverride,
127+
BranchStrategyOverride = command.BranchStrategyOverride,
128+
SeedPromptOverride = command.SeedPromptOverride,
129+
MarkerAdditions = command.MarkerAdditions ?? string.Empty,
130+
InstructionFilesOverride = command.InstructionFilesOverride
131+
},
132+
command.WorkspacePath,
133+
ct),
134+
cancellationToken)
135+
.ConfigureAwait(true);
120136
return new AgentMutationOutcome(result.Success, result.Error);
121137
}
122138

123139
public async Task<AgentMutationOutcome> AssignWorkspaceAgentAsync(AssignWorkspaceAgentCommand command, CancellationToken cancellationToken = default)
124140
{
125-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
126-
var result = await client.Agent.UpsertWorkspaceAgentAsync(
127-
command.AgentId,
128-
new AgentWorkspaceRequest
129-
{
130-
AgentId = command.AgentId,
131-
Enabled = command.Enabled,
132-
AgentIsolation = command.AgentIsolation
133-
},
134-
command.WorkspacePath,
135-
cancellationToken).ConfigureAwait(true);
141+
var result = await _context.UseControlApiClientAsync(
142+
(client, ct) => client.Agent.UpsertWorkspaceAgentAsync(
143+
command.AgentId,
144+
new AgentWorkspaceRequest
145+
{
146+
AgentId = command.AgentId,
147+
Enabled = command.Enabled,
148+
AgentIsolation = command.AgentIsolation
149+
},
150+
command.WorkspacePath,
151+
ct),
152+
cancellationToken)
153+
.ConfigureAwait(true);
136154
return new AgentMutationOutcome(result.Success, result.Error);
137155
}
138156

139157
public async Task<AgentMutationOutcome> DeleteWorkspaceAgentAsync(DeleteWorkspaceAgentCommand command, CancellationToken cancellationToken = default)
140158
{
141-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
142-
var result = await client.Agent.DeleteWorkspaceAgentAsync(command.AgentId, command.WorkspacePath, cancellationToken).ConfigureAwait(true);
159+
var result = await _context.UseControlApiClientAsync(
160+
(client, ct) => client.Agent.DeleteWorkspaceAgentAsync(command.AgentId, command.WorkspacePath, ct),
161+
cancellationToken)
162+
.ConfigureAwait(true);
143163
return new AgentMutationOutcome(result.Success, result.Error);
144164
}
145165

146166
public async Task<AgentMutationOutcome> BanAgentAsync(BanAgentCommand command, CancellationToken cancellationToken = default)
147167
{
148-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
149-
var result = await client.Agent.BanAgentAsync(
150-
command.AgentId,
151-
new AgentBanRequest
152-
{
153-
Reason = command.Reason,
154-
BannedUntilPr = command.BannedUntilPr,
155-
Global = command.Global
156-
},
157-
command.WorkspacePath,
158-
cancellationToken).ConfigureAwait(true);
168+
var result = await _context.UseControlApiClientAsync(
169+
(client, ct) => client.Agent.BanAgentAsync(
170+
command.AgentId,
171+
new AgentBanRequest
172+
{
173+
Reason = command.Reason,
174+
BannedUntilPr = command.BannedUntilPr,
175+
Global = command.Global
176+
},
177+
command.WorkspacePath,
178+
ct),
179+
cancellationToken)
180+
.ConfigureAwait(true);
159181
return new AgentMutationOutcome(result.Success, result.Error);
160182
}
161183

162184
public async Task<AgentMutationOutcome> UnbanAgentAsync(UnbanAgentCommand command, CancellationToken cancellationToken = default)
163185
{
164-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
165-
var result = await client.Agent.UnbanAgentAsync(
166-
command.AgentId,
167-
command.WorkspacePath,
168-
command.Global,
169-
cancellationToken).ConfigureAwait(true);
186+
var result = await _context.UseControlApiClientAsync(
187+
(client, ct) => client.Agent.UnbanAgentAsync(
188+
command.AgentId,
189+
command.WorkspacePath,
190+
command.Global,
191+
ct),
192+
cancellationToken)
193+
.ConfigureAwait(true);
170194
return new AgentMutationOutcome(result.Success, result.Error);
171195
}
172196

173197
public async Task<AgentMutationOutcome> LogEventAsync(LogAgentEventCommand command, CancellationToken cancellationToken = default)
174198
{
175-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
176-
var result = await client.Agent.LogEventAsync(
177-
command.AgentId,
178-
new AgentEventRequest
179-
{
180-
AgentId = command.AgentId,
181-
EventType = command.EventType,
182-
Details = command.Details
183-
},
184-
command.WorkspacePath,
185-
cancellationToken).ConfigureAwait(true);
199+
var result = await _context.UseControlApiClientAsync(
200+
(client, ct) => client.Agent.LogEventAsync(
201+
command.AgentId,
202+
new AgentEventRequest
203+
{
204+
AgentId = command.AgentId,
205+
EventType = command.EventType,
206+
Details = command.Details
207+
},
208+
command.WorkspacePath,
209+
ct),
210+
cancellationToken)
211+
.ConfigureAwait(true);
186212
return new AgentMutationOutcome(result.Success, result.Error);
187213
}
188214

189215
public async Task<AgentEventsResult> GetEventsAsync(GetAgentEventsQuery query, CancellationToken cancellationToken = default)
190216
{
191-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
192-
var result = await client.Agent.GetEventsAsync(query.AgentId, query.WorkspacePath, query.Limit, cancellationToken).ConfigureAwait(true);
217+
var result = await _context.UseControlApiClientAsync(
218+
(client, ct) => client.Agent.GetEventsAsync(query.AgentId, query.WorkspacePath, query.Limit, ct),
219+
cancellationToken)
220+
.ConfigureAwait(true);
193221
var items = result.Items
194222
.Select(item => new AgentEventItem(
195223
item.Id,
@@ -205,8 +233,10 @@ public async Task<AgentEventsResult> GetEventsAsync(GetAgentEventsQuery query, C
205233

206234
public async Task<AgentValidateOutcome> ValidateAsync(ValidateAgentQuery query, CancellationToken cancellationToken = default)
207235
{
208-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
209-
var result = await client.Agent.ValidateAsync(query.WorkspacePath, cancellationToken).ConfigureAwait(true);
236+
var result = await _context.UseControlApiClientAsync(
237+
(client, ct) => client.Agent.ValidateAsync(query.WorkspacePath, ct),
238+
cancellationToken)
239+
.ConfigureAwait(true);
210240
return new AgentValidateOutcome(result.Valid, result.Error, result.Path);
211241
}
212242

src/McpServer.Web/Adapters/AuthConfigApiClientAdapter.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ public AuthConfigApiClientAdapter(WebMcpContext context)
1414

1515
public async Task<AuthConfigSnapshot> GetAuthConfigAsync(CancellationToken cancellationToken = default)
1616
{
17-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
18-
var result = await client.AuthConfig.GetConfigAsync(cancellationToken).ConfigureAwait(true);
17+
var result = await _context.UseControlApiClientAsync(
18+
static (client, ct) => client.AuthConfig.GetConfigAsync(ct),
19+
cancellationToken)
20+
.ConfigureAwait(true);
1921
return new AuthConfigSnapshot(
2022
result.Enabled,
2123
result.Authority,

src/McpServer.Web/Adapters/ConfigurationApiClientAdapter.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,19 @@ public ConfigurationApiClientAdapter(WebMcpContext context)
1414
public async Task<IReadOnlyDictionary<string, string>> GetValuesAsync(
1515
CancellationToken cancellationToken = default)
1616
{
17-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
18-
var result = await client.Configuration.GetValuesAsync(cancellationToken).ConfigureAwait(true);
19-
return result;
17+
return await _context.UseControlApiClientAsync(
18+
static (client, ct) => client.Configuration.GetValuesAsync(ct),
19+
cancellationToken)
20+
.ConfigureAwait(true);
2021
}
2122

2223
public async Task<IReadOnlyDictionary<string, string>> PatchValuesAsync(
2324
IReadOnlyDictionary<string, string?> values,
2425
CancellationToken cancellationToken = default)
2526
{
26-
var client = await _context.GetRequiredControlApiClientAsync(cancellationToken).ConfigureAwait(true);
27-
var result = await client.Configuration.PatchValuesAsync(values, cancellationToken).ConfigureAwait(true);
28-
return result;
27+
return await _context.UseControlApiClientAsync(
28+
(client, ct) => client.Configuration.PatchValuesAsync(values, ct),
29+
cancellationToken)
30+
.ConfigureAwait(true);
2931
}
3032
}

0 commit comments

Comments
 (0)