MCP Tools

Live on this server

Provides tools to AI agents such as Claude via the Model Context Protocol.

McpSample.cs75 lines
using System.ComponentModel.DataAnnotations;

using GenHTTP.Api.Content;
using GenHTTP.Api.Content.Documentation;
using GenHTTP.Api.Protocol;

using GenHTTP.Modules.Mcp;

public static class McpSample
{

    public static IHandlerBuilder Create()
    {
        /*
         *
         * Shows how to provide tools to AI agents such as Claude via the
         * Model Context Protocol (MCP).
         *
         * Add the endpoint to Claude Code via
         *
         *   claude mcp add --transport http library https://genhttp.org/samples/mcp/
         *
         * and ask, for example, "Which books about Rome are in the library?".
         *
         * See https://genhttp.org/documentation/content/frameworks/mcp/
         *
         */

        return Tools.Create()
                    .Server("library", "1.0.0", "Library")
                    .Instructions("Search for books before lending them to a reader.")
                    .Add<LibraryTools>()
                    .Add("get_time", "Returns the current time of the library (UTC)", [Tool(ReadOnly = true)] () => DateTime.UtcNow)
                    // agents may call from anywhere, browsers only from the pages of this website
                    .AllowOrigin("https://genhttp.org")
                    .AllowOrigin("https://genhttp.dev");
    }

    public record Book(int Id, string Title, string? LentTo);

    public class LibraryTools
    {
        private static readonly List<Book> Books =
        [
            new(1, "SPQR: A History of Ancient Rome", null),
            new(2, "The Lord of the Rings", null)
        ];

        [Tool(ReadOnly = true)]
        [Summary("Searches the books of the library by title")]
        public List<Book> FindBooks([Summary("Part of the title, e.g. 'Rome'")] string query, [Range(1, 50)] int limit = 10)
            => Books.Where(b => b.Title.Contains(query, StringComparison.OrdinalIgnoreCase)).Take(limit).ToList();

        [Tool(Destructive = false)]
        [Summary("Lends a book to a reader")]
        public Book LendBook([Summary("The id of the book, as returned by find_books")] int bookId, [Summary("The name of the reader")] string reader)
        {
            var book = Books.FirstOrDefault(b => b.Id == bookId)
                       ?? throw new ProviderException(ResponseStatus.NotFound, $"There is no book with id {bookId}.");

            if (book.LentTo != null)
            {
                throw new ProviderException(ResponseStatus.Conflict, $"'{book.Title}' is already lent to {book.LentTo}.");
            }

            var lent = book with { LentTo = reader };

            Books[Books.IndexOf(book)] = lent;

            return lent;
        }

    }

}

Try it

Send the requests to the sample running on this server - change the path, headers or body as you like, or copy them as curl commands.

  1. Add the server to Claude Code

    Then ask Claude "Which books about Rome are in the library?"

    claude mcp add --transport http library https://genhttp.org/samples/mcp/
  2. List the tools, as an agent would

    POST
    Headers and body
    curl -i -X POST -H 'Content-Type: application/json' -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }' 'https://genhttp.org/samples/mcp/'
  3. Call a tool

    POST
    Headers and body
    curl -i -X POST -H 'Content-Type: application/json' -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "find_books", "arguments": { "query": "Rome" } } }' 'https://genhttp.org/samples/mcp/'