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
| Path | What it is | When to use it |
|---|---|---|
Sample/ | Minimal stdio MCP server with one random-number tool | When you need the fastest possible onboarding example |
src/GroceryInventory.Api/ | Main grocery inventory demo using HTTP transport | When you want a realistic business scenario with multiple MCP capabilities |
src/GroceryInventory.Api/McpTools/ | Tool, prompt, resource, completion, sampling, elicitation, and roots implementations | When extending or reviewing the MCP surface |
src/GroceryInventory.Api/McpApp/ | Vite-based single-file dashboard UI bundle | When demonstrating MCP Apps or chat-adjacent visual experiences |
src/GroceryInventory.Api/GroceryMcpTools.http | End-to-end JSON-RPC request collection for MCP manual testing | When you want to inspect protocol calls directly |
src/GroceryInventory.Api/GroceryRestEndpoints.http | REST request collection for the HTTP API | When comparing REST with MCP or testing deterministic APIs |
.vscode/mcp.json | VS Code MCP server registration | When 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
.httpfiles 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.jsonin development. - The
.csprojautomatically builds the dashboard bundle fromsrc/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:
- Start the grocery API with
dotnet run --project .\src\GroceryInventory.Api. - Open the workspace in VS Code.
- Make sure the MCP server is enabled in Copilot Chat.
- 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:
initializenotifications/initialized- any
tools/list,resources/list,prompts/list, ortools/callrequest
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
.httpfile behaves like a plain client and does not advertise advanced client capabilities such assampling,elicitation, orrootsduringinitialize. - That means requests like
recommend_restocks,plan_bulk_restock, andlist_client_rootsare 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
| Capability | Primary entry point | How to use it | When a customer gets value | Why it matters |
|---|---|---|---|---|
| Reference data lookup | get_categories, get_suppliers, get_stores, get_products | Call the tool directly from chat or JSON-RPC | When an agent must ground itself in real catalog, store, or supplier data | Reliable, deterministic reads reduce hallucinations and bad follow-up actions |
| Inventory state and mutations | get_inventory, set_inventory, adjust_stock, get_low_stock | Use tools to read inventory, update counts, or identify shortages | When workflows need operational actions, not just analysis | Turns chat from passive Q and A into useful business operations |
| MCP App dashboard | show_store_inventory_dashboard plus ui://grocery/store-dashboard.html | Call the tool from an MCP App-aware client | When users need a visual, multi-store inventory view | Easier for humans to validate and act on than raw JSON alone |
| Prompt templates | prompts/list, prompts/get | Discover prompts, then request prompt messages with typed arguments | When you want reusable, repeatable AI tasks | Reduces prompt engineering overhead and standardizes outcomes |
| Resource templates | resources/templates/list, resources/read | Discover URI templates, then substitute concrete IDs | When you need dynamic, read-only context with stable URIs | Keeps frequently requested business views simple and discoverable |
| Argument completions | completion/complete | Ask for suggestions using a prompt or resource reference plus partial input | When users type IDs or known terms | Improves UX and reduces invalid argument errors |
| Sampling-based reasoning | recommend_restocks | Invoke from a client that supports sampling and has a connected model | When deterministic rules are not enough and prioritization needs judgment | Lets the customer reuse the client's model access instead of baking model access into the server |
| Elicitation-based planning | plan_bulk_restock | Invoke from a client that supports elicitation | When the server should ask the human for budget, scope, or preferences before acting | Human-in-the-loop planning is safer and more controllable than guessing |
| Notifications and logging | resources/updated, logging/setLevel, SSE | Listen on the event stream and opt into log levels | When clients need live updates and traceability | Enables reactive UX and better debugging |
| Roots | list_client_roots | Invoke from a client that advertises roots | When server behavior should be aware of workspace or project context | Helps future tools stay scoped to the user's real working set |
| Minimal starter server | Sample/ | Run the stdio sample and call get_random_number | When the audience is new to MCP and should start small | Lowest-friction teaching sample before introducing advanced patterns |
Detailed Capability Guide
1. Reference Data Lookup Tools
Tools:
get_categoriesget_suppliersget_storesget_products
How to use:
- Ask Copilot a domain question like
List the suppliersorShow products in category 2. - Or call
tools/callwith the tool name and optional filters such asid,categoryId, orsupplierId.
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_inventoryset_inventoryadjust_stockget_low_stock
How to use:
- Use
get_inventoryfor chain-wide, per-store, per-product, or single-row inventory reads. - Use
set_inventoryto create or replace an inventory record with absolute values. - Use
adjust_stockfor relative changes such as sales, shrinkage, or restocks. - Use
get_low_stockto 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_dashboardui://grocery/store-dashboard.html
How to use:
- Invoke
show_store_inventory_dashboardfrom 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_performancedraft_supplier_orderexplain_inventory_term
How to use:
- Call
prompts/listto discover available prompt templates. - Call
prompts/getwith 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}/summaryinventory://products/{productId}/details
How to use:
- Call
resources/templates/listto discover parameterized resources. - Substitute real values into the URI template.
- Call
resources/readwith the concrete URI, for exampleinventory://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
refdescribing 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
samplingcapability. - Make sure the client has a connected model.
- Optionally pass
storeIdto scope the recommendation andmaxRecommendationsto 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/updatednotifications after inventory mutationslogging/setLevel- SSE-friendly responses via
Accept: application/json, text/event-stream
How to use:
- Opt into streaming by including
text/event-streamin theAcceptheader. - Call
logging/setLevelto request info-level logs. - Mutate inventory with
set_inventoryoradjust_stockand listen forresources/updatednotifications.
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
rootscapability. - 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.
- List stores or products.
- Read inventory for one store.
- Query low-stock items.
- Adjust stock for a sale or restock.
- 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.
- Call
prompts/list. - Use
analyze_store_performanceordraft_supplier_order. - Show completions for prompt arguments.
- 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.
- Invoke
plan_bulk_restock. - Let the user choose store, budget, and categories.
- 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.
- Run
get_low_stockto show the raw deterministic shortage list. - Invoke
recommend_restocksfrom a sampling-capable host. - 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
| File | Why it matters |
|---|---|
src/GroceryInventory.Api/Program.cs | Wires up OpenAPI, HTTP transport, tools, resources, prompts, completions, and the /mcp endpoint |
src/GroceryInventory.Api/McpTools/Tools.cs | Core deterministic MCP tools |
src/GroceryInventory.Api/McpTools/DashboardTools.cs | MCP App dashboard tool and response shape |
src/GroceryInventory.Api/McpApp/GroceryDashboardResource.cs | UI resource registration and bundle loading |
src/GroceryInventory.Api/McpTools/Prompts.cs | Prompt template definitions |
src/GroceryInventory.Api/McpTools/ResourceTemplates.cs | Dynamic resource templates |
src/GroceryInventory.Api/McpTools/Completions.cs | Completion handler implementation |
src/GroceryInventory.Api/McpTools/RestockRecommendationTools.cs | Sampling-based recommendation flow |
src/GroceryInventory.Api/McpTools/ElicitationTools.cs | Elicitation-based form and planning flow |
src/GroceryInventory.Api/McpTools/RootsTools.cs | Roots capability example |
src/GroceryInventory.Api/Services/InMemoryInventoryService.cs | In-memory persistence and mutation behavior |
src/GroceryInventory.Api/Data/SeedData.cs | Repeatable sample data used throughout the demo |
src/GroceryInventory.Api/GroceryMcpTools.http | Manual 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
samplingcapability. - 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.