Skip to content

Commit 3b9a9d5

Browse files
committed
Add demo project with two dotnet run file samples
1 parent 9abb4c4 commit 3b9a9d5

8 files changed

Lines changed: 199 additions & 3 deletions

File tree

SmallSharp.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ VisualStudioVersion = 17.5.33103.201
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SmallSharp", "src\SmallSharp\SmallSharp.csproj", "{97648980-AA30-4AC0-B8E9-FCF6359F56A0}"
77
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo", "src\Demo\Demo.csproj", "{4E71DAD8-502C-47A9-88FC-2AF018BE762F}"
9+
EndProject
810
Global
911
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1012
Debug|Any CPU = Debug|Any CPU
@@ -15,6 +17,10 @@ Global
1517
{97648980-AA30-4AC0-B8E9-FCF6359F56A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
1618
{97648980-AA30-4AC0-B8E9-FCF6359F56A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
1719
{97648980-AA30-4AC0-B8E9-FCF6359F56A0}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{4E71DAD8-502C-47A9-88FC-2AF018BE762F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{4E71DAD8-502C-47A9-88FC-2AF018BE762F}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{4E71DAD8-502C-47A9-88FC-2AF018BE762F}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{4E71DAD8-502C-47A9-88FC-2AF018BE762F}.Release|Any CPU.Build.0 = Release|Any CPU
1824
EndGlobalSection
1925
GlobalSection(SolutionProperties) = preSolution
2026
HideSolutionNode = FALSE

src/Demo/Demo.csproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<Sdk Name="SmallSharp" Version="42.42.501-main" />
4+
5+
<PropertyGroup>
6+
<OutputType>Exe</OutputType>
7+
<TargetFramework>net10.0</TargetFramework>
8+
</PropertyGroup>
9+
10+
</Project>

src/Demo/Humanizer.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#:package Humanizer@2.14.1
2+
#:property ImplicitUsings true
3+
#:property Nullable enable
4+
5+
using Humanizer;
6+
7+
var dotNet9Released = DateTimeOffset.Parse("2024-12-03");
8+
var since = DateTimeOffset.Now - dotNet9Released;
9+
10+
Console.WriteLine($"It has been {since.Humanize()} since .NET 9 was released.");

src/Demo/Mcp.cs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#:package Smith@0.2.5
2+
#:package DotNetConfig.Configuration@1.2.*
3+
#:package ModelContextProtocol@0.3.0-preview.*
4+
#:package Microsoft.Extensions.Http@9.*
5+
6+
using ModelContextProtocol.Protocol;
7+
using ModelContextProtocol.Server;
8+
9+
var builder = App.CreateBuilder(args);
10+
builder.Configuration.AddDotNetConfig();
11+
12+
var initialized = false;
13+
bool? darkMode = bool.TryParse(builder.Configuration["latex:darkMode"], out var dm) ? dm : null;
14+
string? fontSize = builder.Configuration["latex:fontSize"];
15+
// See https://editor.codecogs.com/docs/4-LaTeX_rendering.php#overview_anchor
16+
var fonts = new Dictionary<string, string>
17+
{
18+
{ "Tiny", "tiny" },
19+
{ "Small", "small" },
20+
{ "Large", "large" },
21+
{ "LARGE", "LARGE" },
22+
{ "Huge", "huge"}
23+
};
24+
25+
builder.Services
26+
.AddHttpClient()
27+
.AddMcpServer()
28+
.WithStdioServerTransport()
29+
.WithTool(
30+
name: "latex",
31+
title: "LaTeX to Image",
32+
description:
33+
"""
34+
Converts LaTeX equations into markdown-formatted images for inline display.
35+
Users can use #latex_setprefs tool to set preferences for dark mode and font size.
36+
Available font sizes: tiny, small, large, LARGE, huge.
37+
""",
38+
tool: async (IHttpClientFactory httpFactory, IMcpServer server,
39+
[Description("The LaTeX equation to render.")] string latex)
40+
=>
41+
{
42+
// On first tool run, we ask for preferences for dark mode and font size.
43+
if (!initialized)
44+
{
45+
initialized = true;
46+
(darkMode, fontSize) = await SetPreferences(server, darkMode, fontSize);
47+
}
48+
49+
var colors = darkMode switch
50+
{
51+
true => @"\fg{white}",
52+
false => @"\fg{black}",
53+
null => @"\bg{white}\fg{black}"
54+
};
55+
56+
var query = WebUtility.UrlEncode(@"\dpi{300}\" + (fontSize ?? "small") + colors + new string([.. latex.Where(c => !char.IsWhiteSpace(c))]));
57+
var url = $"https://latex.codecogs.com/png.image?{query}";
58+
59+
using var client = httpFactory.CreateClient();
60+
using var response = await client.GetAsync(url);
61+
response.EnsureSuccessStatusCode();
62+
63+
var base64 = Convert.ToBase64String(await response.Content.ReadAsByteArrayAsync());
64+
return $"> ![LaTeX Equation](data:image/png;base64,{base64})";
65+
})
66+
.WithTool(
67+
name: "latex_getprefs",
68+
title: "Get LaTeX Preferences",
69+
description: "Gets the saved LaTeX rendering preferences for dark mode and font size.",
70+
tool: () => new { darkMode, fontSize },
71+
options: ToolJsonOptions.Default)
72+
.WithTool(
73+
name: "latex_setprefs",
74+
title: "Set LaTeX Preferences",
75+
description: "Sets the LaTeX rendering preferences for dark mode and font size.",
76+
tool: async (IMcpServer server,
77+
[Description("Use dark mode by inverting the colors in the output.")] bool? darkMode = null,
78+
[Description("Font size to use in the output: tiny=5pt, small=9pt, large=12pt, LARGE=18pt, huge=20pt")] string? fontSize = null)
79+
=> (darkMode, fontSize) = await SetPreferences(server, darkMode, fontSize),
80+
options: ToolJsonOptions.Default);
81+
82+
await builder.Build().RunAsync();
83+
84+
/// <summary>Saves the LaTeX rendering preferences to configuration.</summary>
85+
async ValueTask<(bool? darkMode, string? fontSize)> SetPreferences(IMcpServer server, bool? darkMode, string? fontSize)
86+
{
87+
if ((darkMode is null || fontSize is null || !fonts.ContainsValue(fontSize)) && server.ClientCapabilities?.Elicitation != null)
88+
{
89+
var result = await server.ElicitAsync(new()
90+
{
91+
Message = "Specify LaTeX rendering preferences",
92+
RequestedSchema = new()
93+
{
94+
Required = ["darkMode", "fontSize"],
95+
Properties =
96+
{
97+
{ "darkMode", new ElicitRequestParams.BooleanSchema()
98+
{
99+
Title = "Dark Mode",
100+
Description = "Use dark mode?",
101+
Default = darkMode
102+
}
103+
},
104+
{ "fontSize", new ElicitRequestParams.EnumSchema()
105+
{
106+
Title = "Font Size",
107+
Description = "Font size to use for the LaTeX rendering.",
108+
Enum = [.. fonts.Values],
109+
EnumNames = [.. fonts.Keys],
110+
}
111+
},
112+
},
113+
}
114+
});
115+
116+
if (result.Action == "accept" && result.Content is { } content)
117+
{
118+
darkMode = content["darkMode"].GetBoolean();
119+
fontSize = content["fontSize"].GetString() ?? "tiny";
120+
121+
DotNetConfig.Config.Build(DotNetConfig.ConfigLevel.Global)
122+
.GetSection("latex")
123+
.SetBoolean("darkMode", darkMode.Value)
124+
.SetString("fontSize", fontSize);
125+
}
126+
// action == cancel is not supported in vscode
127+
// actoin == decline would be equal to "ignore" so we just don't set anything.
128+
return (darkMode, fontSize);
129+
}
130+
else
131+
{
132+
// We persist to ~/.netconfig
133+
var config = DotNetConfig.Config.Build(DotNetConfig.ConfigLevel.Global).GetSection("latex");
134+
if (darkMode != null)
135+
config = config.SetBoolean("darkMode", darkMode.Value);
136+
if (fontSize != null && fonts.ContainsValue(fontSize))
137+
config = config.SetString("fontSize", fontSize);
138+
else
139+
fontSize = null;
140+
141+
return (darkMode, fontSize);
142+
}
143+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"profiles": {
3+
"Humanizer.cs": {
4+
"commandName": "Project"
5+
},
6+
"Mcp.cs": {
7+
"commandName": "Project"
8+
}
9+
}
10+
}

src/Directory.props

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
<PackOnBuild>true</PackOnBuild>
77
<PackageProjectUrl>https://clarius.org/SmallSharp</PackageProjectUrl>
88
<NoWarn>NU1702;$(NoWarn)</NoWarn>
9-
10-
<StartAction>Program</StartAction>
11-
<StartProgram>$(VsInstallRoot)\Common7\IDE\devenv.exe</StartProgram>
129
</PropertyGroup>
1310

1411
</Project>

src/SmallSharp/SmallSharp.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
<PackNone>true</PackNone>
99
<GenerateDocumentationFile>false</GenerateDocumentationFile>
1010
<DevelopmentDependency>true</DevelopmentDependency>
11+
<StartAction>Program</StartAction>
12+
<StartProgram>$(VsInstallRoot)\Common7\IDE\devenv.exe</StartProgram>
1113
</PropertyGroup>
1214

1315
<ItemGroup>

src/nuget.config

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
<packageSources>
4+
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
5+
<add key="kzu" value="https://api.kzu.app/index.json" />
6+
</packageSources>
7+
<activePackageSource>
8+
<add key="All" value="(Aggregate source)" />
9+
</activePackageSource>
10+
<packageSourceMapping>
11+
<packageSource key="nuget.org">
12+
<package pattern="*" />
13+
</packageSource>
14+
<packageSource key="kzu">
15+
<package pattern="SmallSharp" />
16+
</packageSource>
17+
</packageSourceMapping>
18+
</configuration>

0 commit comments

Comments
 (0)