Skip to content

mohamed-ali-21/SimpleMCP

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 

Repository files navigation

MCP Learning Project

A minimal end-to-end Model Context Protocol sample written in .NET 9, showing both sides of the protocol:

  • SimpleMcpServer — an ASP.NET Core MCP server built on ModelContextProtocol.AspNetCore that exposes tools, resources, and prompts.
  • SimpleMcpClient — a console client built on ModelContextProtocol that connects over Streamable HTTP, lists every capability the server advertises, and exercises each one.

Repository layout

MCP/
├── SimpleMcpServer/                      # ASP.NET Core MCP server (HTTP transport)
│   ├── Program.cs                        # Server bootstrap + ServerInfo / instructions
│   ├── appsettings.json                  # Logging configuration
│   ├── Tools/
│   │   ├── CalculatorTools.cs            # calc_add, calc_subtract, calc_multiply,
│   │   │                                 # calc_divide, calc_power, calc_sqrt
│   │   ├── TextTools.cs                  # text_echo, text_reverse, text_word_count,
│   │   │                                 # text_to_upper, text_to_lower
│   │   └── TimeTools.cs                  # time_now_utc, time_now_in_zone,
│   │                                     # time_diff_seconds
│   ├── Resources/
│   │   └── AppResources.cs               # info://server (static)
│   │                                     # greeting://{name}, echo://{message} (templated)
│   └── Prompts/
│       └── AppPrompts.cs                 # code_review, summarize, explain_like_im_five
│
└── SimpleMcpClient/                      # Console MCP client
    └── Program.cs                        # Connects, lists, and calls every capability

Requirements

  • .NET 9 SDK
  • Windows, macOS, or Linux

NuGet packages (already referenced):

Project Package Version
SimpleMcpServer ModelContextProtocol.AspNetCore 1.3.0
SimpleMcpClient ModelContextProtocol 1.3.0

Running the server

cd SimpleMcpServer
dotnet run --launch-profile http

The server listens on http://localhost:5116/. The MCP Streamable HTTP endpoint is mounted at the root path (/) by app.MapMcp().

Server identity advertised to clients:

{
  "name": "SimpleMcpServer",
  "version": "1.0.0",
  "instructions": "A demo MCP server exposing calculator, text and time tools, static and templated resources, and reusable prompt templates."
}

Running the client

In a second terminal, with the server already running:

cd SimpleMcpClient
dotnet run                            # uses default http://localhost:5116/
dotnet run -- http://localhost:5116/  # or pass a custom endpoint

Expected output (abridged):

Connected. Server: SimpleMcpServer v1.0.0

== Tools ==
  calc_add              Adds two numbers and returns the sum.
  ...

-> calc_add(2, 3)
  -> 5

-> text_reverse("Hello, MCP!")
  -> !PCM ,olleH

-> calc_divide(10, 0)  // expected to fail
  (server reported tool error)
  -> An error occurred invoking 'calc_divide': Cannot divide by zero.

== Resources ==
  info://server   Static metadata about this MCP server (name, version, build host).

== Resource templates ==
  greeting://{name}    Returns a friendly greeting for the given name.
  echo://{message}     Echoes the message segment of the URI back to the caller.

Server features

Tools (14)

Name Description
calc_add, calc_subtract, calc_multiply, calc_divide, calc_power, calc_sqrt Basic arithmetic; calc_divide and calc_sqrt validate inputs and throw McpException on bad arguments.
text_echo, text_reverse, text_word_count, text_to_upper, text_to_lower String utilities.
time_now_utc, time_now_in_zone, time_diff_seconds Time helpers; time_now_in_zone accepts IANA or Windows time-zone ids.

Resources

  • Static: info://server returns JSON metadata (server name, version, host, runtime).
  • Templated: greeting://{name} and echo://{message} return text computed from the URI segment.

Prompts

  • code_review(code, language="csharp") — emits a structured code-review prompt.
  • summarize(text, maxSentences=3) — emits a summarization prompt.
  • explain_like_im_five(topic) — emits an ELI5 prompt.

How it is wired

Server registration (SimpleMcpServer/Program.cs)

builder.Services
    .AddMcpServer(options =>
    {
        options.ServerInfo = new Implementation { Name = "SimpleMcpServer", Version = "1.0.0" };
        options.ServerInstructions = "...";
    })
    .WithHttpTransport()
    .WithToolsFromAssembly()
    .WithPromptsFromAssembly()
    .WithResourcesFromAssembly();

app.MapMcp();

WithToolsFromAssembly() (and the prompt/resource equivalents) auto-register every class tagged with [McpServerToolType] / [McpServerPromptType] / [McpServerResourceType]. Adding a new file is the only step needed for new capabilities; no manual registration is required.

Tool authoring pattern

[McpServerToolType]
public sealed class CalculatorTools
{
    [McpServerTool(Name = "calc_add"), Description("Adds two numbers.")]
    public double Add(
        [Description("First addend.")]  double a,
        [Description("Second addend.")] double b) => a + b;
}

The [Description] attributes flow into the JSON schema clients receive — that is what lets an LLM pick the right tool and fill its arguments correctly.

Client connection (SimpleMcpClient/Program.cs)

var transport = new HttpClientTransport(new HttpClientTransportOptions
{
    Endpoint = new Uri("http://localhost:5116/"),
    Name = "SimpleMcpClient"
    // TransportMode defaults to AutoDetect:
    //   tries Streamable HTTP, falls back to SSE
});

await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
{
    ClientInfo = new Implementation { Name = "SimpleMcpClient", Version = "1.0.0" }
});

var tools   = await client.ListToolsAsync();
var result  = await client.CallToolAsync("calc_add",
                  new Dictionary<string, object?> { ["a"] = 2, ["b"] = 3 });

Using the server from an MCP-aware tool

Cursor (~/.cursor/mcp.json)

{
  "mcpServers": {
    "SimpleMcp": {
      "type": "http",
      "url": "http://localhost:5116/"
    }
  }
}

Claude Code

claude mcp add --transport http simple http://localhost:5116/

Note on HTTPS: the project ships with an http launch profile on localhost:5116. If you switch to https://localhost:7297, most MCP clients will refuse the ASP.NET dev cert. Either keep using http for local development, or run dotnet dev-certs https --trust and ensure the cert is in the trust store the client uses.

Error handling

Tools raise McpException for invalid arguments (e.g. divide by zero, bad time-zone, malformed timestamp). ModelContextProtocol.Core 1.3.0 only exposes the standard Exception constructors on McpException, so error codes are not specified explicitly — the message is what reaches the client as an IsError=true tool result.

License

For learning / demo purposes. No warranty.

About

A lightweight learning project for practicing how to implement both an MCP Server and MCP Client using the Model Context Protocol SDK.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages