I asked Claude: "Which provider is performing best and why?"
It didn't guess. It didn't hallucinate. It called a tool, queried my live PostgreSQL database, and returned this:
That's not a chatbot. That's an analyst with direct database access.
What is MCP?
Model Context Protocol (MCP) is an open standard that lets AI agents call external tools in a structured way. Instead of embedding data in a prompt, you expose tools — functions with descriptions — that the AI can call when it needs information.
The key insight: Claude doesn't know what's in your database. But if you give it a tool called GetPaymentSummary with a description that says "Get volume and status breakdown of recent payments", Claude knows when to call it — and what the result means.
"The description attribute is architecture. How you describe a tool determines when Claude calls it, what arguments it passes, and how it interprets the result."
Building PayCore.Mcp in .NET 10
The MCP server is a standard ASP.NET Core project with one NuGet package:
dotnet add package ModelContextProtocol.AspNetCore
// Program.cs — the entire setup
builder.Services.AddMcpServer()
.WithHttpTransport()
.WithTools<PayCoreTools>();
app.MapMcp("/mcp");
Three lines of setup. The rest is your tool implementations.
[McpServerToolType]
public class PayCoreTools
{
[McpServerTool]
[Description("Get a summary of payment volume and status breakdown. "
+ "Use this to answer: 'What is the total payment volume?', "
+ "'How many payments succeeded vs failed?'")]
public async Task<string> GetPaymentSummary(
[Description("Number of recent payments to include (1-500). Default 100.")]
int count = 100)
{
var payments = await _intents.GetRecentAsync(count, null, null);
var summary = new {
TotalPayments = payments.Count,
ByStatus = payments.GroupBy(p => p.Status)
.ToDictionary(g => g.Key, g => g.Count()),
VolumeByCurrency = payments
.Where(p => p.Status == "captured")
.GroupBy(p => p.Currency)
.ToDictionary(g => g.Key, g => g.Sum(p => p.Amount))
};
return JsonSerializer.Serialize(summary, _jsonOptions);
}
}
The four tools
| Tool | Claude can answer... |
|---|---|
| get_payment_summary | What is the total volume? How many payments failed vs succeeded? |
| get_provider_stats | Which provider is performing best? Compare Stripe vs M-PESA. |
| get_recent_events | Show me the last 10 events. Which provider had failures today? |
| get_recent_payments | Show all M-PESA transactions. Which payments are still processing? |
Connecting Claude.ai: the ngrok journey
Claude.ai is a cloud service. Your development machine is not. Connecting them required ngrok — a tunneling tool that creates a public URL pointing at your local server.
The journey had three obstacles:
# Obstacle 1: Wrong URL
app.MapMcp() # registers at '/' — Claude can't find it
app.MapMcp("/mcp") # explicit path — works ✅
# Obstacle 2: CORS
# Claude.ai is a different origin — blocked by default
app.UseCors(p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
# Obstacle 3: ngrok version too old
ngrok update
ngrok http https://localhost:7070 --host-header="localhost:7070"
# → https://contusion-affirm-steadily.ngrok-free.dev/mcp ✅
What Claude found
Once connected, the first query was: "What is the total payment volume in PayCore?"
That last line is what separates an AI tool from an AI analyst. Claude didn't just answer the question — it identified the next question worth asking.
The bigger implication
Every .NET developer building a business system now has a straightforward path to making that system conversational. Add ModelContextProtocol.AspNetCore, write a few tool methods with good descriptions, expose an /mcp endpoint, and any Claude-connected interface can query your system in natural language.
This isn't the future of software. It's available today, in .NET 10, with a NuGet package and three lines of Program.cs.