Resources and Prompts Guide
Expose contextual information and reusable prompt templates to AI agents through PoshMcp's MCP Resources and Prompts capabilities.
Overview
MCP Resources
Resources allow AI agents to read static or dynamic content without invoking PowerShell commands. Perfect for:
- Configuration context: Expose runbooks, deployment guides, or policies
- Live system state: Serve processes, services, or Azure resources on-demand
- Audit trails: Expose logs or event data for analysis
- Infrastructure inventory: Share topology or resource listings
Two sources:
- File-based: Read from disk (config files, markdown docs, JSON)
- Command-based: Execute PowerShell and return output (live processes, service status)
MCP Prompts
Prompts are reusable templates with named arguments that AI agents can invoke. Perfect for:
- Standardized workflows: Define consistent runbook execution patterns
- Dynamic context injection: Pass runtime values (service names, resource IDs) into templates
- Compliance templates: Encode organizational best practices
- Multi-step guides: Create templates that orchestrate complex investigations
Prompts use generic template rendering with named placeholders.
MCP Resources
Configuration
Add resources to appsettings.json:
{
"McpResources": {
"Resources": [
{
"Uri": "poshmcp://resources/deployment-guide",
"Name": "Deployment Guide",
"Description": "Standard deployment procedures for production",
"MimeType": "text/markdown",
"Source": "file",
"Path": "docs/DEPLOYMENT.md"
},
{
"Uri": "poshmcp://resources/running-processes",
"Name": "Running Processes",
"Description": "Live list of running processes",
"MimeType": "application/json",
"Source": "command",
"Command": "Get-Process | Select-Object Name, Id, WorkingSet | ConvertTo-Json -Depth 2"
}
]
}
}
Schema Reference
| Field | Type | Required | Description |
|---|---|---|---|
Uri |
string | Yes | Unique resource identifier, typically poshmcp://resources/{id} |
Name |
string | Yes | Human-readable display name |
Description |
string | Yes | What the resource contains (shown in resources/list) |
MimeType |
string | Yes | Content type: text/plain, text/markdown, application/json, etc. |
Source |
string | Yes | "file" or "command" |
Path |
string | If Source="file" | File path (relative to appsettings.json directory, or absolute) |
Command |
string | If Source="command" | PowerShell command to execute |
Noun-Derived Resources
When PowerShellConfiguration.EnableNounResources is true, PoshMcp can derive additional MCP resources from the discovered PowerShell command set.
A noun becomes resourceable only when a matching Get-{Noun} command exists and at least one of its parameter sets can run without required user parameters. When that happens, PoshMcp:
- derives a snake_case resource name from the noun
- registers a
poshmcp://resources/{resource_name}resource inresources/list - serves
application/jsonfromresources/readby invoking the backingGet-{Noun}command with no arguments
For example, Get-NounResourceFixture produces a resource named noun_resource_fixture at poshmcp://resources/noun_resource_fixture.
If a noun does not have a matching Get-* command, or the matching Get-* command requires user input for every parameter set, PoshMcp does not list or read a derived resource for it.
Configure the feature in appsettings.json:
{
"PowerShellConfiguration": {
"EnableNounResources": true,
"NounResourceOverrides": {
"noun_resource_fixture": {
"ResourceName": "fixture_override",
"Uri": "poshmcp://resources/fixture_override",
"Description": "Fixture resource exposed through noun derivation"
}
}
}
}
Override keys use the default derived resource name. Each override can:
- set
Disabledto suppress the resource entirely - change
ResourceName,Uri, orDescription - set
DisableResourceLinkBlockto keep the resource readable but skip tool-result link injection
You can also associate a specific exposed MCP resource with an individual command result through PowerShellConfiguration.CommandOverrides.<Command>.AssociatedResourceUri (or legacy FunctionOverrides). This association can point at either:
- a static/custom resource from
McpResources.Resources - a noun-derived resource exposed through
EnableNounResources
Resource Link Blocks
When noun-derived resources are enabled, successful tool results for the same noun get an extra content block appended at the end of the MCP result. The block points the client at the readable MCP resource for that noun.
The appended block uses the application/json+mcp-resource-link MIME type:
{
"type": "resource",
"resource": {
"uri": "poshmcp://resources/noun_resource_fixture",
"mimeType": "application/json+mcp-resource-link",
"text": "{\"resourceLink\":{\"uri\":\"poshmcp://resources/noun_resource_fixture\",\"resourceName\":\"noun_resource_fixture\",\"noun\":\"NounResourceFixture\",\"relationship\":\"subject\",\"description\":\"...\"}}"
}
}
This block is not appended when:
- noun resources are disabled
- the noun override sets
Disabled: true - the noun override sets
DisableResourceLinkBlock: true - the tool result is returned with
isError: true
When AssociatedResourceUri is set on a command override, PoshMcp first tries to resolve that URI against the exposed resource surface. If it resolves, PoshMcp appends exactly one application/json+mcp-resource-link block for that target with relationship: "context", even when the noun override has DisableResourceLinkBlock: true.
If AssociatedResourceUri is missing or does not resolve to an exposed resource for a discovered command override during tool setup, PoshMcp falls back to the implicit noun-derived behavior above. That unresolved override path logs a warning and is otherwise ignored; PoshMcp does not perform generic startup validation of AssociatedResourceUri values.
Example:
{
"PowerShellConfiguration": {
"CommandOverrides": {
"Invoke-Deployment": {
"AssociatedResourceUri": "poshmcp://resources/deployment-guide"
}
}
},
"McpResources": {
"Resources": [
{
"Uri": "poshmcp://resources/deployment-guide",
"Name": "Deployment Guide",
"Description": "Operator runbook for deployment workflows",
"MimeType": "text/markdown",
"Source": "file",
"Path": "docs/DEPLOYMENT.md"
}
]
}
}
Example: File-Based Resources
Expose documentation files for AI context:
{
"McpResources": {
"Resources": [
{
"Uri": "poshmcp://resources/runbook-vm-restart",
"Name": "VM Restart Runbook",
"Description": "Standard procedure for restarting Azure VMs",
"MimeType": "text/markdown",
"Source": "file",
"Path": "runbooks/restart-vm.md"
},
{
"Uri": "poshmcp://resources/compliance-checklist",
"Name": "Security Compliance Checklist",
"Description": "Required checks before production deployment",
"MimeType": "text/markdown",
"Source": "file",
"Path": "docs/compliance/checklist.md"
}
]
}
}
File paths are resolved relative to the directory containing appsettings.json. Use absolute paths for resources outside the config directory:
{
"Uri": "poshmcp://resources/external-guide",
"Source": "file",
"Path": "/shared/guides/architecture.md"
}
Example: Command-Based Resources
Serve live system data:
{
"McpResources": {
"Resources": [
{
"Uri": "poshmcp://resources/critical-services",
"Name": "Critical Services Status",
"Description": "Real-time status of critical Windows services",
"MimeType": "application/json",
"Source": "command",
"Command": "Get-Service -ServiceName 'wuauserv', 'spooler', 'w32time' | Select-Object Name, Status, StartType | ConvertTo-Json"
},
{
"Uri": "poshmcp://resources/azure-resource-inventory",
"Name": "Azure Resource Inventory",
"Description": "List of Azure resources in production subscription",
"MimeType": "application/json",
"Source": "command",
"Command": "Get-AzResource -ResourceGroupName 'prod-*' | Select-Object Name, ResourceType, Location, Id | ConvertTo-Json -Depth 2"
},
{
"Uri": "poshmcp://resources/disk-usage",
"Name": "Disk Usage Report",
"Description": "Free disk space across all drives",
"MimeType": "application/json",
"Source": "command",
"Command": "Get-Volume | Where-Object DriveLetter | Select-Object DriveLetter, @{Label='SizeGB';Expression={$_.Size/1GB}}, @{Label='FreeGB';Expression={$_.SizeRemaining/1GB}} | ConvertTo-Json"
}
]
}
}
MCP Methods
resources/list
Discover all configured resources.
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "resources/list"
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resources": [
{
"uri": "poshmcp://resources/deployment-guide",
"name": "Deployment Guide",
"description": "Standard deployment procedures",
"mimeType": "text/markdown"
},
{
"uri": "poshmcp://resources/running-processes",
"name": "Running Processes",
"description": "Live list of running processes",
"mimeType": "application/json"
}
]
}
}
resources/read
Read a specific resource by URI.
Request:
{
"jsonrpc": "2.0",
"id": 2,
"method": "resources/read",
"params": {
"uri": "poshmcp://resources/deployment-guide"
}
}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"contents": [
{
"uri": "poshmcp://resources/deployment-guide",
"mimeType": "text/markdown",
"text": "# Deployment Guide\n\n1. Pre-check list...\n2. Execute migration...\n"
}
]
}
}
Command-Based Resource Best Practices
Performance:
- Keep PowerShell commands fast; resources are executed on every
resources/readcall - Use targeted filtering:
Get-Process -Name 'svchost'instead ofGet-Process | Where-Object ... - Consider caching implications if resources are read frequently
Error handling:
- PowerShell errors in command-based resources return MCP error responses
- Use
-ErrorAction Stopto fail fast on errors - Test commands independently before adding to configuration
Output formatting:
- Use
ConvertTo-Json -Depth 2for nested objects - Use
Select-Objectto limit output size - Use
Format-TableorConvertTo-Csvfor large datasets
Security:
- Resources are visible to any MCP client that can connect
- Do not expose secrets, API keys, or sensitive data
- Consider resource URIs as part of your security boundary
MCP Prompts
Configuration
Add prompts to appsettings.json:
{
"McpPrompts": {
"Prompts": [
{
"Name": "analyze-service",
"Description": "Analyze Windows service status and health",
"Arguments": [
{
"Name": "serviceName",
"Description": "Name of the Windows service",
"Required": true
},
{
"Name": "detail",
"Description": "Level of detail (basic, advanced)",
"Required": false
}
],
"Source": "command",
"Command": "Analyze service '{{serviceName}}' with detail level '{{detail}}'."
}
]
}
}
Schema Reference
| Field | Type | Required | Description |
|---|---|---|---|
Name |
string | Yes | Prompt identifier (must be unique) |
Description |
string | Recommended | Purpose of the prompt (shown in prompts/list) |
Arguments |
array | No | Array of argument definitions |
Arguments[].Name |
string | Yes | Argument name |
Arguments[].Description |
string | Recommended | What the argument is for |
Arguments[].Required |
boolean | No | Whether the argument must be provided (default: false) |
Source |
string | Yes | "file" or "command" |
Path |
string | If Source="file" |
File path to load template content |
Command |
string | If Source="command" |
Command/script used to produce template content |
Template placeholders support both:
{{argName}}(preferred){argName}(backward-compatible)
Example: Simple Prompts
Basic prompt with required argument:
{
"Name": "check-process",
"Description": "Summarize details of a running process",
"Source": "command",
"Arguments": [
{
"Name": "processName",
"Description": "Process name to check",
"Required": true
}
],
"Command": "Analyze process '{{processName}}' and summarize health indicators."
}
Prompt with optional arguments:
{
"Name": "list-services",
"Description": "List Windows services with optional filtering",
"Source": "file",
"Arguments": [
{
"Name": "pattern",
"Description": "Filter services by name pattern (e.g., 'sql*')",
"Required": false
}
],
"Path": "prompts/list-services.md"
}
Example: Complex Prompts
Multi-argument prompt for incident investigation:
{
"McpPrompts": {
"Prompts": [
{
"Name": "investigate-incident",
"Description": "Investigate a specific incident event",
"Source": "command",
"Arguments": [
{
"Name": "eventId",
"Description": "Event ID to investigate",
"Required": true
},
{
"Name": "logName",
"Description": "Event log name (System, Application, Security)",
"Required": false
},
{
"Name": "hours",
"Description": "Look back this many hours (default: 24)",
"Required": false
}
],
"Command": "Investigate event '{{eventId}}' in log '{{logName}}' over the last '{{hours}}' hours. Return findings and next actions."
}
]
}
}
MCP Methods
prompts/list
Discover all configured prompts.
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "prompts/list"
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"prompts": [
{
"name": "analyze-service",
"description": "Analyze Windows service status and health",
"arguments": [
{
"name": "serviceName",
"description": "Name of the Windows service",
"required": true
}
]
}
]
}
}
prompts/get
Retrieve a prompt with arguments rendered.
Request:
{
"jsonrpc": "2.0",
"id": 2,
"method": "prompts/get",
"params": {
"name": "analyze-service",
"arguments": {
"serviceName": "svchost"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "Analyze Windows service status and health\n\nService name: svchost\n\nDetail level: basic"
}
}
]
}
}
Runtime behavior summary:
prompts/listexposes configured prompt metadata and argument definitions.prompts/getloads content from the selected source (fileviaPath,commandviaCommand) and renders placeholders using request arguments.- Required arguments (
Required: true) are enforced atprompts/getruntime. - Placeholder syntax supports both
{{argName}}(preferred) and{argName}(backward-compatible).
Prompt Best Practices
Argument handling:
- Use meaningful names:
serviceName,resourceId,environment(notarg1,arg2) - Provide clear descriptions for required arguments
- Use optional arguments for filtering or configuration
- Prefer
{{argName}}placeholders in new prompts - Keep
{argName}only when maintaining existing templates
Command design:
- Keep prompts focused: one investigation, analysis, or action per prompt
- Use readable placeholders:
{{serviceName}}, not abbreviated names - Handle missing optional arguments gracefully with
if/elselogic - Return structured output: use
Select-ObjectorConvertTo-Json
Error handling:
- Prompt PowerShell errors return MCP error responses
- Use
-ErrorAction SilentlyContinuefor non-critical failures - Return meaningful error messages (don't let PowerShell errors propagate raw)
Security:
- Prompts execute in the shared PowerShell runspace with full command access
- Do not expose prompts for destructive commands (Remove-, Reset-, etc.)
- Validate user-supplied arguments before interpolating into dangerous commands
- Consider RBAC: filter by user identity if exposed via HTTP
Configuration Validation
Use poshmcp doctor to validate your resources and prompts configuration:
poshmcp doctor
Doctor checks include:
Resources:
- Duplicate URIs
- File paths exist and are readable
- PowerShell command syntax is valid
- MimeType values are recognized
Prompts:
- Duplicate names
- Required arguments are documented
- PowerShell command syntax is valid
- Template placeholders reference declared argument names
Noun resources:
- Whether noun-derived resources are enabled
- Registered noun-derived resources and their backing
Get-*commands - Resource name conflicts
- Suppressed nouns from
NounResourceOverrides
When noun resources are enabled, the text report includes a Noun Resources section that lists registered resources as:
registered : 1 resource(s)
- noun_resource_fixture (Get-NounResourceFixture) -> poshmcp://resources/noun_resource_fixture
Output:
Validation Results
==================
Resources: 3 configured
✓ poshmcp://resources/deployment-guide — file OK
✓ poshmcp://resources/running-processes — command OK
✓ poshmcp://resources/audit-log — file OK
Prompts: 2 configured
✓ analyze-service — 1 required arg
✓ investigate-incident — 3 args
No issues found.
Common Patterns
Pattern 1: Expose Configuration Files
Share runbooks or policies as grounded context:
{
"Uri": "poshmcp://resources/production-runbook",
"Name": "Production Runbook",
"Description": "Runbook for production deployments",
"MimeType": "text/markdown",
"Source": "file",
"Path": "docs/production-runbook.md"
}
Pattern 2: Live System State
Serve on-demand snapshots of system health:
{
"Uri": "poshmcp://resources/health-status",
"Name": "System Health Status",
"Description": "Current system health metrics",
"MimeType": "application/json",
"Source": "command",
"Command": "$cpu = (Get-Counter '\\Processor(_Total)\\% Processor Time' -SampleInterval 1 -MaxSamples 1).CounterSamples[0].CookedValue\n$mem = Get-CimInstance Win32_OperatingSystem | Select-Object @{Label='MemUsedGB';Expression={($_.TotalVisibleMemorySize-$_.FreePhysicalMemory)/1MB}}, @{Label='MemTotalGB';Expression={$_.TotalVisibleMemorySize/1MB}}\n@{ cpu = $cpu; memory = $mem } | ConvertTo-Json"
}
Pattern 3: Parameterized Analysis
Reusable templates for common investigations:
{
"Name": "analyze-disk",
"Description": "Analyze disk usage for a specific drive",
"Arguments": [
{
"Name": "drive",
"Description": "Drive letter (C, D, etc.)",
"Required": true
}
],
"Command": "$disk = Get-Volume -DriveLetter $drive -ErrorAction Stop\n$dir = \"$drive`:\"\n$top = Get-ChildItem -Path $dir -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum\n@{\n disk = $disk | Select-Object DriveLetter, Size, SizeRemaining\n topDir = $top | Select-Object Count, Sum\n} | ConvertTo-Json"
}
Pattern 4: Multi-Step Workflows
Prompts that orchestrate complex investigations:
{
"Name": "audit-permissions",
"Description": "Audit permissions for a resource",
"Arguments": [
{
"Name": "resourceId",
"Description": "Azure resource ID",
"Required": true
}
],
"Command": "$resource = Get-AzResource -ResourceId $resourceId\n$assignments = Get-AzRoleAssignment -Scope $resourceId | Select-Object RoleDefinitionName, DisplayName, Scope\n$perms = @{\n resource = $resource | Select-Object Name, ResourceType, Location\n assignments = $assignments\n}\n$perms | ConvertTo-Json -Depth 2"
}
Troubleshooting
Resource read fails with "file not found"
Symptom: resources/read returns error "Path does not exist"
Solution:
- Check that file path is relative to
appsettings.jsondirectory, or use an absolute path - Verify file permissions (PoshMcp process must be able to read the file)
"Path": "docs/guide.md" // Relative to appsettings.json
"Path": "/etc/poshmc/config.json" // Absolute path
Command-based resource returns PowerShell errors
Symptom: resources/read returns error with PowerShell exception
Solution:
- Test command independently:
pwsh -Command 'Your-Command' - Add error handling:
Get-Service -Name $name -ErrorAction Stop - Check that modules are loaded or imported in
appsettings.json
Prompt arguments not being substituted
Symptom: Prompt output shows {{argName}} or {argName} literally instead of argument values
Solution:
- Verify argument names match placeholders exactly (
serviceName→{{serviceName}}) - Ensure required arguments are supplied in
prompts/getparams.arguments - Check the prompt uses supported placeholder syntax (
{{argName}}preferred,{argName}backward-compatible)
Doctor reports duplicate URIs
Symptom: poshmcp doctor output: "Duplicate URI: poshmcp://resources/my-resource"
Solution:
- Each resource must have a unique URI
- Search
appsettings.jsonfor duplicate URIs:"Uri": "poshmcp://resources/..." - Rename conflicting resources
See Also
- Configuration Guide — Full appsettings.json schema
- Release Notes 0.6.0 — What's new in this release
- MCP Specification — Official MCP protocol documentation
- Getting Started — Installation and first steps