Forge
csharpc0b81713
1using System.Collections.Frozen;
2using System.Diagnostics;
3using System.Text.Json;
4using AgentNotes.Core;
5using AgentNotesMcp.Status;
6using ModelContextProtocol.Protocol;
7using ModelContextProtocol.Server;
8
9if (AgentNotesBootstrap.IsStatusOnly(args))
10 return await AgentNotesStatusOnlyRunner.RunAsync(args);
11
12var startupCode = AgentNotesBootstrap.TryLoadSettings(args, out var localSettings, out var startupError);
13if (startupCode != 0)
14{
15 Console.Error.WriteLine(startupError);
16 return startupCode;
17}
18
19AgentNotesRuntime.Initialize(localSettings!, AgentNotesBootstrap.LoadedConfigPath);
20
21var storage = new NotesStorage();
22var handlers = new ToolHandlers(storage);
23var tools = ToolCatalog.Build();
24
25var startedAt = DateTimeOffset.UtcNow;
26AgentNotesStatusHost? statusHost = null;
27if (AgentNotesStatusHost.TryStartBackground(storage, startedAt, out statusHost, out var statusUrl, out var statusError)
28 && statusUrl is not null)
29{
30 Console.Error.WriteLine($"AgentNotesStatus: {statusUrl}");
31 if (localSettings!.Status.PreviewWorkspace is { } preview)
32 AgentNotesStatusRuntimeFile.TryWrite(preview, statusUrl, AgentNotesBootstrap.LoadedConfigPath ?? "");
33}
34else if (localSettings!.Status.Enabled && statusError is not null)
35{
36 Console.Error.WriteLine($"AgentNotesStatus: failed to start ({statusError}). MCP continues without HTTP status.");
37}
38
39var mcpVersion = typeof(Program).Assembly.GetName().Version?.ToString(3) ?? "2.1.0";
40var options = new McpServerOptions
41{
42 ServerInfo = new Implementation { Name = "AgentNotesMcp", Version = mcpVersion },
43 ProtocolVersion = "2024-11-05",
44 Capabilities = new ServerCapabilities
45 {
46 Tools = new ToolsCapability { ListChanged = false }
47 },
48 Handlers = new McpServerHandlers
49 {
50 ListToolsHandler = (_, _) => ValueTask.FromResult(new ListToolsResult { Tools = tools }),
51 CallToolHandler = (request, _) =>
52 {
53 var name = request.Params?.Name ?? "";
54 var args = request.Params?.Arguments is IReadOnlyDictionary<string, JsonElement> providedArgs
55 ? providedArgs
56 : FrozenDictionary<string, JsonElement>.Empty;
57
58 var sw = Stopwatch.StartNew();
59 try
60 {
61 var text = handlers.Handle(name, args);
62 var isError = handlers.IsWriteLikeTool(name) && text != "OK" && !text.StartsWith("NO_CHANGES", StringComparison.Ordinal);
63 AgentNotesToolCallRingBuffer.Record(name, args, text, isError, sw.ElapsedMilliseconds);
64
65 return ValueTask.FromResult(new CallToolResult
66 {
67 Content = [new TextContentBlock { Text = text }],
68 IsError = isError
69 });
70 }
71 catch (ArgumentException ex)
72 {
73 var message = $"Error: {ex.Message}";
74 AgentNotesToolCallRingBuffer.Record(name, args, message, isError: true, sw.ElapsedMilliseconds);
75 return ValueTask.FromResult(new CallToolResult
76 {
77 Content = [new TextContentBlock { Text = message }],
78 IsError = true
79 });
80 }
81 catch (Exception ex)
82 {
83 var message = "Error: " + ex.Message;
84 AgentNotesToolCallRingBuffer.Record(name, args, message, isError: true, sw.ElapsedMilliseconds);
85 return ValueTask.FromResult(new CallToolResult
86 {
87 Content = [new TextContentBlock { Text = message }],
88 IsError = true
89 });
90 }
91 }
92 }
93};
94
95try
96{
97 var transport = new StdioServerTransport("AgentNotesMcp");
98 await using var server = McpServer.Create(transport, options);
99 await server.RunAsync();
100 return 0;
101}
102finally
103{
104 if (statusHost is not null)
105 await statusHost.StopAsync();
106}
107
View only · write via MCP/CIDE