MCP Architecture
This document describes the Model Context Protocol (MCP) architecture implementation in Roslyn-Stone.
Overview
Roslyn-Stone implements MCP to help LLMs create single-file C# utility programs (file-based apps). It properly distinguishes between:
- Tools: Active functions that execute, validate, and build utility programs
- Resources: Passive data sources providing read-only access to documentation and package info
- Prompts: Optimized templates guiding LLMs to create runnable .cs files
Design Philosophy
The goal is to enable LLMs to create complete, runnable single-file C# programs using .NET 10's file-based app feature. This aligns with dotnet run app.cs, which eliminates the need for project files and boilerplate code by supporting:
- Top-level statements: No class or Main method required
#:packagedirective: Declare NuGet dependencies directly in .cs files#:sdkdirective: Specify project SDK (e.g., Microsoft.NET.Sdk.Web) in code
Target output: Self-contained .cs files that can be run directly, perfect for:
- Command-line utilities
- Data processing scripts
- Automation tools
- Web APIs and services
- Quick C# programs without project scaffolding
Development workflow:
- Test with
nugetPackagesparameter: Load packages during REPL execution for testing - Finalize with
#:packagedirective: Create self-contained .cs files for production use - No .csproj needed: Everything declared in the single .cs file
Resources (Passive Data Access)
Resources provide read-only, URI-based access to data. They enable efficient discovery and querying without execution.
DocumentationResource
Provides access to .NET XML documentation.
URI Pattern: doc://{symbolName}
Examples:
doc://System.String
doc://System.Linq.Enumerable.Select
doc://System.Collections.Generic.List`1
Response: Structured documentation with summary, parameters, return values, examples, and related types.
NuGetSearchResource
Searchable catalog of NuGet packages.
URI Pattern: nuget://search?q={query}&skip={skip}&take={take}
Examples:
nuget://search?q=json
nuget://search?q=http%20client&skip=0&take=10
Response: Package list with ID, description, version, download count, tags.
NuGetPackageResource
Package-specific information.
URI Patterns:
- Versions:
nuget://packages/{id}/versions - README:
nuget://packages/{id}/readme?version={version}
Examples:
nuget://packages/Newtonsoft.Json/versions
nuget://packages/Newtonsoft.Json/readme
nuget://packages/Newtonsoft.Json/readme?version=13.0.3
Response: Version list or README content in Markdown.
ReplStateResource
REPL environment and session state.
URI Patterns:
- General:
repl://stateorrepl://info - Session-specific:
repl://sessions/{contextId}/state
Examples:
repl://state
repl://sessions/abc-123-def-456/state
Response: Framework version, capabilities, active session count, session metadata.
Tools (Active Operations)
Tools perform operations and can modify state. All REPL tools support context management.
Context-Aware Design
All tools accept an optional contextId parameter:
- Without contextId: Single-shot execution (context created, can be reused)
- With contextId: Session-based execution (state persists)
EvaluateCsharp
Execute C# code to create and test single-file utility programs. Supports inline package loading for testing.
Parameters:
code: C# code to execute (use top-level statements for file-based apps)contextId(optional): Session context ID for iterative developmentcreateContext(optional): Create persistent context for multi-step buildingnugetPackages(optional): Array of packages to load inline:[{packageName: "Humanizer", version: "3.0.1"}]
Returns: { success, returnValue, output, errors, warnings, executionTime, contextId }
Use Cases:
- Test complete utility programs with packages loaded inline
- Iteratively build single-file apps with stateful context
- Validate program logic before finalizing
- Rapid prototyping with NuGet packages (test) β Finalize with
#:packagedirective (production)
Example workflow:
1. Test: EvaluateCsharp(code, nugetPackages: [{packageName: "Humanizer"}])
2. Iterate: Refine logic with loaded packages
3. Finalize: Output utility.cs with #:package directive at top
ValidateCsharp
Validate C# syntax and semantics for single-file utility programs.
Parameters:
code: C# code to validate (use top-level statements)contextId(optional): Session context for context-aware validation
Returns: { isValid, issues: [{ code, message, severity, line, column }] }
Use Cases:
- Check utility program syntax before execution
- Validate complete .cs files
- Context-aware validation against session variables
ResetRepl
Reset REPL sessions.
Parameters:
contextId(optional): Specific session to reset
Behavior:
- With contextId: Reset specific session
- Without contextId: Reset all sessions
Returns: { success, message, sessionsCleared }
LoadNuGetPackage
Load a NuGet package for use in utility programs.
Parameters:
packageName: Package IDversion(optional): Specific version (omit for latest stable)
Use Cases: Add functionality to single-file utility programs (JSON processing, HTTP clients, etc.)
GetReplInfo
Get current execution environment information and capabilities for building file-based C# apps.
Parameters:
contextId(optional): Session context for session-specific information
Returns: { frameworkVersion, language, state, activeSessionCount, contextId, isSessionSpecific, defaultImports, capabilities, tips, examples, sessionMetadata }
Use Cases:
- Understand environment capabilities (.NET 10, C# 14)
- Check active session count
- Get tips for creating utility programs (includes
nugetPackagesguidance) - Access example code patterns (includes package loading example)
- Learn about file-based app workflow (REPL testing β
#:packagefinalization)
SearchNuGetPackages
Search for NuGet packages (Tool alternative to nuget://search resource).
Parameters:
query: Search queryskip(optional): Pagination offset (default: 0)take(optional): Results to return (default: 20, max: 100)
Returns: { packages, totalCount, query, skip, take }
Use Cases: For clients that don't support MCP resources
GetNuGetPackageVersions
Get all versions of a NuGet package (Tool alternative to nuget://packages/{id}/versions resource).
Parameters:
packageId: Package ID to query
Returns: { found, packageId, versions, totalCount }
Use Cases: For clients that don't support MCP resources
GetNuGetPackageReadme
Get README content for a NuGet package (Tool alternative to nuget://packages/{id}/readme resource).
Parameters:
packageId: Package IDversion(optional): Specific version (omit for latest)
Returns: { found, packageId, version, content }
Use Cases: For clients that don't support MCP resources
GetDocumentation
Get XML documentation for .NET types/methods (Tool alternative to doc:// resource).
Parameters:
symbolName: Fully qualified type or method namepackageId(optional): NuGet package ID for package-specific types
Returns: { found, symbolName, summary, remarks, parameters, returns, exceptions, example }
Use Cases: For clients that don't support MCP resources
Examples:
- GetDocumentation("System.String")
- GetDocumentation("JsonConvert", "Newtonsoft.Json")
Context Management
IReplContextManager
Interface for managing REPL session lifecycle.
Key Methods:
CreateContext(): Create new session, return GUIDContextExists(contextId): Check if session existsGetContextState(contextId): Retrieve script stateUpdateContextState(contextId, state): Update script stateRemoveContext(contextId): Delete sessionCleanupExpiredContexts(): Remove old sessions
ReplContextManager
Thread-safe implementation using ConcurrentDictionary.
Features:
- Configurable timeout (default: 30 minutes)
- Automatic cleanup of expired sessions
- Metadata tracking (creation time, last access, execution count)
- Thread-safe concurrent operations
Context Metadata
Tracks session information:
ContextId: Unique identifier (GUID)CreatedAt: Session creation timestampLastAccessedAt: Last activity timestampExecutionCount: Number of executionsIsInitialized: Whether code has been executed
Prompts (Optimized Templates)
Prompts guide LLMs in creating single-file C# utility programs. All prompts focus on file-based app patterns.
Available Prompts
- QuickStartRepl (150 tokens): Quick start for creating single-file utilities
- GetStartedWithCsharpRepl (800 tokens): Comprehensive guide to file-based C# apps with complete examples
- DebugCompilationErrors (250 tokens): Error handling workflow
- ReplBestPractices (600 tokens): Best practices for creating utility programs with complete examples
- WorkingWithPackages (400 tokens): Using NuGet packages in utility programs
- PackageIntegrationGuide (700 tokens): Detailed package integration with 4 complete utility examples
Prompt Design Principles
- File-based focus: Guide LLMs to create complete, runnable .cs files with .NET 10 syntax
- Top-level statements: Emphasize simple, boilerplate-free code
#:packagedirective: Show self-contained apps with inline package declarations#:sdkdirective: Demonstrate specialized SDKs (e.g., web apps)- Complete examples: Show full utility programs, not just snippets
- Resource-driven: Reference doc://, nuget:// for API lookup
- Context-aware: Document optional contextId for iterative development
- nugetPackages parameter: Show testing workflow with inline package loading
- Two-phase workflow: Test with
nugetPackagesβ Finalize with#:package - Workflow-focused: Resource query β Build β Test β Refine
- Practical patterns: Real-world utility examples (file processing, HTTP clients, etc.)
Workflow Patterns
Creating a Simple Utility
1. Access doc://System.IO.File (learn API)
2. ValidateCsharp(code) (check syntax)
3. EvaluateCsharp(code) (test program)
4. β Complete utility.cs file
Building with Packages (Recommended Workflow)
Testing Phase:
1. Access nuget://search?q=json (find package)
2. Access nuget://packages/Newtonsoft.Json/readme (read docs)
3. EvaluateCsharp(code, nugetPackages: [{packageName: "Newtonsoft.Json", version: "13.0.3"}])
(test with inline package loading)
4. Iterate and refine logic
Finalization Phase:
5. Generate final utility.cs with #:package directive:
#:package [email protected]
using Newtonsoft.Json;
// ... complete utility code ...
6. β Self-contained json-processor.cs (no .csproj needed!)
7. Run with: dotnet run json-processor.cs
Alternative (Legacy):
1. Access nuget://search?q=json (find package)
2. LoadNuGetPackage("Newtonsoft.Json") (load into global context)
3. EvaluateCsharp(code) (test)
4. β Generate utility.cs (requires .csproj or LoadNuGetPackage for execution)
Iterative Development
1. EvaluateCsharp(initial code, createContext: true) β get contextId
2. ValidateCsharp(next code, contextId) β check additions
3. EvaluateCsharp(next code, contextId) β test incremental changes
4. Repeat steps 2-3 as needed
5. β Final complete utility program
Design Decisions
Why Focus on File-Based Apps?
- Simplicity: No project files, build configuration, or boilerplate code
- Self-contained:
#:packagedirective eliminates need for .csproj - Quick utilities: Perfect for creating small, focused programs
- LLM-friendly: Clear goal (complete .cs file) vs. open-ended REPL experimentation
- Real-world use: Aligns with .NET 10's
dotnet run app.csfeature - Completeness: Guides toward finished programs, not code snippets
- Modern syntax: Leverages .NET 10 directives for project-less development
Why Resources?
- Efficiency: Read-only data access without execution overhead
- Discoverability: LLMs can explore available data
- Caching: Resources can be cached by clients
- Separation: Clear distinction between data (Resources) and operations (Tools)
Why Context Management?
- Iterative development: Build utility programs step by step
- Isolation: Multiple concurrent sessions without interference
- Flexibility: Support both single-shot and iterative development
- Lifecycle: Automatic cleanup prevents resource leaks
Why Optimize Prompts?
- Clear guidance: Help LLMs create complete, runnable programs
- Token efficiency: Focus on essential patterns and examples
- Practical examples: Show real utility programs, not toy snippets
- Resource-driven: Leverage Resources for API docs instead of embedding
- Goal-oriented: Guide toward finished .cs files
Performance Considerations
Resource Caching
- Documentation lookups cached by symbol name
- NuGet queries cached by search terms
- Package metadata cached by ID
Context Cleanup
- Automatic background cleanup every X minutes
- Configurable timeout (default: 30 minutes)
- Manual cleanup via ResetRepl
Concurrent Sessions
- Thread-safe ConcurrentDictionary
- No lock contention for independent sessions
- Isolation prevents cross-session interference
Testing
Test Coverage
- Resources: 12 tests covering URI parsing, error handling, response structure
- Context Management: 19 tests covering lifecycle, thread safety, cleanup
- Tools: 11 integration tests updated for context-aware API
- Total: 580+ new assertions, 134 tests passing
Test Categories
- Unit tests: Components in isolation
- Integration tests: Tool β Service β Context interactions
- Resource tests: URI handling and response validation
- Thread safety tests: Concurrent context operations
Future Enhancements
Potential Additions
- Context persistence: Save/restore sessions across server restarts
- Context limits: Enforce maximum context count/size
- Context listing resource:
repl://sessionsto enumerate all - Package documentation resource: Loaded package type docs
- Execution history resource: Per-session execution log
Optimization Opportunities
- Lazy loading for Resources
- Response streaming for large results
- Incremental compilation caching
- NuGet package preloading
Recommended Pairing: Microsoft Learn MCP
For optimal C# utility program development, Roslyn-Stone pairs excellently with the Microsoft Learn MCP server (github.com/microsoftdocs/mcp).
Complementary capabilities:
- Roslyn-Stone: C# code execution, validation, package loading, REPL testing
- Microsoft Learn MCP: Official .NET documentation, API references, code samples from Microsoft Learn
Combined workflow:
- Search docs (Microsoft Learn) β Find APIs
- Get code samples (Microsoft Learn) β Test with packages (Roslyn-Stone)
- Look up types (both) β Execute and validate (Roslyn-Stone)
- Build utility with official guidance + live testing
This combination provides comprehensive documentation alongside live execution for the ultimate utility program development experience.
References
- Model Context Protocol: https://modelcontextprotocol.io
- MCP C# SDK: https://github.com/modelcontextprotocol/csharp-sdk
- Microsoft Learn MCP: https://github.com/microsoftdocs/mcp (recommended pairing)
- Roslyn Scripting: https://github.com/dotnet/roslyn/wiki/Scripting-API-Samples
- .NET 10 File-Based Apps: https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/