Skip to content

Commit 1da63ab

Browse files
authored
Merge pull request #280 from Resgrid/develop
RE1-T102 Fixing MCP server issue.
2 parents 069179f + 99224da commit 1da63ab

2 files changed

Lines changed: 109 additions & 102 deletions

File tree

Web/Resgrid.Web.Mcp/Program.cs

Lines changed: 15 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -44,131 +44,44 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
4444
{
4545
webBuilder.UseSentry(options =>
4646
{
47-
//options.MinimumBreadcrumbLevel = LogEventLevel.Debug;
48-
//options.MinimumEventLevel = LogEventLevel.Error;
4947
options.Dsn = ExternalErrorConfig.ExternalErrorServiceUrlForMcp;
5048
options.AttachStacktrace = true;
5149
options.SendDefaultPii = true;
5250
options.AutoSessionTracking = true;
53-
54-
//if (ExternalErrorConfig.SentryPerfSampleRate > 0)
55-
// options.EnableTracing = true;
56-
5751
options.TracesSampleRate = ExternalErrorConfig.SentryPerfSampleRate;
5852
options.Environment = ExternalErrorConfig.Environment;
59-
options.Release = Assembly.GetEntryAssembly().GetName().Version.ToString();
53+
options.Release = Assembly.GetEntryAssembly()?.GetName().Version?.ToString();
6054
options.ProfilesSampleRate = ExternalErrorConfig.SentryProfilingSampleRate;
6155

62-
// Requires NuGet package: Sentry.Profiling
63-
// Note: By default, the profiler is initialized asynchronously. This can be tuned by passing a desired initialization timeout to the constructor.
64-
options.AddIntegration(new ProfilingIntegration(
65-
// During startup, wait up to 500ms to profile the app startup code. This could make launching the app a bit slower so comment it out if your prefer profiling to start asynchronously
66-
//TimeSpan.FromMilliseconds(500)
67-
));
56+
// Add profiling integration
57+
options.AddIntegration(new ProfilingIntegration());
6858

69-
options.TracesSampler = samplingContext =>
70-
{
71-
if (samplingContext != null && samplingContext.CustomSamplingContext != null)
59+
options.TracesSampler = samplingContext =>
7260
{
73-
if (samplingContext.CustomSamplingContext.TryGetValue("__HttpPath", out var httpPath))
61+
if (samplingContext?.CustomSamplingContext != null)
7462
{
75-
var pathValue = httpPath?.ToString();
76-
if (string.Equals(pathValue, "/health/getcurrent", StringComparison.OrdinalIgnoreCase))
63+
if (samplingContext.CustomSamplingContext.TryGetValue("__HttpPath", out var httpPath))
7764
{
78-
return 0;
65+
var pathValue = httpPath?.ToString();
66+
if (string.Equals(pathValue, "/health/getcurrent", StringComparison.OrdinalIgnoreCase))
67+
{
68+
return 0;
69+
}
7970
}
8071
}
81-
}
8272

83-
return ExternalErrorConfig.SentryPerfSampleRate;
84-
};
73+
return ExternalErrorConfig.SentryPerfSampleRate;
74+
};
8575
});
8676
}
8777

8878
webBuilder.UseKestrel(serverOptions =>
8979
{
9080
// Configure Kestrel to listen on a specific port for health checks
91-
serverOptions.ListenAnyIP(5050); // Health check port
92-
});
93-
webBuilder.Configure(app =>
94-
{
95-
app.UseRouting();
96-
app.UseSentryTracing();
97-
app.UseEndpoints(endpoints =>
98-
{
99-
endpoints.MapControllers();
100-
});
81+
serverOptions.ListenAnyIP(5050);
10182
});
102-
})
103-
.ConfigureAppConfiguration((_, config) =>
104-
{
105-
config.SetBasePath(Directory.GetCurrentDirectory())
106-
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
107-
.AddEnvironmentVariables()
108-
.AddCommandLine(args);
109-
})
110-
.ConfigureServices((hostContext, services) =>
111-
{
112-
var configuration = hostContext.Configuration;
113-
114-
// Configuration is already loaded in ConfigureWebHostDefaults
115-
// Initialize Resgrid logging framework with Sentry if available
116-
if (!string.IsNullOrWhiteSpace(ExternalErrorConfig.ExternalErrorServiceUrlForMcp))
117-
{
118-
Framework.Logging.Initialize(ExternalErrorConfig.ExternalErrorServiceUrlForMcp);
119-
}
120-
121-
// Register MCP server
122-
services.AddHostedService<McpServerHost>();
123-
124-
// Add MVC controllers for health check endpoint
125-
services.AddControllers()
126-
.AddNewtonsoftJson();
127-
128-
// Register infrastructure services
129-
services.AddMemoryCache();
130-
services.AddSingleton<Infrastructure.IResponseCache, Infrastructure.ResponseCache>();
131-
services.AddSingleton<Infrastructure.IRateLimiter, Infrastructure.RateLimiter>();
132-
services.AddSingleton<Infrastructure.ITokenRefreshService, Infrastructure.TokenRefreshService>();
133-
services.AddSingleton<Infrastructure.IAuditLogger, Infrastructure.AuditLogger>();
134-
135-
// Validate required API configuration from SystemBehaviorConfig
136-
if (string.IsNullOrWhiteSpace(SystemBehaviorConfig.ResgridApiBaseUrl))
137-
{
138-
throw new InvalidOperationException(
139-
"SystemBehaviorConfig.ResgridApiBaseUrl is required but not configured. " +
140-
"Configure this setting via the Resgrid configuration file or environment variables (RESGRID:SystemBehaviorConfig:ResgridApiBaseUrl).");
141-
}
142-
143-
// Register HTTP client for API calls with connection pooling
144-
services.AddHttpClient("ResgridApi", client =>
145-
{
146-
client.BaseAddress = new Uri(SystemBehaviorConfig.ResgridApiBaseUrl);
147-
client.DefaultRequestHeaders.Add("Accept", "application/json");
148-
client.Timeout = TimeSpan.FromSeconds(30);
149-
})
150-
.ConfigurePrimaryHttpMessageHandler(() => new System.Net.Http.SocketsHttpHandler
151-
{
152-
PooledConnectionLifetime = TimeSpan.FromMinutes(5),
153-
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2),
154-
MaxConnectionsPerServer = 10
155-
});
156-
157-
// Register API client
158-
services.AddSingleton<IApiClient, ApiClient>();
15983

160-
// Register tool providers
161-
services.AddSingleton<Tools.AuthenticationToolProvider>();
162-
services.AddSingleton<Tools.CallsToolProvider>();
163-
services.AddSingleton<Tools.DispatchToolProvider>();
164-
services.AddSingleton<Tools.PersonnelToolProvider>();
165-
services.AddSingleton<Tools.UnitsToolProvider>();
166-
services.AddSingleton<Tools.MessagesToolProvider>();
167-
services.AddSingleton<Tools.CalendarToolProvider>();
168-
services.AddSingleton<Tools.ShiftsToolProvider>();
169-
services.AddSingleton<Tools.InventoryToolProvider>();
170-
services.AddSingleton<Tools.ReportsToolProvider>();
171-
services.AddSingleton<McpToolRegistry>();
84+
webBuilder.UseStartup<Startup>();
17285
});
17386
}
17487
}

Web/Resgrid.Web.Mcp/Startup.cs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using System;
2+
using Microsoft.AspNetCore.Builder;
3+
using Microsoft.AspNetCore.Hosting;
4+
using Microsoft.Extensions.Configuration;
5+
using Microsoft.Extensions.DependencyInjection;
6+
using Resgrid.Config;
7+
using Resgrid.Web.Mcp.Infrastructure;
8+
using Resgrid.Web.Mcp.Tools;
9+
10+
namespace Resgrid.Web.Mcp
11+
{
12+
public class Startup
13+
{
14+
public IConfiguration Configuration { get; }
15+
16+
public Startup(IConfiguration configuration)
17+
{
18+
Configuration = configuration;
19+
}
20+
21+
public void ConfigureServices(IServiceCollection services)
22+
{
23+
// Initialize Resgrid logging framework with Sentry if available
24+
if (!string.IsNullOrWhiteSpace(ExternalErrorConfig.ExternalErrorServiceUrlForMcp))
25+
{
26+
Framework.Logging.Initialize(ExternalErrorConfig.ExternalErrorServiceUrlForMcp);
27+
}
28+
29+
// Register MCP server
30+
services.AddHostedService<McpServerHost>();
31+
32+
// Add MVC controllers for health check endpoint
33+
services.AddControllers()
34+
.AddNewtonsoftJson();
35+
36+
// Register infrastructure services
37+
services.AddMemoryCache();
38+
services.AddSingleton<IResponseCache, ResponseCache>();
39+
services.AddSingleton<IRateLimiter, RateLimiter>();
40+
services.AddSingleton<ITokenRefreshService, TokenRefreshService>();
41+
services.AddSingleton<IAuditLogger, AuditLogger>();
42+
43+
// Validate required API configuration from SystemBehaviorConfig
44+
if (string.IsNullOrWhiteSpace(SystemBehaviorConfig.ResgridApiBaseUrl))
45+
{
46+
throw new InvalidOperationException(
47+
"SystemBehaviorConfig.ResgridApiBaseUrl is required but not configured. " +
48+
"Configure this setting via the Resgrid configuration file or environment variables (RESGRID:SystemBehaviorConfig:ResgridApiBaseUrl).");
49+
}
50+
51+
// Register HTTP client for API calls with connection pooling
52+
services.AddHttpClient("ResgridApi", client =>
53+
{
54+
client.BaseAddress = new Uri(SystemBehaviorConfig.ResgridApiBaseUrl);
55+
client.DefaultRequestHeaders.Add("Accept", "application/json");
56+
client.Timeout = TimeSpan.FromSeconds(30);
57+
})
58+
.ConfigurePrimaryHttpMessageHandler(() => new System.Net.Http.SocketsHttpHandler
59+
{
60+
PooledConnectionLifetime = TimeSpan.FromMinutes(5),
61+
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2),
62+
MaxConnectionsPerServer = 10
63+
});
64+
65+
// Register API client
66+
services.AddSingleton<IApiClient, ApiClient>();
67+
68+
// Register tool providers
69+
services.AddSingleton<AuthenticationToolProvider>();
70+
services.AddSingleton<CallsToolProvider>();
71+
services.AddSingleton<DispatchToolProvider>();
72+
services.AddSingleton<PersonnelToolProvider>();
73+
services.AddSingleton<UnitsToolProvider>();
74+
services.AddSingleton<MessagesToolProvider>();
75+
services.AddSingleton<CalendarToolProvider>();
76+
services.AddSingleton<ShiftsToolProvider>();
77+
services.AddSingleton<InventoryToolProvider>();
78+
services.AddSingleton<ReportsToolProvider>();
79+
services.AddSingleton<McpToolRegistry>();
80+
}
81+
82+
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
83+
{
84+
app.UseRouting();
85+
86+
app.UseEndpoints(endpoints =>
87+
{
88+
endpoints.MapControllers();
89+
});
90+
}
91+
}
92+
}
93+
94+

0 commit comments

Comments
 (0)