▲ NexaFlowDemo — Supply Chain AI Platform MCP Version

Agents + Real MCP + RAG + Workflows + Multi-Tenant — ASP.NET Core 9 MVC • Visual Studio 2022 • LLM: claude-sonnet-4-6 (live) • MCP: ModelContextProtocol v1.3.0 (JSON-RPC 2.0 / stdio) • Status: All Stages Complete ✓

Overview

NexaFlowDemo is a complete, runnable Visual Studio 2022 demonstration of AI Agents, Real Model Context Protocol (MCP), Retrieval-Augmented Generation (RAG), Parallel Agent Execution, Event-Driven Workflows, Multi-Tenant Support, Audit Logging, and Carrier/ERP Integration — all wired into a realistic supply chain application. The fictional company NexaFlow Logistics operates 6 SKUs, 6 suppliers, and live shipment tracking — powered by real Claude AI and real MCP protocol over JSON-RPC 2.0 / stdio.

This is the MCP Version: MCP tools are hosted in a separate NexaFlowDemo.McpServer console app and invoked via the official ModelContextProtocol v1.3.0 NuGet package. The web app spawns the McpServer as a subprocess and communicates over real JSON-RPC 2.0 stdio transport through RealMcpClientService.

181
Tests Passing
9
MCP Tools
6
KB Documents
4
Projects
4+MCP
Stages Complete
1
API Key Required

Architecture

1
Models
Core domain types: AgentModels, Document, McpModels (McpInvokeResponse, McpToolDefinition)
2
LLM Layer
ILlmServiceClaudeService (live Anthropic API; claude-sonnet-4-6)
3
Embeddings
IEmbeddingServiceSimulatedDenseEmbeddingService — 384-dim FNV-1a hash vectors
4
Vector Store
IVectorStoreInMemoryVectorStore + SqliteVectorStore; cosine similarity search
5
RAG Layer
InMemoryDocumentStore (TF-IDF) + VectorDocumentStore; RagPipeline + RagEvaluator
6
McpServer (NEW)
Separate console app (NexaFlowDemo.McpServer); 9 tool classes with [McpServerToolType] / [McpServerTool] attributes; WithToolsFromAssembly auto-registration; real JSON-RPC 2.0 stdio server
7
MCP Client
RealMcpClientServiceMcpClient.CreateAsync + StdioClientTransport; spawns McpServer subprocess; SemaphoreSlim lazy-init; routes all tool calls over JSON-RPC 2.0
8
Agents
ReactAgent (ReAct loop) • ParallelReactAgent (concurrent tool calls) • PlanningAgent (plan→execute) • MultiAgentOrchestrator
9
Memory & Conversation
Recency-decay memory + importance scoring; MemoryConsolidator (Jaccard merging); SQLite conversation persistence
10
Workflows
WorkflowEngine + ReorderWorkflow (inventory_low) + SlaBreachWorkflow (sla_breach); event-driven trigger system
11
Multi-Tenant
ITenantContext + TenantRegistry (3 demo tenants: Acme, Globex, Initech); TenantScopedDocumentStore
12
Audit & Integration
IAuditLogger / InMemoryAuditLogger; ICarrierApiService (SimulationMode); ErpTools (SAP-compatible)
13
Web / SignalR / SSE
13 controllers + 2 SignalR hubs + SSE endpoint; cookie auth; 12 Razor views; webhook order ingestion

Feature Pages

💬 RAG Chat (/Chat)

Ask natural-language questions about NexaFlow's inventory policies, supplier contracts, SLAs, and AI forecasting system. Powered by TF-IDF + dense vector search over 6 pre-seeded documents.

🧠 ReAct Agent (/Agent)

The agent thinks, calls MCP tools via real JSON-RPC over stdio, observes results, and loops until it has a final answer. Watch the Think → Act → Observe cycle live with inventory lookups, supplier queries, and shipment tracking.

🆕 Multi-Agent Pipeline (/Orchestration)

Two agents collaborate via SignalR streaming: a Research Agent gathers supply chain facts, then a Summary Agent synthesizes a final executive response. Real-time step-by-step rendering.

🔧 MCP Tools (/Mcp)

Browse all 9 MCP tools hosted in the McpServer subprocess, click to select, edit JSON parameters, and invoke directly via the HTTP bridge. Tools are served over real JSON-RPC 2.0 / stdio transport.

🌀 SSE Stream (/Stream)

Server-Sent Events alternative to SignalR. Run a ReactAgent query and receive step-by-step updates directly in the browser via native EventSource API — no WebSocket overhead.

⚙ Workflows (/Workflow)

Manually fire inventory_low or sla_breach triggers with custom payloads. The WorkflowEngine dispatches matching workflows: ReorderWorkflow creates POs; SlaBreachWorkflow escalates tickets.

📋 Audit Log (/Audit)

In-memory audit trail for all tool calls, agent runs, webhook events, and auth actions. Timestamped entries show user, tenant, action, resource, and success/failure status.

🚀 Integration Hub (/Integration)

Live carrier rate quotes (FedEx, UPS, USPS, DHL — simulated) and SAP-compatible ERP actions via the real erp_connector MCP tool: create_po, get_po, post_gr, get_financials — all zero-config.

📄 Upload (/Upload)

Drag-and-drop .txt documents into the knowledge base. New content is immediately indexed and searchable via all RAG and Agent endpoints.

📊 Evaluation (/Evaluation)

Run Precision@K, Recall@K, MRR, and Hit Rate evaluation against 6 domain-specific test cases. Per-case breakdown table shows retrieval quality for each supply chain topic.

🧠 Memory (/Memory)

Add memory entries with importance scores and keywords. Search returns results ranked by keyword relevance (50%) + importance (30%) + recency decay (20%). Auto-summarize top entries. MemoryConsolidator merges similar entries via Jaccard similarity.

📈 Dashboard (/)

At-a-glance KPIs: document count, tool count, memory entries. Quick-start links to all features with feature summary and architectural overview.

MCP Tools Reference

All 9 tools are hosted in the NexaFlowDemo.McpServer project as static classes annotated with [McpServerToolType] and [McpServerTool]. The WithToolsFromAssembly() call auto-registers them all at server startup. The web app calls them through RealMcpClientService via real JSON-RPC 2.0 over stdio.

ToolCategoryParametersDescription
inventory_lookupSupply Chainsku, category, statusReal-time stock levels for 6 NexaFlow SKUs; filter by status (Critical Low, Low Stock, In Stock)
supplier_lookupSupply Chainid, name, country, statusSupplier directory with ratings, lead times, and approval status for 6 suppliers
shipment_trackerSupply Chaintracking_number, order_idTrack 5 shipments (FedEx, UPS, DHL, Ocean) by NF-TRK ID or carrier number
document_searchKnowledgequery, top_kSemantic TF-IDF search over the NexaFlow knowledge base (calls back into Web's IDocumentStore)
calculatorUtilityexpressionArithmetic expressions with recursive-descent parser (+, -, *, /, %, parentheses)
datetimeUtilitytimezoneCurrent UTC time or converted to any IANA timezone
web_searchResearchquery, max_resultsSimulated logistics and supply chain search results (3 topic buckets)
code_interpreterComputecode, timeoutSandboxed C# evaluation via Roslyn CSharpScript; System namespaces only
erp_connectorIntegrationaction, supplier_id, amount, po_number, quantitySAP-compatible ERP: create_po, get_po, post_gr, get_financials. Full PO lifecycle simulation.

MCP HTTP bridge: GET /api/mcp/tools — list all tools via RealMcpClientService • POST /api/mcp/invoke body: {"tool":"inventory_lookup","input":{"sku":"NF-SKU-001"}}

File Map

NexaFlowDemo.Core — Stage 1

PathPurpose
Models/AgentModels.csAgentStep, AgentRunRequest, AgentStepType enum
Models/Document.csDocument, DocumentChunk, SearchResult
Models/McpModels.csMcpToolDefinition, McpInvokeResponse (bridge types)
LLM/ILlmService.csLLM abstraction interface
LLM/SimulatedLlmService.csZero-key simulated LLM; used by unit tests only
LLM/ClaudeService.csLive Anthropic API — always active in MCP Version
Embeddings/SimulatedDenseEmbeddingService.cs384-dim FNV-1a hash embeddings
VectorStore/InMemoryVectorStore.csThread-safe in-memory cosine similarity
VectorStore/SqliteVectorStore.csPersistent SQLite vector store
VectorStore/VectorDocumentStore.csIDocumentStore over dense embeddings
RAG/TextChunker.csSliding window word chunker
RAG/TfIdfEmbeddingService.csTF-IDF vectorizer + cosine similarity
RAG/DocumentStore.csInMemoryDocumentStore (TF-IDF search)
RAG/RagPipeline.csRetrieve → Augment → Generate
RAG/RagEvaluator.csPrecision@K, Recall@K, MRR, Hit Rate
MCP/IMcpServerService.csMCP client abstraction (ListToolsAsync, InvokeToolAsync)
Agents/ReactAgent.csReAct loop: Think → Tool → Observe
Agents/MultiAgentOrchestrator.csResearch → Summary two-stage pipeline
Memory/InMemoryMemoryStore.csRecency decay + importance scoring
Conversation/InMemoryConversationStore.csPer-session conversation history
Data/KnowledgeBaseSeeder.csSeeds 6 NexaFlow supply-chain documents

NexaFlowDemo.Core — Stages 2/3/4

PathPurpose
Agents/ParallelReactAgent.csParallel tool execution via <tool_calls> + Task.WhenAll
Agents/PlanningAgent.csPlan-then-execute: <plan><step> format → sequential tool loop
Memory/MemoryConsolidator.csJaccard similarity → merge near-duplicate memory entries
Persistence/SqliteConversationStore.csSQLite-backed IConversationStore with sessions + turns tables
Persistence/PersistenceOptions.csUseInMemory flag + ConnectionString config
Workflows/IWorkflow.csIWorkflow interface + WorkflowContext + WorkflowResult
Workflows/WorkflowEngine.csEvent-driven trigger → matching workflow dispatch
Workflows/ReorderWorkflow.csTrigger: inventory_low → creates simulated PO
Workflows/SlaBreachWorkflow.csTrigger: sla_breach → escalation ticket + credit memo
MultiTenant/ITenantContext.csTenantId, TenantName, AllowedRoles interface
MultiTenant/TenantContext.csImplementation + TenantRegistry (Acme, Globex, Initech)
MultiTenant/TenantScopedDocumentStore.csWraps IDocumentStore; filters by tenantId metadata
Audit/AuditEntry.csAudit record: Id, Timestamp, UserId, TenantId, Action, Resource
Audit/IAuditLogger.csLogAsync + GetEntriesAsync interface
Audit/InMemoryAuditLogger.csThread-safe in-memory audit store
Integration/ICarrierApiService.csGetRates, CreateShipment, TrackShipment interface
Integration/CarrierModels.csRateRequest, RateQuote, ShipmentRequest/Response, TrackingResult
Integration/SimulatedCarrierApiService.cs4-carrier rate simulation; shipment tracking lifecycle
Integration/WebhookModels.csOrderWebhookEvent + OrderLineItem

▶ NexaFlowDemo.McpServer (NEW — MCP Version)

PathPurpose
Program.csBuilds MCP stdio server: AddMcpServer().WithStdioServerTransport().WithToolsFromAssembly(…); suppresses stdout logging to protect JSON-RPC stream
NexaFlowDemo.McpServer.csprojReferences ModelContextProtocol v1.3.0; OutputType=Exe; references NexaFlowDemo.Core
Tools/InventoryTools.cs[McpServerToolType] static class; inventory_lookup — 6-SKU catalog
Tools/SupplierTools.cssupplier_lookup — 6-supplier directory with ratings and lead times
Tools/ShipmentTools.csshipment_tracker — 5-shipment tracking system
Tools/DocumentSearchTools.csdocument_search — TF-IDF search over seeded knowledge base
Tools/CalculatorTools.cscalculator — recursive-descent arithmetic parser
Tools/DateTimeTools.csdatetime — UTC + IANA timezone conversion
Tools/WebSearchTools.csweb_search — simulated logistics search (3 topic buckets)
Tools/CodeInterpreterTools.cscode_interpreter — Roslyn CSharpScript sandboxed executor
Tools/ErpTools.cserp_connector — SAP-compatible ERP: create_po, get_po, post_gr, get_financials

NexaFlowDemo.Web

PathPurpose
Program.csDI wiring — 1 line replaces 10 old MCP registrations: AddSingleton<IMcpServerService, RealMcpClientService>
appsettings.jsonLLM/Embeddings/Agent/Persistence/Carrier config + McpServer section (ServerPath auto-detected)
Services/RealMcpClientService.csImplements IMcpServerService via McpClient.CreateAsync + StdioClientTransport; spawns McpServer subprocess; SemaphoreSlim lazy-init
Services/IMcpServerService.csListToolsAsync / InvokeToolAsync abstraction (same interface, real transport)
Services/McpServerOptions.csServerPath config binding for McpServer executable location
Services/UserService.csIUserService + DemoUserService; SHA-256 hashed passwords; 4 demo users
Controllers/HomeController.csDashboard KPIs
Controllers/ChatController.csRAG Chat API
Controllers/AgentController.csSingle-agent REST API
Controllers/McpController.csMCP HTTP bridge: GET /tools, POST /invoke (via RealMcpClientService)
Controllers/OrchestrationController.csPipeline page host
Controllers/UploadController.csDocument upload + list API
Controllers/EvaluationController.csRAG evaluation run + test-case builder
Controllers/MemoryController.csAdd / Search / Delete / Summarize memory
Controllers/AuthController.csCookie login/logout; validates against DemoUserService
Controllers/WorkflowController.csWorkflow list + manual trigger form
Controllers/StreamController.csSSE endpoint: GET /stream/run?query=…
Controllers/AuditController.csAudit log viewer
Controllers/IntegrationController.csCarrier rate quotes + ERP action form
Controllers/WebhookController.csPOST /api/webhooks/orders — order event ingestion
Hubs/AgentHub.csSignalR: streams ReactAgent steps
Hubs/OrchestrationHub.csSignalR: streams pipeline steps
Views/Home/Index.cshtmlDashboard with feature cards
Views/Chat/Index.cshtmlChat UI with source document panel
Views/Agent/Index.cshtmlStep-by-step agent run visualizer
Views/Orchestration/Index.cshtmlReal-time pipeline with agent badges
Views/Mcp/Index.cshtmlTool browser + JSON invoke console
Views/Upload/Index.cshtmlDrag-and-drop document uploader
Views/Evaluation/Index.cshtmlEvaluation metrics dashboard
Views/Memory/Index.cshtmlMemory CRUD + search + summarize
Views/Auth/Login.cshtmlLogin form; shows demo credentials
Views/Workflow/Index.cshtmlRegistered workflows list + manual trigger form
Views/Stream/Index.cshtmlSSE streaming demo page
Views/Audit/Index.cshtmlAudit log table view
Views/Integration/Index.cshtmlCarrier rate quote + ERP console
Views/Shared/_Layout.cshtmlNav bar with all 12 pages + user/role display

Test Suite — 181 Tests Passing

Test ClassCountWhat It Tests
Core Tests — Stage 1 (95 Tests)
RAG/TextChunkerTests5Sliding window chunker: empty, short, long, overlap, null
RAG/DocumentStoreTests5InMemoryDocumentStore: add, search, delete, topK, empty query
RAG/RagPipelineTests4RagPipeline: answer generation, empty store, source results, ranking
RAG/RagEvaluatorTests5RagEvaluator: no cases, valid cases, metric bounds, detail count, multi-relevant
Embeddings/SimulatedDenseEmbeddingServiceTests7Dimensions, normalization, determinism, diff texts, batch, empty string
VectorStore/InMemoryVectorStoreTests6Upsert, search topK, descending scores, delete by doc, overwrite, empty
VectorStore/SqliteVectorStoreTests5In-memory SQLite: upsert, search, delete, embedding roundtrip, empty
MCP/McpToolDefinitionTests5McpToolDefinition model: name, description, parameter schema, required fields, JSON roundtrip
Agents/ReactAgentTests7Final answer, thinking step, tool call+result, cancellation, system prompt, content, max iterations
Agents/MultiAgentOrchestratorTests5Handoff steps, final answer, both agents, cancellation, handoff message content
Memory/InMemoryMemoryStoreTests8Add/get, search relevance, delete, delete missing, summarize, empty summarize, access count, topK
Conversation/InMemoryConversationStoreTests7Create, get, get null, list, add turn, delete, delete missing
LLM/ClaudeServiceTests6SplitPrompt extraction, system param pass-through, HTTP header wiring, non-2xx error handling, response mapping, cancellation
Core Tests — Stages 2/3/4 (59 Tests)
Persistence/SqliteConversationStoreTests7SQLite sessions/turns: create, get, null, list, add turn, delete, multi-turn ordering
Agents/ParallelReactAgentTests5Direct final answer, single tool call, parallel tool calls (Task.WhenAll), thinking step, LLM error
Agents/PlanningAgentTests4No plan → direct answer, 2-step plan with synthesis, tool call in step, LLM error
Workflows/WorkflowEngineTests4No match, matching trigger, only matching fires, faulting workflow doesn't block others
Workflows/ReorderWorkflowTests4Creates PO, default payload, trigger name, unique PO numbers
Memory/MemoryConsolidatorTests8Empty list, single entry, similar entries merged, dissimilar kept, keyword union, Jaccard identical/disjoint/partial
MultiTenant/TenantContextTests5Registry has 3 tenants, Acme correct, FindById success, FindById unknown, AllowedRoles set
MultiTenant/TenantScopedDocumentStoreTests3Tags docs with tenantId, GetAll filters to tenant, Search filters to tenant
Audit/InMemoryAuditLoggerTests5Store entry, most-recent-first, respects limit, multiple entries, default Success=true
Integration/CarrierApiServiceTests6Returns 4 carriers, heavier costs more, tracking number, track created shipment, unknown tracking, unique numbers
Integration/ErpConnectorToolTests7(Legacy Core ERP tests) create_po, missing supplier, get_po, post_gr, get_financials, unknown action, definition name
McpServer Tool Tests — 27 New Tests (MCP Version)
McpServer/InventoryToolsTests5Valid SKU lookup, invalid SKU, no params, filter by status, all-SKU listing
McpServer/SupplierToolsTests4Valid ID, invalid ID, name search, status/country filter
McpServer/ShipmentToolsTests3Valid tracking number, by order ID, not found
McpServer/CalculatorToolsTests4Basic arithmetic, parentheses, percent operator, invalid expression
McpServer/DateTimeToolsTests3UTC result, valid timezone conversion, invalid timezone
McpServer/WebSearchToolsTests3Valid query returns results, max_results respected, logistics topic bucket
McpServer/ErpToolsTests5create_po success, missing supplier fails, get_po after create, post_gr updates status, unknown action

Quick Start

Prerequisites

Set Your API Key

# In src/NexaFlowDemo.Web/appsettings.json:
{
  "LLM": {
    "ApiKey": "sk-ant-...",
    "Model": "claude-sonnet-4-6"
  }
}

Run

cd src/NexaFlowDemo.Web
dotnet run
# → http://localhost:5xxx  (check console for port)
# The McpServer subprocess is launched automatically on first tool call — no manual start needed

Test

# Run all tests (Core + McpServer tool tests)
dotnet test src/NexaFlowDemo.Tests/NexaFlowDemo.Tests.csproj
# → Passed! Failed: 0, Passed: 181

# Run with minimal output (final verification)
dotnet test src/NexaFlowDemo.Tests/NexaFlowDemo.Tests.csproj --verbosity minimal

Demo Login Accounts

UsernamePasswordRoleTenant
adminadmin123AdminACME Distribution
opsops123OpsACME Distribution
managermanager123ManagerGlobex Corp
execexec123ExecInitech Logistics

Try the Workflow Engine

# POST /api/webhooks/orders (triggers inventory_low when quantity > 50)
curl -X POST http://localhost:5xxx/api/webhooks/orders \
  -H "Content-Type: application/json" \
  -d '{"orderId":"ORD-001","customerId":"CUST-001","source":"Shopify","status":"new","totalAmount":1500,"lineItems":[{"skuId":"NF-SKU-001","quantity":100,"price":15}]}'

Enable SQLite Conversation Persistence

{
  "Persistence": {
    "UseInMemory": false,
    "ConnectionString": "Data Source=nexaflow.db"
  }
}

Then change Program.cs to register SqliteConversationStore instead of InMemoryConversationStore.

MCP API Examples

# List tools (fetched from McpServer subprocess via RealMcpClientService)
curl http://localhost:5xxx/api/mcp/tools

# ERP: Create PO
curl -X POST http://localhost:5xxx/api/mcp/invoke \
  -H "Content-Type: application/json" \
  -d '{"tool":"erp_connector","input":{"action":"create_po","supplier_id":"SUP-001","amount":"5000"}}'

# Inventory lookup
curl -X POST http://localhost:5xxx/api/mcp/invoke \
  -H "Content-Type: application/json" \
  -d '{"tool":"inventory_lookup","input":{"sku":"NF-SKU-001"}}'

Roadmap

StageFeaturesStatus
Stage 1
Core Platform
Core library (Models, LLM, Embeddings, VectorStore, RAG, MCP, Agents, Memory, Conversation, Data) • 8 MCP tools (3 supply-chain domain tools) • ReactAgent ReAct loop • Multi-Agent Orchestrator • Web app (8 controllers, 2 SignalR hubs, 8 views) • Knowledge base seeder (6 supply-chain docs) • 95 tests • HTML roadmap Complete ✓
Stage 2
Persistence & New Agents
SQLite conversation persistence (SqliteConversationStore) • ParallelReactAgent with Task.WhenAll parallel tool calls • PlanningAgent (plan→execute→synthesize) • ERP Connector tool (create_po, get_po, post_gr, get_financials) • Persistence config options • 7 new tests Complete ✓
Stage 3
Advanced Agents & Workflows
SSE streaming endpoint (/stream/run) • MemoryConsolidator (Jaccard keyword merge) • WorkflowEngine event-driven trigger dispatch • ReorderWorkflow (inventory_low → PO) • SlaBreachWorkflow (sla_breach → escalation + credit) • Workflow controller + view • SSE view • 21 new tests Complete ✓
Stage 4
Production Features
Multi-tenant: TenantRegistry (Acme, Globex, Initech) + TenantScopedDocumentStore • Cookie authentication + 4 demo users (admin/ops/manager/exec) • IAuditLogger / InMemoryAuditLogger • Carrier API service (4 carriers, SimulationMode) • Webhook order event ingestion (POST /api/webhooks/orders) • Audit/Integration views • User display in nav • 31 new tests Complete ✓
MCP Version
Real MCP Protocol
New NexaFlowDemo.McpServer project (console app, stdio server) • 9 tool classes with [McpServerToolType]/[McpServerTool] attributes • WithToolsFromAssembly auto-registration • RealMcpClientService (McpClient.CreateAsync + StdioClientTransport) replaces all simulated MCP wiring • 27 new McpServer tool tests • 181 total tests passing • Official ModelContextProtocol v1.3.0 NuGet package • JSON-RPC 2.0 over stdio Complete ✓

ClaudeLiveKey → MCP_Version Migration

This project (MCP_Version) is a copy of the completed ClaudeLiveKey build with the simulated MCP layer replaced by real Model Context Protocol using the official ModelContextProtocol v1.3.0 NuGet package, JSON-RPC 2.0 over stdio transport, and a new NexaFlowDemo.McpServer subprocess.

What Changed

File / ProjectChangeWhy
NexaFlowDemo.McpServer (new project) New console app project. Program.cs calls:
builder.Services.AddMcpServer()
    .WithStdioServerTransport()
    .WithToolsFromAssembly(
        Assembly.GetExecutingAssembly(), jsonOptions);
await app.RunAsync();
9 [McpServerToolType] static tool classes in Tools/. Stdout logging suppressed so JSON-RPC stream is uncontaminated.
Encapsulates all tool logic in a real MCP stdio server; any MCP-compatible client can now use these tools.
Web/Services/RealMcpClientService.cs (new file) Implements IMcpServerService using the official SDK:
var transport = new StdioClientTransport(
    new StdioClientTransportOptions {
        Command = "dotnet",
        Arguments = ["exec", ResolveServerPath()],
        Name = "NexaFlowDemoMcpServer"
    });
_client = await McpClient.CreateAsync(transport, ct);
SemaphoreSlim guards lazy init for thread safety. ResolveServerPath() auto-detects sibling project bin output.
Replaces all 10 hand-written tool registrations with a single JSON-RPC bridge to the McpServer subprocess.
Web/Program.cs 10 individual AddSingleton<IMcpTool, XyzTool>() lines replaced by 1:
builder.Services.AddSingleton<IMcpServerService,
    RealMcpClientService>();
The McpServer project owns all tool implementations; Web only needs the client bridge.
McpServer/Tools/*.cs Old IMcpTool-based classes replaced by [McpServerToolType] static classes:
[McpServerToolType]
public static class InventoryTools
{
    [McpServerTool(Name = "inventory_lookup", ReadOnly = true)]
    [Description("Look up stock level for a SKU.")]
    public static string LookupInventory(
        [Description("The product SKU code")] string sku)
    { … }
}
No interface to implement; schema generated from [Description] attributes automatically.
Official SDK pattern; eliminates manual schema JSON; tools can be static (no DI needed).
appsettings.json Added McpServer section:
"McpServer": {
  "ServerPath": ""  // auto-detected if blank
}
Removed LLM.SimulationMode (always live in MCP Version).
ServerPath allows explicit override when the auto-detection path differs from the default.
NexaFlowDemo.Tests 27 new McpServer tool test classes added (InventoryToolsTests, SupplierToolsTests, ShipmentToolsTests, CalculatorToolsTests, DateTimeToolsTests, WebSearchToolsTests, ErpToolsTests). All tests call the static tool methods directly — no McpClient needed in tests. Static tool methods are trivially unit-testable without protocol overhead; 27 new tests → 181 total.

What Did NOT Change

How to Set Your API Key

Get your key from console.anthropic.com → API Keys, then set it in one of these ways:

MethodHowBest For
appsettings.Development.json Create src/NexaFlowDemo.Web/appsettings.Development.json with {"LLM":{"ApiKey":"sk-ant-..."}} Local development (override file, gitignored)
Environment variable Set LLM__ApiKey=sk-ant-... before running (double underscore = config section separator) CI/CD, Docker, production
appsettings.json Replace the placeholder directly in src/NexaFlowDemo.Web/appsettings.json Quick local test (do not commit)

Bug Fixes & API Gotchas (MCP Version)

🐞 BF-001 — StdioClientTransportOptions Has No Version Property

FieldDetail
SymptomCompiler error: "StdioClientTransportOptions does not contain a definition for 'Version'"
Root CauseThe ModelContextProtocol v1.3.0 SDK's StdioClientTransportOptions record has Command, Arguments, Name, and WorkingDirectory — no Version property.
Fix
// WRONG:
new StdioClientTransportOptions {
    Command = "dotnet",
    Arguments = ["exec", path],
    Name = "NexaFlowDemoMcpServer",
    Version = "1.0"   // ← does not exist
}

// CORRECT:
new StdioClientTransportOptions {
    Command = "dotnet",
    Arguments = ["exec", path],
    Name = "NexaFlowDemoMcpServer"
}

🐞 BF-002 — McpClientTool.JsonSchema Not InputSchema

FieldDetail
SymptomCompiler error or null reference when reading tool schema.
Root CauseThe correct property on McpClientTool is JsonSchema. InputSchema does not exist in v1.3.0.
Fix
// WRONG:
var schema = tool.InputSchema;

// CORRECT:
var schema = tool.JsonSchema;

🐞 BF-003 — ListToolsAsync Returns a List Directly (No .Tools Wrapper)

FieldDetail
SymptomCompiler error: "ValueTask<IList<McpClientTool>> does not contain a definition for 'Tools'"
Root CauseMcpClient.ListToolsAsync() in v1.3.0 returns ValueTask<IList<McpClientTool>> — the list is the result directly, not a wrapper object with a .Tools property.
Fix
// WRONG:
var response = await _client!.ListToolsAsync(ct);
foreach (var tool in response.Tools) { … }

// CORRECT:
var tools = await _client!.ListToolsAsync(ct);
foreach (var tool in tools) { … }

🐞 BF-004 — McpServer Must Suppress Stdout Logging

FieldDetail
SymptomRealMcpClientService throws JSON parse errors or hangs on startup. McpServer subprocess crashes immediately.
Root CauseThe JSON-RPC 2.0 stdio transport uses stdout exclusively for protocol messages. Any logging written to stdout (the default for console apps) corrupts the stream, causing the client to receive malformed JSON.
Fix In McpServer/Program.cs, redirect all logging to stderr and suppress console output:
builder.Logging.ClearProviders();
builder.Logging.AddConsole(opts =>
{
    opts.LogToStandardErrorThreshold = LogLevel.Trace;
});
This ensures stdout carries only clean JSON-RPC messages.
General RuleAny MCP stdio server must write ALL logging to stderr. stdout is reserved for the JSON-RPC protocol stream.

CLI Build Reference

All commands below run from the solution root C:\Guy\Notes\Claud Projects\Agentic Baiic 03_SupplyChain_ClaudeLiveKey_MCP_Version\. This is a 4-project solution — restore and build all four projects.

Restore Dependencies

dotnet restore src/NexaFlowDemo.Core/NexaFlowDemo.Core.csproj
dotnet restore src/NexaFlowDemo.McpServer/NexaFlowDemo.McpServer.csproj
dotnet restore src/NexaFlowDemo.Web/NexaFlowDemo.Web.csproj
dotnet restore src/NexaFlowDemo.Tests/NexaFlowDemo.Tests.csproj

Build Individual Projects

# Build the core library only
dotnet build src/NexaFlowDemo.Core/NexaFlowDemo.Core.csproj

# Build the McpServer project (also rebuilds Core)
dotnet build src/NexaFlowDemo.McpServer/NexaFlowDemo.McpServer.csproj

# Build the web app (also rebuilds Core; McpServer built separately)
dotnet build src/NexaFlowDemo.Web/NexaFlowDemo.Web.csproj

# Build the test project (rebuilds Core and McpServer as dependencies)
dotnet build src/NexaFlowDemo.Tests/NexaFlowDemo.Tests.csproj

Run Tests

# Build + run all tests (Core tests + McpServer tool tests = 181)
dotnet test src/NexaFlowDemo.Tests/NexaFlowDemo.Tests.csproj

# Run with minimal output (used for final verification)
dotnet test src/NexaFlowDemo.Tests/NexaFlowDemo.Tests.csproj --verbosity minimal

# Run without rebuilding (re-run against already-compiled binaries)
dotnet test src/NexaFlowDemo.Tests/NexaFlowDemo.Tests.csproj --no-build

Run the Web App

# Start the web application
dotnet run --project src/NexaFlowDemo.Web/NexaFlowDemo.Web.csproj
# → http://localhost:5xxx  (check console for port)
# → McpServer subprocess is spawned automatically on first tool call

Inspect Project Files

# List all .cs files in a project (PowerShell)
Get-ChildItem "src/NexaFlowDemo.Core" -Recurse -Filter "*.cs" `
  | Select-Object -ExpandProperty FullName | Sort-Object

Get-ChildItem "src/NexaFlowDemo.McpServer" -Recurse -Filter "*.cs" `
  | Select-Object -ExpandProperty FullName | Sort-Object

Get-ChildItem "src/NexaFlowDemo.Web" -Recurse -Filter "*.cs" `
  | Select-Object -ExpandProperty FullName | Sort-Object

Get-ChildItem "src/NexaFlowDemo.Tests" -Recurse -Filter "*.cs" `
  | Select-Object -ExpandProperty FullName | Sort-Object

Build Sequence Used During Development

StepCommandPurpose
1dotnet build NexaFlowDemo.Core.csprojVerify Core compiles after each batch of changes
2dotnet build NexaFlowDemo.McpServer.csprojVerify McpServer compiles after adding or editing tool classes
3dotnet build NexaFlowDemo.Web.csprojVerify Web compiles after adding RealMcpClientService and Program.cs changes
4dotnet test NexaFlowDemo.Tests.csprojFull build + test run; target was 0 failures at 181 tests
5dotnet test … --verbosity minimalFinal clean pass — shows only the summary line

NuGet Packages Added (MCP Version — beyond ClaudeLiveKey)

PackageVersionUsed By
ModelContextProtocol1.3.0NexaFlowDemo.McpServer (server) + RealMcpClientService (client)
Microsoft.Extensions.Hosting9.0.0NexaFlowDemo.McpServer (IHost for stdio server)

All packages from ClaudeLiveKey (Microsoft.Data.Sqlite, Microsoft.CodeAnalysis.CSharp.Scripting, Moq, xunit, etc.) are unchanged.