Kestrun MCP Server
Kestrun.Mcp is a stdio-based Model Context Protocol (MCP) server for local Kestrun apps. It starts a Kestrun PowerShell script in-process, inspects the resulting host, and exposes safe MCP tools for route discovery, OpenAPI inspection, runtime inspection, request validation, and optional route invocation.
What It Exposes
The initial tool surface is:
kestrun.list_routeskestrun.get_routekestrun.get_openapikestrun.inspect_runtimekestrun.validate_requestkestrun.invoke_route
These tools are backed by Kestrun’s own route metadata, OpenAPI document generation, and HTTP pipeline. kestrun.invoke_route sends a real HTTP request to the running Kestrun listener. It does not bypass middleware, routing, validation, or content negotiation.
What You Can Do With It
Kestrun.Mcp is most useful when you want an MCP client or coding agent to inspect a live local Kestrun app without reverse-engineering the script by hand.
Typical uses:
- discover the routes a script actually registered, including verbs, tags, summaries, request content types, and response content types
- inspect one route in detail, including OpenAPI-derived request and response schemas when the route is annotated
- fetch the generated OpenAPI document as structured JSON instead of scraping
/openapi/...text output - check whether a request is likely to fail with
404,406, or415before sending it - safely invoke allowlisted local routes through the normal HTTP pipeline for smoke testing and agent workflows
Safety Model
The default posture is local and non-destructive:
kestrun.invoke_routeis disabled unless you explicitly enable it with one or more--allow-invokepatterns.- Invocation is limited to allowlisted paths.
- Response headers such as
Authorization,Cookie,Set-Cookie, andX-Api-Keyare redacted in tool output. - Runtime inspection returns a safe configuration snapshot and does not expose secret values from environment variables, configuration, certificates, or auth tokens.
Build And Install
Kestrun.Mcp is a C# project in this repository and is included in Kestrun.sln. The repository’s standard Invoke-Build Build flow stays focused on the main Kestrun artifacts, so the MCP host has its own dedicated build task.
From the repository root, restore dependencies and build the MCP host explicitly:
Invoke-Build Restore
Invoke-Build Build-KestrunMcp
If you prefer to build the project directly with dotnet:
dotnet build .\src\CSharp\Kestrun.Mcp\Kestrun.Mcp.csproj
This produces Kestrun.Mcp.dll under:
src/CSharp/Kestrun.Mcp/bin/Debug/net10.0/- or the matching
Releaseoutput if you build with-c Release
What You Need
To use the MCP server, you need:
- a Kestrun PowerShell script to run
- the Kestrun module manifest, typically
src/PowerShell/Kestrun/Kestrun.psd1 - a stdio-capable MCP client
- .NET 10 and PowerShell available on the local machine
The server starts the target script in-process, waits for a KestrunHost, and then exposes MCP tools against that running host.
Run The Server
From the repository root:
dotnet run --project .\src\CSharp\Kestrun.Mcp\Kestrun.Mcp.csproj -- `
--script .\docs\_includes\examples\pwsh\24.1-Mcp-Hello.ps1 `
--kestrun-manifest .\src\PowerShell\Kestrun\Kestrun.psd1
You can also launch the built DLL directly:
dotnet .\src\CSharp\Kestrun.Mcp\bin\Debug\net10.0\Kestrun.Mcp.dll -- `
--script .\docs\_includes\examples\pwsh\24.1-Mcp-Hello.ps1 `
--kestrun-manifest .\src\PowerShell\Kestrun\Kestrun.psd1
Command-Line Options
The initial command-line surface is:
--script <path>: required path to the Kestrun PowerShell script to run--kestrun-manifest <path>: optional explicitKestrun.psd1path--host-name <name>: optional named host when the script does not use the default host--discover-pshome: let the process discoverPSHOMEinstead of setting it explicitly--allow-invoke <pattern>: enablekestrun.invoke_routeand allow a path glob such as/helloor/api/*
If --kestrun-manifest is omitted, Kestrun.Mcp tries common local manifest locations before failing.
If the script registers a named host instead of using the default host, add --host-name:
dotnet run --project .\src\CSharp\Kestrun.Mcp\Kestrun.Mcp.csproj -- `
--script .\docs\_includes\examples\pwsh\24.1-Mcp-Hello.ps1 `
--kestrun-manifest .\src\PowerShell\Kestrun\Kestrun.psd1 `
--host-name MyHost
To enable request invocation for specific routes:
dotnet run --project .\src\CSharp\Kestrun.Mcp\Kestrun.Mcp.csproj -- `
--script .\docs\_includes\examples\pwsh\24.1-Mcp-Hello.ps1 `
--kestrun-manifest .\src\PowerShell\Kestrun\Kestrun.psd1 `
--allow-invoke /hello `
--allow-invoke /api/*
Configure A Script For MCP
The easiest setup is a normal local Kestrun script that:
- creates a server
- adds one or more listeners
- enables configuration
- registers routes
- starts the server
Example:
param([int]$Port = $env:PORT ?? 5000)
New-KrServer -Name 'MCP Hello'
Add-KrEndpoint -Port $Port
Enable-KrConfiguration
Add-KrMapRoute -Pattern '/hello' -Verbs Get -ScriptBlock {
Write-KrJsonResponse @{ message = 'hello from Kestrun' }
}
Start-KrServer
The same script can still be run normally outside MCP. The MCP host just supplies the process/runtime wrapper around it.
Configure An MCP Client
Any MCP client that supports stdio servers can launch Kestrun.Mcp. The MCP client needs to know:
- the executable to start, usually
dotnet - the arguments needed to launch
Kestrun.Mcp - which script the MCP server should run
- whether route invocation should be enabled
Typical client configuration:
{
"mcpServers": {
"kestrun": {
"command": "dotnet",
"args": [
"run",
"--project",
"./src/CSharp/Kestrun.Mcp/Kestrun.Mcp.csproj",
"--",
"--script",
"./docs/_includes/examples/pwsh/24.1-Mcp-Hello.ps1",
"--kestrun-manifest",
"./src/PowerShell/Kestrun/Kestrun.psd1",
"--allow-invoke",
"/hello"
]
}
}
}
If your client prefers launching a built binary instead of dotnet run, point it at the built DLL:
{
"mcpServers": {
"kestrun": {
"command": "dotnet",
"args": [
"./src/CSharp/Kestrun.Mcp/bin/Debug/net10.0/Kestrun.Mcp.dll",
"--script",
"./docs/_includes/examples/pwsh/24.1-Mcp-Hello.ps1",
"--kestrun-manifest",
"./src/PowerShell/Kestrun/Kestrun.psd1"
]
}
}
}
How To Use It
Once the MCP client connects, a typical workflow is:
- Call
kestrun.inspect_runtimeto confirm the host is running and listeners are active. - Call
kestrun.list_routesto see the registered routes and metadata. - Call
kestrun.get_routefor one route when you need request/response schema detail. - Call
kestrun.get_openapiwhen you want the full generated OpenAPI document. - Call
kestrun.validate_requestbefore invoking a route if you want likely404,406, or415outcomes explained. - Call
kestrun.invoke_routeonly for explicitly allowlisted paths.
Practical Walkthrough: Hello Route
Sample file: docs/_includes/examples/pwsh/24.1-Mcp-Hello.ps1
This script exposes one GET /hello route. It is the shortest useful MCP walkthrough because it shows route discovery, runtime inspection, and optional invocation.
Start the MCP server with route invocation enabled for /hello:
dotnet run --project .\src\CSharp\Kestrun.Mcp\Kestrun.Mcp.csproj -- `
--script .\docs\_includes\examples\pwsh\24.1-Mcp-Hello.ps1 `
--kestrun-manifest .\src\PowerShell\Kestrun\Kestrun.psd1 `
--allow-invoke /hello
Then use the MCP tools in this order.
1. Confirm The Runtime Is Ready
Tool call:
{
"tool": "kestrun.inspect_runtime",
"arguments": {}
}
Typical result excerpt:
{
"applicationName": "MCP Hello",
"status": "running",
"routeCount": 1
}
2. Discover The Registered Route
Tool call:
{
"tool": "kestrun.list_routes",
"arguments": {}
}
Typical result excerpt:
[
{
"pattern": "/hello",
"verbs": ["GET"]
}
]
3. Invoke The Route Through Kestrun
Tool call:
{
"tool": "kestrun.invoke_route",
"arguments": {
"method": "GET",
"path": "/hello"
}
}
Typical result excerpt:
{
"statusCode": 200,
"contentType": "application/json; charset=utf-8",
"body": "{\"message\":\"hello from Kestrun\"}"
}
That is a real request through the running Kestrun listener. If /hello was not included in --allow-invoke, the same tool call would return a 403 error with code invoke_not_allowlisted.
Example Script: Hello World
Sample file: docs/_includes/examples/pwsh/24.1-Mcp-Hello.ps1
With that script running through Kestrun.Mcp, an MCP client can call:
kestrun.list_routesto see/hellokestrun.inspect_runtimeto inspect listeners and uptimekestrun.invoke_routefor/helloif--allow-invoke /hellois enabled
Practical Walkthrough: OpenAPI-Aware Route
Sample file: docs/_includes/examples/pwsh/24.2-Mcp-OpenAPI.ps1
This script exposes a POST /items/{id} route with OpenAPI metadata. It is the better example when you want to see how MCP helps an agent inspect schemas, validate a request before sending it, and then invoke the route safely.
Start the MCP server with invocation enabled for the route family:
dotnet run --project .\src\CSharp\Kestrun.Mcp\Kestrun.Mcp.csproj -- `
--script .\docs\_includes\examples\pwsh\24.2-Mcp-OpenAPI.ps1 `
--kestrun-manifest .\src\PowerShell\Kestrun\Kestrun.psd1 `
--allow-invoke /items/*
1. Inspect A Route By operationId
Tool call:
{
"tool": "kestrun.get_route",
"arguments": {
"operationId": "createItem"
}
}
Typical result excerpt:
{
"route": {
"pattern": "/items/{id}",
"verbs": ["POST"],
"tags": ["items"],
"operationId": "createItem"
},
"requestSchemas": {
"application/json": {
"type": "object"
}
}
}
2. Fetch The Generated OpenAPI Document
Tool call:
{
"tool": "kestrun.get_openapi",
"arguments": {
"version": "3.1"
}
}
Typical result excerpt:
{
"documentId": "Default",
"version": "3.1.2",
"document": {
"openapi": "3.1.2",
"paths": {
"/items/{id}": {
"post": {}
}
}
}
}
3. Validate A Request Before Sending It
Tool call:
{
"tool": "kestrun.validate_request",
"arguments": {
"method": "POST",
"path": "/items/42",
"headers": {
"Content-Type": "application/json",
"Accept": "application/json"
},
"body": {
"name": "widget"
}
}
}
Typical result excerpt:
{
"isValid": true,
"statusCode": 200,
"message": "The request matches a registered route and satisfies known content-type/accept constraints."
}
A failure example with an incompatible Accept header:
{
"tool": "kestrun.validate_request",
"arguments": {
"method": "POST",
"path": "/items/42",
"headers": {
"Content-Type": "application/json",
"Accept": "text/plain"
},
"body": {
"name": "widget"
}
}
}
Typical failure excerpt:
{
"isValid": false,
"statusCode": 406,
"error": {
"code": "not_acceptable"
}
}
4. Invoke The Route After Validation
Tool call:
{
"tool": "kestrun.invoke_route",
"arguments": {
"method": "POST",
"path": "/items/42",
"headers": {
"Content-Type": "application/json",
"Accept": "application/json"
},
"body": {
"name": "widget"
}
}
}
Typical result excerpt:
{
"statusCode": 200,
"contentType": "application/json; charset=utf-8",
"body": "{\"itemId\":42,\"ok\":true}"
}
This makes kestrun.get_route and kestrun.get_openapi useful for the same route:
kestrun.get_routereturns route metadata plus OpenAPI-derived request and response schemas when available.kestrun.get_openapireturns the generated OpenAPI document as structured JSON.kestrun.validate_requestcan explain likely404,406, or415outcomes before you send a request.kestrun.invoke_routereturns response headers too, but sensitive values such asSet-Cookieare redacted when present.
Example Agent Tasks
Once the MCP server is connected, these are realistic things to ask an MCP-capable agent to do:
- “List the routes in my Kestrun script and tell me which ones accept JSON.”
- “Show me the OpenAPI schema for
createItem.” - “Check why
POST /items/42withAccept: text/plainwould fail.” - “Invoke
/helloand summarize the JSON response.” - “Fetch the OpenAPI 3.1 document and compare it with the route metadata for
/items/{id}.”
Notes
kestrun.get_openapisupports selecting an OpenAPI version such as2.0,3.0,3.1, or3.2.kestrun.get_routecan select a route by pattern and/or operation id.kestrun.inspect_runtimereports Kestrun runtime status, start time, uptime, listeners, and a safe configuration snapshot.kestrun.validate_requestis intended for debugging and agent planning. It predicts likely framework outcomes from route metadata and known content-type / Accept constraints.