Table of Contents

Create Multi-Turn AI Chatbot with MCP in .NET Applications


🎯 Purpose of the Sample

Multi-Turn AI Chatbot with MCP demonstrates how LM-Kit.NET connects to Model Context Protocol (MCP) servers and exposes their tools to your assistant. During the conversation, the model can decide to call one or multiple MCP tools with JSON arguments, receive JSON results, and use them to craft grounded replies while preserving full multi-turn context.

MCP tools are discovered dynamically from the server and registered into LM-Kit’s ToolRegistry. Runtime behavior can be shaped via ToolChoice.

Why MCP?

  • Plug-in catalog: fetch tools from remote servers on demand.
  • Agentic chaining: the assistant can call several tools per turn and combine outputs.
  • Typed contracts: JSON-RPC + JSON schemas for safer calls and clearer failures.
  • Live updates: react to catalog change events from the server.
  • Separation of concerns: servers own business logic; the model focuses on reasoning.

👥 Target Audience

  • Platform & Product – wire assistants to internal/external MCP services
  • Ops & Integrations – standardize tool catalogs across teams
  • Demo & Education – minimal example of MCP + tool-calling in chat
  • B2B Apps – auditable actions via remote tools

🚀 Problem Solved

  • Dynamic capabilities: add/remove tools by switching MCP servers.
  • Grounded answers: results come from known services and APIs.
  • Multi-turn memory: context is preserved across tool calls and server switches.
  • Operational visibility: event hooks log requests, responses, and catalog updates.

💻 Sample Application Description

Console app that:

  • Lets you choose a local model (or a custom URI).
  • Connects to a selected MCP server (public list or custom URI).
  • Registers all server tools into the chat’s ToolRegistry.
  • Runs a multi-turn chat where the model decides when to call MCP tools.
  • Prints generation stats (tokens, stop reason, speed, context usage) and MCP logs.

✨ Key Features

  • 🔌 MCP Integration: discover tools, prompts, and resources from a server.
  • 🧩 Multiple Tool Calls: several invocations in one turn, or across turns.
  • 🧠 Context Retention: full dialogue history.
  • 📈 Telemetry: color-coded streaming (reasoning/tool/user), plus gen stats.
  • 🔁 Live Catalog: reacts to Tools/Prompts/Resources Changed events.
  • 🔐 Optional Auth: set a bearer token for protected servers.
  • 📝 Special Commands: /reset, /continue, /regenerate, /server (switch MCP).

🧰 Built-In MCP Servers (menu)

Option Server (Public unless noted) Purpose / Example uses Auth
0 Echo MCP Echo input for sanity checks & debugging No
1 Time MCP Time & timezone utilities No
2 DeepWiki Ask questions over public GitHub repos No
3 Text Extractor Extract clean text/Markdown from URLs No
4 Everything Reference server (prompts/resources/tools) No
5 Microsoft Learn Docs Search & fetch MS Learn docs No
6 Peek Experiences/activities discovery No
7 Currency (Wes Bos) FX conversion via MCP tool No
8 Find-A-Domain Domain ideas & WHOIS lookup No
9 Hugging Face MCP Models, datasets, spaces Yes

Custom servers are supported: paste any MCP endpoint URI, then optionally provide a token.


🧠 Supported Models

Pick per hardware (defaults provided):

  • Mistral Nemo 2407 12.2B (~7.7 GB VRAM)
  • Meta Llama 3.1 8B (~6 GB VRAM)
  • Google Gemma 3 4B Medium (~4 GB VRAM)
  • Microsoft Phi-4 Mini 3.82B (~3.3 GB VRAM)
  • Alibaba Qwen-3 8B (~5.6 GB VRAM)
  • Microsoft Phi-4 14.7B (~11 GB VRAM)
  • IBM Granite 4 7B (~6 GB VRAM)
  • Open-AI GPT OSS 20B (~16 GB VRAM)

Or provide a custom model URI (GGUF/LMK).


🛠️ Commands

  • /reset – clear conversation
  • /continue – continue last assistant message
  • /regenerate – new answer for last user input
  • /server – switch to another MCP server (re-register tools automatically)

🗣️ Example Prompts

  • “What time is it in Tokyo and New York?” (Time MCP)
  • “Extract and summarize the main points from https://…(Text Extractor)
  • “Search Microsoft Learn for HttpClient best practices and give the link + 3 bullets.” (MS Learn Docs)
  • “Suggest 10 .dev domains for greenhub and check availability.” (Find-A-Domain)
  • “Convert 125 USD to EUR and show a 7-day trend.” (Currency MCP)
  • “What are common pitfalls when contributing to numpy/numpy? Cite sources.” (DeepWiki)
  • “Family-friendly activities in Paris this weekend?” (Peek)

Chain calls naturally: “Get the article text from this URL, then summarize it for a non-technical audience in 5 bullets.”


⚙️ Behavior & Policies (quick reference)

  • Tool selection policy: let the model decide by default; configure per turn via ToolChoice to Auto / Require / Forbid / Force.
  • Multiple tool calls: runtime supports several invocations per turn; outputs are injected back into context.
  • MCP lifecycle: McpClient handles session init, retries (408/429/5xx), content negotiation, and SSE notifications.
  • Catalog changes: reacts to ToolsChanged / PromptsChanged / ResourcesChanged; caches refresh automatically.
  • Auth: call SetBearerToken(string) if the server requires it.
  • Networking: MCP tools depend on server connectivity; failures are surfaced with clear errors.
  • Schemas matter: precise tool schemas/descriptions improve argument construction and determinism.
  • Tracing: sample logs Sending/Received MCP messages and color-codes streamed segments (internal/tool/user). Disable or customize in Chat_AfterTextCompletion.

💻 Minimal Integration Snippet

// Connect and register all MCP tools into the chat
var mcp = new McpClient(serverUri);
mcp.SetBearerToken(tokenIfAny);
chat.Tools.Register(mcp); // adds server tools to ToolRegistry

Switch servers at runtime with the /server command; the sample removes prior tools, connects to the new server, re-registers, and resets the history.


🛠️ Getting Started

📋 Prerequisites

  • .NET Framework 4.6.2 or .NET 6.0

📥 Download

git clone https://github.com/LM-Kit/lm-kit-net-samples.git
cd lm-kit-net-samples/console_net/multi_turn_chat_with_mcp

Project Link: multi_turn_chat_with_mcp (same path as above)

▶️ Run

dotnet build
dotnet run

Then:

  • Pick a model or paste a custom model URI.
  • Choose an MCP server from the menu (or enter a custom URI).
  • If prompted, paste a Bearer token for authenticated servers.
  • Chat naturally; the assistant will call one or multiple MCP tools as needed.
  • Use /reset, /continue, /regenerate, or /server anytime.

🔍 Notes on Key Types

  • McpClient – connects to MCP over HTTP/JSON-RPC 2.0; discovers tools/resources/prompts; exposes:

    • GetToolsAsync(), ReadResourceAsync(), GetPromptsAsync()
    • Events: CatalogChanged, ToolsChanged, PromptsChanged, ResourcesChanged, AuthFailed, Sending, Received
    • SetBearerToken(string) for authentication
  • ToolRegistry – enforces unique tool names, validates schemas, and registers tools in bulk:

    • Register(McpClient …), Remove(string), EnsureValid(ToolCallPolicy)

⚠️ Troubleshooting

  • 401/403 – set or refresh the bearer token; see AuthFailed event output.
  • 429/5xx – automatic retries are enabled; try again or reduce call rate.
  • No tools appear – verify the MCP endpoint URL and that tools/list is supported.
  • Model won’t call tools – check ToolChoice policy and tool descriptions/schemas.

🔧 Extend the Demo

  • Point to your own MCP server to expose internal actions (knowledge search, ticketing, analytics, etc.).
  • Filter which tools to register by name/prefix when calling chat.Tools.Register(mcpClient, filter: …).
  • Customize streaming, logging, and color-coding in Chat_AfterTextCompletion.