MCP Apps Demo

May 20, 2026 ยท View on GitHub

This repository contains two C# Model Context Protocol (MCP) demos:

  • Sample/: the smallest possible stdio MCP server, useful for learning the basics.
  • src/GroceryInventory.Api/: a richer HTTP MCP server plus REST API for a grocery inventory scenario, including tools, prompts, resources, completions, notifications, logging, elicitation, sampling, roots, and an MCP App dashboard.

The main goal is to show colleagues and customers what MCP looks like across a maturity curve:

  • starting with a deterministic tool-only server,
  • moving into structured prompts and resources,
  • then layering on advanced client-mediated capabilities like sampling, elicitation, logging, notifications, and interactive UI.

Why This Repo Is Worth Sharing

This repo is useful when you want to show customers or internal teams:

  • how to expose business data and actions through MCP without inventing a new agent framework,
  • when MCP tools are a better fit than raw prompt engineering,
  • why prompts, resources, and completions make agent experiences more reliable,
  • how to keep deterministic operations separate from model-driven reasoning,
  • what an MCP App experience looks like when the client can render HTML UI,
  • how the same domain can be offered through both REST and MCP.

Repo Map

PathWhat it isWhen to use it
Sample/Minimal stdio MCP server with one random-number toolWhen you need the fastest possible onboarding example
src/GroceryInventory.Api/Main grocery inventory demo using HTTP transportWhen you want a realistic business scenario with multiple MCP capabilities
src/GroceryInventory.Api/McpTools/Tool, prompt, resource, completion, sampling, elicitation, and roots implementationsWhen extending or reviewing the MCP surface
src/GroceryInventory.Api/McpApp/Vite-based single-file dashboard UI bundleWhen demonstrating MCP Apps or chat-adjacent visual experiences
src/GroceryInventory.Api/GroceryMcpTools.httpEnd-to-end JSON-RPC request collection for MCP manual testingWhen you want to inspect protocol calls directly
src/GroceryInventory.Api/GroceryRestEndpoints.httpREST request collection for the HTTP APIWhen comparing REST with MCP or testing deterministic APIs
.vscode/mcp.jsonVS Code MCP server registrationWhen connecting the running server to Copilot Chat

Architecture At A Glance

The main demo intentionally exposes the same grocery domain in two ways:

  • REST API for conventional application integration.
  • MCP server for AI-assisted workflows, interactive chat tools, prompt templates, resources, and UI.

That split makes it easier to explain to customers that MCP is not a replacement for their application backend. It is a focused agent-facing contract layered on top of their domain model.

Prerequisites

For the full grocery demo:

  • .NET 10 SDK
  • Node.js 20+ and npm
  • VS Code with Copilot Chat if you want to use the MCP server from chat
  • Optional: REST Client extension for VS Code if you want to run the .http files directly

For the minimal sample only:

  • .NET 10 SDK

Quick Start

Run the Grocery Inventory demo

From the repo root:

dotnet restore .\MCPAppsDemo.slnx
dotnet run --project .\src\GroceryInventory.Api

What happens:

  • The app starts an HTTP API and an HTTP MCP endpoint.
  • The MCP endpoint is available at http://localhost:5256/mcp.
  • The REST root probe is available at http://localhost:5256/.
  • OpenAPI is available at http://localhost:5256/openapi/v1.json in development.
  • The .csproj automatically builds the dashboard bundle from src/GroceryInventory.Api/McpApp/ before the .NET build.

If you need to skip the dashboard build because Node is not installed:

dotnet run --project .\src\GroceryInventory.Api -p:BuildMcpApp=false

In that mode, the server still runs, but the MCP App dashboard resource will show a placeholder unless McpApp/dist/index.html already exists.

Run the minimal sample

dotnet run --project .\Sample

Use this when you want the smallest possible teaching sample before introducing the richer grocery scenario.

Connect From VS Code Copilot Chat

This repo already includes .vscode/mcp.json:

{
  "servers": {
    "Grocery MCP Demo": {
      "type": "http",
      "url": "http://localhost:5256/mcp"
    }
  }
}

How to use it:

  1. Start the grocery API with dotnet run --project .\src\GroceryInventory.Api.
  2. Open the workspace in VS Code.
  3. Make sure the MCP server is enabled in Copilot Chat.
  4. Ask Copilot to use the server, for example:
    • Show the store inventory dashboard.
    • List low-stock items for store 2.
    • Analyze Riverbend Foods inventory health.
    • Explain shrinkage in plain language.

Why customers like this flow:

  • It keeps the MCP configuration local to the workspace.
  • It demonstrates how business tools can feel native inside the chat UI.
  • It lowers the barrier for non-developers who do not want to craft raw JSON-RPC requests.

Manual MCP Testing With The HTTP Collection

Open src/GroceryInventory.Api/GroceryMcpTools.http and run the requests in order.

The first-time handshake is:

  1. initialize
  2. notifications/initialized
  3. any tools/list, resources/list, prompts/list, or tools/call request

This file is useful when you want to:

  • inspect the exact JSON-RPC payloads,
  • demonstrate session handling using Mcp-Session-Id,
  • test individual MCP features in isolation,
  • compare what works in a generic REST client versus a richer MCP-aware host.

Important limitation:

  • The .http file behaves like a plain client and does not advertise advanced client capabilities such as sampling, elicitation, or roots during initialize.
  • That means requests like recommend_restocks, plan_bulk_restock, and list_client_roots are useful for showing capability negotiation, but not always for demonstrating the happy path.

REST API Testing

The grocery project is also a standard ASP.NET Core API.

Representative routes:

  • /api/categories
  • /api/suppliers
  • /api/stores
  • /api/products
  • /api/inventory/stores/{storeId}
  • /api/inventory/products/{productId}
  • /api/inventory/stores/{storeId}/products/{productId}
  • /api/inventory/low-stock

This dual-surface design is valuable for customers because it makes the boundary clear:

  • REST remains the conventional application contract.
  • MCP is the AI-facing contract that packages the most useful tasks for agents and copilots.

Capability Overview

CapabilityPrimary entry pointHow to use itWhen a customer gets valueWhy it matters
Reference data lookupget_categories, get_suppliers, get_stores, get_productsCall the tool directly from chat or JSON-RPCWhen an agent must ground itself in real catalog, store, or supplier dataReliable, deterministic reads reduce hallucinations and bad follow-up actions
Inventory state and mutationsget_inventory, set_inventory, adjust_stock, get_low_stockUse tools to read inventory, update counts, or identify shortagesWhen workflows need operational actions, not just analysisTurns chat from passive Q and A into useful business operations
MCP App dashboardshow_store_inventory_dashboard plus ui://grocery/store-dashboard.htmlCall the tool from an MCP App-aware clientWhen users need a visual, multi-store inventory viewEasier for humans to validate and act on than raw JSON alone
Prompt templatesprompts/list, prompts/getDiscover prompts, then request prompt messages with typed argumentsWhen you want reusable, repeatable AI tasksReduces prompt engineering overhead and standardizes outcomes
Resource templatesresources/templates/list, resources/readDiscover URI templates, then substitute concrete IDsWhen you need dynamic, read-only context with stable URIsKeeps frequently requested business views simple and discoverable
Argument completionscompletion/completeAsk for suggestions using a prompt or resource reference plus partial inputWhen users type IDs or known termsImproves UX and reduces invalid argument errors
Sampling-based reasoningrecommend_restocksInvoke from a client that supports sampling and has a connected modelWhen deterministic rules are not enough and prioritization needs judgmentLets the customer reuse the client's model access instead of baking model access into the server
Elicitation-based planningplan_bulk_restockInvoke from a client that supports elicitationWhen the server should ask the human for budget, scope, or preferences before actingHuman-in-the-loop planning is safer and more controllable than guessing
Notifications and loggingresources/updated, logging/setLevel, SSEListen on the event stream and opt into log levelsWhen clients need live updates and traceabilityEnables reactive UX and better debugging
Rootslist_client_rootsInvoke from a client that advertises rootsWhen server behavior should be aware of workspace or project contextHelps future tools stay scoped to the user's real working set
Minimal starter serverSample/Run the stdio sample and call get_random_numberWhen the audience is new to MCP and should start smallLowest-friction teaching sample before introducing advanced patterns

Detailed Capability Guide

1. Reference Data Lookup Tools

Tools:

  • get_categories
  • get_suppliers
  • get_stores
  • get_products

How to use:

  • Ask Copilot a domain question like List the suppliers or Show products in category 2.
  • Or call tools/call with the tool name and optional filters such as id, categoryId, or supplierId.

When to use:

  • At the beginning of any workflow that needs trusted business context.
  • When the client needs to resolve IDs before calling mutation tools or resource templates.
  • When you want a compact tool surface instead of exposing many tiny, overlapping endpoints to the model.

Why customers get value:

  • Lookup tools give the model structured facts instead of forcing it to infer domain state.
  • They are deterministic and cheap, so they are ideal for high-frequency grounding.
  • They show how to wrap ordinary line-of-business data in MCP without overcomplicating the tool design.

Good customer scenarios:

  • A store operations copilot that needs store and supplier metadata before creating an order.
  • A planning assistant that filters products by category or supplier.
  • A support agent that needs quick answers about locations, suppliers, or SKUs.

2. Inventory State And Mutation Tools

Tools:

  • get_inventory
  • set_inventory
  • adjust_stock
  • get_low_stock

How to use:

  • Use get_inventory for chain-wide, per-store, per-product, or single-row inventory reads.
  • Use set_inventory to create or replace an inventory record with absolute values.
  • Use adjust_stock for relative changes such as sales, shrinkage, or restocks.
  • Use get_low_stock to find rows at or below threshold, optionally scoped to one store.

When to use:

  • When you need the model to perform operational tasks rather than just explain data.
  • When you want to simulate or automate receiving, sales adjustments, or restocking.
  • When low-stock detection should be deterministic and fast.

Why customers get value:

  • This is the core pattern many customers care about: expose safe business actions in a tool contract.
  • It demonstrates the difference between absolute updates and relative adjustments.
  • It makes inventory workflows auditable and repeatable.

Good customer scenarios:

  • Store managers adjusting stock after cycle counts.
  • Loss-prevention or shrink analysis flows that subtract known losses.
  • Automated low-stock monitoring feeding downstream planning or ordering.

Important note:

  • The demo uses a singleton in-memory store seeded from SeedData.cs.
  • Changes persist for the lifetime of the running process only.
  • Restarting the app resets the dataset.

3. MCP App Dashboard

Tool and resource:

  • show_store_inventory_dashboard
  • ui://grocery/store-dashboard.html

How to use:

  • Invoke show_store_inventory_dashboard from an MCP App-aware client.
  • The tool returns structured snapshot data plus _meta.ui.resourceUri, which tells the client which HTML resource to render.
  • The HTML bundle is served from src/GroceryInventory.Api/McpApp/dist/index.html.

When to use:

  • When raw JSON is not enough and the user needs a visual inventory review.
  • When you want a human to compare stores, scan KPIs, and validate outliers quickly.
  • When demonstrating that MCP can pair tools with UI, not just text.

Why customers get value:

  • Visual validation builds trust in the tool output.
  • Dashboards reduce cognitive load for operations users who are not developers.
  • It shows a practical path from tool output to richer task-oriented interfaces.

Good customer scenarios:

  • Daily inventory standups.
  • District manager reviews across multiple stores.
  • Human-in-the-loop approval before acting on tool recommendations.

4. Prompt Templates

Prompts:

  • analyze_store_performance
  • draft_supplier_order
  • explain_inventory_term

How to use:

  • Call prompts/list to discover available prompt templates.
  • Call prompts/get with the prompt name and typed arguments.
  • The server returns prompt messages ready for the client to send to its LLM.

When to use:

  • When you have recurring AI tasks with a stable structure.
  • When you want to package domain-specific analysis or writing tasks without building a new tool.
  • When business users should not need to know the exact prompt wording.

Why customers get value:

  • Prompt templates provide consistency without hardcoding a single model response.
  • They keep the domain context close to the server instead of scattering prompts across clients.
  • They are ideal for reusable workflows such as store reviews, draft purchase orders, or glossary explanations.

Good customer scenarios:

  • A category manager wants consistent store health analysis across locations.
  • A purchasing assistant needs a first draft supplier order from current shortages.
  • A frontline worker needs a plain-language explanation of inventory terms.

5. Resource Templates

Templates:

  • inventory://stores/{storeId}/summary
  • inventory://products/{productId}/details

How to use:

  • Call resources/templates/list to discover parameterized resources.
  • Substitute real values into the URI template.
  • Call resources/read with the concrete URI, for example inventory://stores/3/summary.

When to use:

  • When a client needs structured read-only context that should behave like addressable content.
  • When you want stable URIs for repeatable access, caching, or linking.
  • When tool invocation would be heavier than necessary for a read operation.

Why customers get value:

  • Resource templates make dynamic business views discoverable without proliferating bespoke tools.
  • They align well with clients that want to browse or fetch reference material on demand.
  • They are especially good for summaries, details pages, and reusable context payloads.

Good customer scenarios:

  • A copilot loading a store summary before drafting an operational update.
  • A product assistant fetching chain-wide stock detail for one SKU.
  • A dashboard experience that deep-links into resource-backed detail views.

6. Argument Completions

Completion entry point:

  • completion/complete

How to use:

  • Provide a ref describing either a prompt or a resource template.
  • Provide the argument name and the partial value typed so far.
  • The server returns filtered suggestions.
  • Some arguments, such as urgencyLevel, are supplied automatically from [AllowedValues] on the prompt definition.

When to use:

  • When users type store IDs, product IDs, supplier IDs, or known domain terms.
  • When you are building a client UI that should guide correct parameter entry.
  • When you want to reduce bad calls caused by typos or unknown values.

Why customers get value:

  • Completions are a simple but high-impact usability feature.
  • They reduce error rates without requiring a large custom UI.
  • They make prompt and resource invocation feel more like an application and less like manual protocol work.

Good customer scenarios:

  • Prompt forms in chat.
  • Resource browsers with inline search.
  • Guided data-entry experiences for store operators.

7. Sampling-Based Restock Recommendations

Tool:

  • recommend_restocks

How to use:

  • Invoke the tool from an MCP client that advertises the sampling capability.
  • Make sure the client has a connected model.
  • Optionally pass storeId to scope the recommendation and maxRecommendations to cap input size.
  • The server gathers low-stock context, then asks the client-side model to prioritize and size recommended orders.

When to use:

  • When deterministic reorder rules are not sufficient.
  • When urgency should reflect tradeoffs such as perishability, unit price exposure, and depth below threshold.
  • When you want model reasoning but do not want to host model credentials inside the server.

Why customers get value:

  • This is a realistic pattern for enterprises that already govern model access in the client layer.
  • The server owns business context; the client owns model access.
  • It lets customers add reasoning to existing deterministic systems without rewriting their backend around an LLM.

Good customer scenarios:

  • Prioritizing which low-stock items deserve same-day attention.
  • Generating a ranked list for a purchasing or store operations team.
  • Comparing model-driven prioritization with simple threshold-based ordering.

Important caveats:

  • A generic REST client will not satisfy sampling/createMessage.
  • If the client reports Model is not connected, connect or select a model in the host first.
  • The server can send model hints, but the final model availability is controlled by the client host.

8. Elicitation-Based Bulk Restock Planning

Tool:

  • plan_bulk_restock

How to use:

  • Invoke the tool from a client that supports elicitation.
  • The server presents a form asking for store, budget, categories, and whether to include near-threshold items.
  • After the user responds, the server builds a filtered restock plan capped to the chosen budget.

When to use:

  • When the user, not the model, should provide operating constraints before planning.
  • When you need budget-aware or category-scoped planning.
  • When you want a safer, approval-friendly alternative to freeform agent action.

Why customers get value:

  • Elicitation is a strong pattern for human-in-the-loop enterprise workflows.
  • It keeps the user in control of business constraints.
  • It turns chat into a guided planning experience without a separate web form.

Good customer scenarios:

  • A store manager planning a weekly bakery and dairy restock with a fixed budget.
  • A purchasing team exploring tradeoffs across categories before approving an order.
  • Any scenario where the acceptable answer depends on user-provided preferences.

9. Notifications And Logging

Relevant features:

  • resources/updated notifications after inventory mutations
  • logging/setLevel
  • SSE-friendly responses via Accept: application/json, text/event-stream

How to use:

  • Opt into streaming by including text/event-stream in the Accept header.
  • Call logging/setLevel to request info-level logs.
  • Mutate inventory with set_inventory or adjust_stock and listen for resources/updated notifications.

When to use:

  • When the client needs to refresh UI automatically after state changes.
  • When you want visibility into tool execution progress or server-side decisions.
  • When building richer clients that behave more like reactive applications than one-shot RPC callers.

Why customers get value:

  • Notifications reduce polling and stale UI.
  • Logging gives operators and developers insight into what the server is doing.
  • These patterns matter when customers move from prototype tooling to operational experiences.

Good customer scenarios:

  • Live dashboards that update after stock adjustments.
  • Admin tools that need a clear event trail.
  • Debugging advanced capabilities such as sampling or bulk planning.

10. Roots

Tool:

  • list_client_roots

How to use:

  • Invoke it from a client that advertises the roots capability.
  • The server requests the client's workspace roots and returns them in a readable summary.

When to use:

  • When the server should tailor behavior to the user's active repositories or folders.
  • When a future tool should limit itself to the relevant workspace rather than guessing context.

Why customers get value:

  • Roots are a clean way to keep server behavior aligned with the user's actual working set.
  • They are especially useful when a server may operate on documents, repos, or local artifacts.

Good customer scenarios:

  • Repo-aware code assistants.
  • Multi-project workspaces where scope matters.
  • Governance-sensitive tools that should only operate inside approved directories.

11. Minimal Sample Server

Project:

  • Sample/

How to use:

  • Run dotnet run --project .\Sample.
  • Configure it as a stdio MCP server.
  • Ask for random numbers to confirm the tool path works.

When to use:

  • When introducing MCP to a customer for the first time.
  • When you need a low-noise starter before discussing prompts, resources, or UI.
  • When teaching the difference between transport wiring and domain logic.

Why customers get value:

  • It strips MCP down to the essentials.
  • It makes onboarding faster for teams who are new to the protocol.
  • It gives people a clean baseline before they evaluate the richer grocery example.

Suggested Demo Flows

Flow 1: Deterministic operational assistant

Use this when the audience wants to see grounded, safe tool calls first.

  1. List stores or products.
  2. Read inventory for one store.
  3. Query low-stock items.
  4. Adjust stock for a sale or restock.
  5. Show that low-stock and resource summaries change immediately.

Why it works well:

  • It demonstrates trustable read and write operations.
  • It avoids model-dependency concerns early in the conversation.

Flow 2: Guided analysis and writing

Use this when the audience cares about repeatable AI workflows.

  1. Call prompts/list.
  2. Use analyze_store_performance or draft_supplier_order.
  3. Show completions for prompt arguments.
  4. Explain how the server packages domain context for the model.

Why it works well:

  • It shows how MCP can standardize prompt-based work without custom app development.

Flow 3: Human-in-the-loop planning

Use this when the audience wants approval points and budget controls.

  1. Invoke plan_bulk_restock.
  2. Let the user choose store, budget, and categories.
  3. Review the returned plan.

Why it works well:

  • It shows a practical path to enterprise-safe interactive flows.

Flow 4: Model-assisted prioritization

Use this when the audience wants to see where model reasoning adds value.

  1. Run get_low_stock to show the raw deterministic shortage list.
  2. Invoke recommend_restocks from a sampling-capable host.
  3. Compare the ranked recommendations with the raw low-stock rows.

Why it works well:

  • It highlights the difference between threshold detection and business prioritization.

Key Files For Extending The Demo

FileWhy it matters
src/GroceryInventory.Api/Program.csWires up OpenAPI, HTTP transport, tools, resources, prompts, completions, and the /mcp endpoint
src/GroceryInventory.Api/McpTools/Tools.csCore deterministic MCP tools
src/GroceryInventory.Api/McpTools/DashboardTools.csMCP App dashboard tool and response shape
src/GroceryInventory.Api/McpApp/GroceryDashboardResource.csUI resource registration and bundle loading
src/GroceryInventory.Api/McpTools/Prompts.csPrompt template definitions
src/GroceryInventory.Api/McpTools/ResourceTemplates.csDynamic resource templates
src/GroceryInventory.Api/McpTools/Completions.csCompletion handler implementation
src/GroceryInventory.Api/McpTools/RestockRecommendationTools.csSampling-based recommendation flow
src/GroceryInventory.Api/McpTools/ElicitationTools.csElicitation-based form and planning flow
src/GroceryInventory.Api/McpTools/RootsTools.csRoots capability example
src/GroceryInventory.Api/Services/InMemoryInventoryService.csIn-memory persistence and mutation behavior
src/GroceryInventory.Api/Data/SeedData.csRepeatable sample data used throughout the demo
src/GroceryInventory.Api/GroceryMcpTools.httpManual MCP protocol walkthrough

Troubleshooting

The dashboard says the bundle is missing

Build the MCP App bundle:

Set-Location .\src\GroceryInventory.Api\McpApp
npm install
npm run build

Then restart the API.

recommend_restocks fails

Check these conditions:

  • The client must advertise the sampling capability.
  • The client must have a connected model.
  • A plain REST client will not satisfy the sampling round-trip.

plan_bulk_restock returns a capability error or an empty plan

Possible causes:

  • The client does not support elicitation.
  • The selected categories and store do not currently produce any qualifying restock items.
  • The budget cap filters everything out.

list_client_roots returns a capability message

That means the client did not advertise roots. The tool is working as designed; it is demonstrating capability negotiation.

Inventory changes disappear after restart

This is expected. The grocery demo uses an in-memory singleton store seeded from SeedData.cs.

What To Tell Customers

If you are presenting this repo to customers, a useful summary is:

  • Start with deterministic tools for safe reads and writes.
  • Add prompts when repeatable AI tasks matter.
  • Add resources when the client needs stable, discoverable context.
  • Add completions when the user experience needs guardrails.
  • Add elicitation when humans should choose constraints.
  • Add sampling when model reasoning adds value but should remain client-owned.
  • Add MCP App UI when text alone is not the right interaction surface.

That progression helps customers see MCP as a practical integration layer for copilots, not just a protocol demo.