Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion Smith.sln
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36221.1 d17.14
VisualStudioVersion = 17.14.36221.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Smith", "src\Smith\Smith.csproj", "{728856C5-A241-6AD6-5CDE-1991FE2F10D7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Demos", "Demos", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HostedDemo", "src\HostedDemo\HostedDemo.csproj", "{7A572273-B346-1CA7-67AE-DC4906060B7A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpectreDemo", "src\SpectreDemo\SpectreDemo.csproj", "{7C636145-4896-4FA2-BC7C-053AFDD6F6E9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MCPDemo", "src\MCPDemo\MCPDemo.csproj", "{63E9B9A8-3EC5-4C0F-B8E5-30C475B2275E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -15,8 +23,28 @@ Global
{728856C5-A241-6AD6-5CDE-1991FE2F10D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{728856C5-A241-6AD6-5CDE-1991FE2F10D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{728856C5-A241-6AD6-5CDE-1991FE2F10D7}.Release|Any CPU.Build.0 = Release|Any CPU
{7A572273-B346-1CA7-67AE-DC4906060B7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7A572273-B346-1CA7-67AE-DC4906060B7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7A572273-B346-1CA7-67AE-DC4906060B7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7A572273-B346-1CA7-67AE-DC4906060B7A}.Release|Any CPU.Build.0 = Release|Any CPU
{7C636145-4896-4FA2-BC7C-053AFDD6F6E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C636145-4896-4FA2-BC7C-053AFDD6F6E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C636145-4896-4FA2-BC7C-053AFDD6F6E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C636145-4896-4FA2-BC7C-053AFDD6F6E9}.Release|Any CPU.Build.0 = Release|Any CPU
{63E9B9A8-3EC5-4C0F-B8E5-30C475B2275E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{63E9B9A8-3EC5-4C0F-B8E5-30C475B2275E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{63E9B9A8-3EC5-4C0F-B8E5-30C475B2275E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{63E9B9A8-3EC5-4C0F-B8E5-30C475B2275E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{7A572273-B346-1CA7-67AE-DC4906060B7A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{7C636145-4896-4FA2-BC7C-053AFDD6F6E9} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{63E9B9A8-3EC5-4C0F-B8E5-30C475B2275E} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D5E491DA-619A-457D-BEBE-A137B0D9F527}
EndGlobalSection
EndGlobal
13 changes: 9 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,20 @@ Example using Claude:
```csharp
#:package Smith@0.*

var chat = new Anthropic.AnthropicClient(Throw.
configuration["Claude:Key"] ?? throw new InvalidOperationException("Missing Claude:Key configuration."),
var client = new Anthropic.AnthropicClient(Throw.
Env.Get("Claude:Key") ?? throw new InvalidOperationException("Missing Claude:Key configuration."),
services.GetRequiredService<IHttpClientFactory>().CreateClient("ai")))
.UseLogging()
.UseFunctionInvocation();

var provider = services.BuildServiceProvider();
var builder = App.CreateBuilder(args);
builder.Services.AddChatClient(new );

var app = builder.Build();

var history = new List<ChatMessage> { new ChatMessage(ChatRole.System, Prompts.System) };
var chat = provider.GetRequiredService<IChatClient>();
var chat = app.Services.GetRequiredService<IChatClient>();

var options = new ChatOptions
{
ModelId = "claude-sonnet-4-20250514",
Expand Down
5 changes: 5 additions & 0 deletions samples/.github/chatmodes/math.chatmode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
description: 'An Ask mode for math-related queries, which can render LaTeX equations.'
tools: ['smith-mcp']
---
Actively use the #latex_to_image_markdown tool to render LaTeX equations in your responses as inline markdown images to enhance clarity and visual appeal. This tool is particularly useful for displaying mathematical equations, formulas, and other LaTeX-rendered content in a visually engaging manner.
4 changes: 4 additions & 0 deletions samples/.github/prompts/latex.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
mode: ask
---
Showcase popular equations in LaTeX format, and ensure they are rendered as images in the response by using the `latex_to_image_markdown` tool.
13 changes: 13 additions & 0 deletions samples/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"logging": {
"logLevel": {
"default": "Information",
"Polly": "Warning",
"System.Net.Http.HttpClient": "Warning",
"Microsoft.AspNetCore": "Warning",
"Microsoft.Extensions": "Warning",
"Microsoft.Azure": "Warning",
"Microsoft.Hosting": "Warning"
}
}
}
66 changes: 66 additions & 0 deletions samples/latex.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#:package [email protected]
#:package [email protected].*
#:package Microsoft.Extensions.Http@9.*
#:package [email protected].*

using Smith;
using System.ComponentModel;
using ModelContextProtocol.Server;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using Microsoft.Extensions.Logging;

var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHttpClient();
builder.Logging.AddConsole(consoleLogOptions =>
{
// Configure all logs to go to stderr
consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});

builder.Services
.AddMcpServer()
.WithStdioServerTransport()
.WithToolsFromAssembly();

await builder.Build().RunAsync();

[McpServerToolType]
public class LaTeX(IHttpClientFactory httpFactory)
{
[McpServerTool, Description("Converts LaTeX equations into markdown-formatted images for display inline.")]
public async Task<string> LatexToImageMarkdown(
[Description("The LaTeX equation to render.")] string latex,
[Description("Use dark mode by inverting the colors in the output.")] bool darkMode)
{
var colors = darkMode ? @"\bg{black}\fg{white}" : @"\bg{white}\fg{black}";
var query = WebUtility.UrlEncode(@"\small\dpi{300}" + colors + latex);
var url = $"https://latex.codecogs.com/png.image?{query}";
using var client = httpFactory.CreateClient();
using var response = await client.GetAsync(url);

if (response.IsSuccessStatusCode)
{
using var image = Image.Load<Rgba32>(await response.Content.ReadAsStreamAsync());
using var ms = new MemoryStream();
image.SaveAsPng(ms);
var base64 = Convert.ToBase64String(ms.ToArray());
return
$"""
![{latex}](
data:image/png;base64,{base64}
)
""";
}
else
{
return
$"""
```latex
{latex}
```
> {response.ReasonPhrase}
""";
}
}
}
23 changes: 23 additions & 0 deletions src/HostedDemo/HostedDemo.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="..\Smith\Smith.props" />

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Anthropic" Version="3.7.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.7" />
<PackageReference Include="Spectre.Console" Version="0.50.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Smith\Smith.csproj" />
</ItemGroup>


<Import Project="..\Smith\Smith.targets" />

</Project>
72 changes: 72 additions & 0 deletions src/HostedDemo/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using Anthropic;

const string Instructions =
"""
Your responses will be rendered using Spectre.Console.AnsiConsole.Write(new Markup(string text))).
This means that you can use rich text formatting, colors, and styles in your responses, but you must
ensure that the text is valid markup syntax.
""";

var builder = App.CreateBuilder(args);
builder.Services.AddHttpClient();

builder.Services
.AddChatClient(services => new AnthropicClient(
Throw.IfNullOrEmpty(Env.Get("ANTHROPIC_KEY")),
services.GetRequiredService<IHttpClientFactory>().CreateClient()))
.UseLogging()
.UseFunctionInvocation();

var app = builder.Build(async (IChatClient chat, CancellationToken token) =>
{
var history = new List<ChatMessage> { new(ChatRole.System, Instructions) };
var options = new ChatOptions
{
ModelId = "claude-sonnet-4-20250514",
MaxOutputTokens = 1000,
Temperature = 0.7f,
Tools = [AIFunctionFactory.Create(() => DateTime.Now, "get_datetime", "Gets the current date and time on the user's local machine.")]
};

AnsiConsole.MarkupLine($":robot: Ready");
AnsiConsole.Markup($":person_beard: ");
while (!token.IsCancellationRequested)
{
var input = Console.ReadLine()?.Trim();
if (string.IsNullOrEmpty(input))
continue;

history.Add(new ChatMessage(ChatRole.User, input));
try
{
var response = await AnsiConsole.Status().StartAsync(":robot: Thinking...",
ctx => chat.GetResponseAsync(input, options));

history.AddRange(response.Messages);
try
{
// Try rendering as formatted markup
if (response.Text is { Length: > 0 })
AnsiConsole.MarkupLine($":robot: {response.Text}");
}
catch (Exception)
{
// Fallback to escaped markup text if rendering fails
AnsiConsole.MarkupLineInterpolated($":robot: {response.Text}");
}

AnsiConsole.Markup($":person_beard: ");
}
catch (Exception e)
{
AnsiConsole.WriteException(e);
}
}

AnsiConsole.MarkupLine($":robot: Shutting down...");
});

Console.WriteLine("Powered by Smith");


await app.RunAsync();
13 changes: 13 additions & 0 deletions src/HostedDemo/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"logging": {
"logLevel": {
"default": "Information",
"Polly": "Warning",
"System.Net.Http.HttpClient": "Warning",
"Microsoft.AspNetCore": "Warning",
"Microsoft.Extensions": "Warning",
"Microsoft.Azure": "Warning",
"Microsoft.Hosting": "Warning"
}
}
}
23 changes: 23 additions & 0 deletions src/MCPDemo/MCPDemo.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="..\Smith\Smith.props" />

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.7" />
<PackageReference Include="ModelContextProtocol" Version="0.3.0-preview.2" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.10" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Smith\Smith.csproj" />
</ItemGroup>


<Import Project="..\Smith\Smith.targets" />

</Project>
58 changes: 58 additions & 0 deletions src/MCPDemo/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using ModelContextProtocol.Server;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

var builder = App.CreateBuilder(args);
builder.Services.AddHttpClient();
builder.Logging.AddConsole(consoleLogOptions =>
{
// Configure all logs to go to stderr
consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});

builder.Services
.AddMcpServer()
.WithStdioServerTransport()
.WithToolsFromAssembly();

await builder.Build().RunAsync();

[McpServerToolType]
public class LaTeX(IHttpClientFactory httpFactory)
{
[McpServerTool, Description("Converts LaTeX equations into markdown-formatted images for display inline.")]
public async Task<string> LatexToImageMarkdown(
[Description("The LaTeX equation to render.")] string latex,
[Description("Use dark mode by inverting the colors in the output.")] bool darkMode)
{
var colors = darkMode ? @"\bg{black}\fg{white}" : @"\bg{white}\fg{black}";
var query = WebUtility.UrlEncode(@"\small\dpi{300}" + colors + latex);
var url = $"https://latex.codecogs.com/png.image?{query}";
using var client = httpFactory.CreateClient();
using var response = await client.GetAsync(url);

if (response.IsSuccessStatusCode)
{
using var image = Image.Load<Rgba32>(await response.Content.ReadAsStreamAsync());
using var ms = new MemoryStream();
image.SaveAsPng(ms);
var base64 = Convert.ToBase64String(ms.ToArray());
return
$"""
![{latex}](
data:image/png;base64,{base64}
)
""";
}
else
{
return
$"""
```latex
{latex}
```
> {response.ReasonPhrase}
""";
}
}
}
13 changes: 13 additions & 0 deletions src/MCPDemo/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"logging": {
"logLevel": {
"default": "Information",
"Polly": "Warning",
"System.Net.Http.HttpClient": "Warning",
"Microsoft.AspNetCore": "Warning",
"Microsoft.Extensions": "Warning",
"Microsoft.Azure": "Warning",
"Microsoft.Hosting": "Warning"
}
}
}
Loading