Roslyn-Stone / GETTING_STARTED.md
dylanlangston's picture
Add files using upload-large-folder tool
e462aae verified

Getting Started with Roslyn-Stone Development

This guide covers advanced setup options, development workflows, and technical details for contributors and developers working on Roslyn-Stone.

For basic usage, see the main README.md.

Table of Contents

Local Development Setup

Prerequisites

  • .NET 10.0 SDK or later
  • C# 13
  • Docker (for containerized deployment)
  • VS Code with Dev Containers extension (optional)
  • .NET Aspire workload (optional, for local orchestration)

Building from Source

# Clone the repository
git clone https://github.com/dylanlangston/Roslyn-Stone.git
cd Roslyn-Stone

# Build the solution
dotnet build

# Run tests
dotnet test

# Run the MCP server (stdio transport - default)
cd src/RoslynStone.Api
dotnet run

Transport Modes

Roslyn-Stone supports two MCP transport modes:

Stdio Transport (Default)

  • Best for local, single-machine integrations
  • Used by Claude Desktop and other local MCP clients
  • Communication via stdin/stdout
  • No network ports required

HTTP Transport

  • Best for remote access and web-based integrations
  • Accessible over the network via HTTP/SSE
  • Endpoint at /mcp (e.g., http://localhost:8080/mcp)
  • ⚠️ WARNING: Do not expose publicly without authentication, authorization, and network restrictions. This server can execute arbitrary C# code.

To switch transport modes, set the MCP_TRANSPORT environment variable:

# Stdio (default)
MCP_TRANSPORT=stdio dotnet run

# HTTP
MCP_TRANSPORT=http dotnet run --urls "http://localhost:8080"

Development Environments

With Aspire (Orchestrated)

# Install Aspire workload
dotnet workload install aspire

# Run with Aspire dashboard for observability
cd src/RoslynStone.AppHost
dotnet run

This will start:

  • Aspire Dashboard at http://localhost:18888 - View logs, metrics, and traces
  • MCP Inspector UI at http://localhost:6274 - Interactive tool testing interface (development mode only)
  • MCP Proxy at http://localhost:6277 - Protocol bridge for the inspector
  • MCP Server (stdio) - Stdio transport instance for local testing
  • MCP Server (HTTP) at http://localhost:8080/mcp - HTTP transport instance for remote access

The MCP Inspector is automatically started in development mode, providing a web-based interface to test and debug MCP tools in real-time.

Development Container

The repository includes a fully configured devcontainer with Docker-in-Docker support for isolated development:

# Open the repo in VS Code
code .

# Press F1 and select "Dev Containers: Reopen in Container"
# The container will automatically build, restore dependencies, and build the project

See .devcontainer/README.md for more details about the devcontainer setup.

Docker Compose

# Build and run both stdio and HTTP variants with Docker Compose
docker-compose up --build

# Run only the stdio variant
docker-compose up roslyn-stone-mcp-stdio

# Run only the HTTP variant
docker-compose up roslyn-stone-mcp-http

# Access Aspire dashboard at http://localhost:18888
# Access HTTP MCP endpoint at http://localhost:8080/mcp

The server supports both stdio and HTTP transport modes:

  • Stdio transport: Reads JSON-RPC messages from stdin and writes responses to stdout, with logging to stderr
  • HTTP transport: Exposes MCP endpoints via HTTP/SSE for remote access at /mcp

Advanced Configuration

Custom MCP Server Configurations

For local development without Docker:

Claude Desktop:

{
  "mcpServers": {
    "roslyn-stone": {
      "command": "dotnet",
      "args": ["run", "--project", "/path/to/Roslyn-Stone/src/RoslynStone.Api"],
      "env": {
        "DOTNET_ENVIRONMENT": "Development",
        "MCP_TRANSPORT": "stdio"
      }
    }
  }
}

HTTP Transport Configuration

For remote MCP servers or web-based integrations, use HTTP transport:

Local HTTP Server:

# Start the server with HTTP transport
cd src/RoslynStone.Api
MCP_TRANSPORT=http ASPNETCORE_URLS=http://localhost:8080 dotnet run

Docker HTTP Server:

# Run with HTTP transport
docker run -e MCP_TRANSPORT=http -e ASPNETCORE_URLS=http://+:8080 -p 8080:8080 ghcr.io/dylanlangston/roslyn-stone:latest

MCP Client Configuration (HTTP):

{
  "mcpServers": {
    "roslyn-stone-http": {
      "type": "http",
      "url": "http://localhost:8080/mcp"
    }
  }
}

The HTTP endpoint supports:

  • Server-Sent Events (SSE) for streaming responses
  • CORS support for web-based clients - ⚠️ Configure strict origin allowlists in production. Never use wildcard (*) CORS for code execution endpoints.
  • Standard MCP protocol over HTTP

See .github/MCP_CONFIGURATION.md for more configuration examples.

OpenTelemetry Configuration

Configure OpenTelemetry export with environment variables:

# OTLP endpoint (default: Aspire dashboard)
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:18889

# Service name
OTEL_SERVICE_NAME=roslyn-stone-mcp

# Additional resource attributes
OTEL_RESOURCE_ATTRIBUTES=service.namespace=roslyn-stone,deployment.environment=production

Production Deployment

For production, configure the OTLP endpoint to send telemetry to your monitoring solution:

  • Azure Monitor / Application Insights
  • AWS CloudWatch
  • Google Cloud Operations
  • Grafana / Prometheus / Jaeger
  • Any OTLP-compatible collector

Development Tools

This project uses several development tools:

  • CSharpier - Code formatter (dotnet csharpier <file-or-directory>)
  • ReSharper CLI - Code analysis (jb <command>)
  • Cake - Build automation (dotnet cake <script>)

See .github/COPILOT_ENVIRONMENT.md for details on the custom environment setup.

Testing

Running Tests

dotnet test --logger "console;verbosity=normal"

# Run tests by category
dotnet test --filter "Category=Unit"

# Run tests by component
dotnet test --filter "Component=REPL"

Test Coverage

The project maintains high test coverage with automated reporting in CI:

  • Line Coverage: >86% (target: 80%)
  • Branch Coverage: >62% (target: 75%)
  • Total Tests: 103+ tests

Run Tests with Coverage

# Using Cake build script (recommended)
dotnet cake --target=Test-Coverage

# Using dotnet CLI
dotnet test --collect:"XPlat Code Coverage"

Coverage reports are generated in ./artifacts/coverage/ with detailed metrics including:

  • Line coverage percentage
  • Branch coverage percentage
  • Per-file coverage analysis
  • Uncovered code locations

Generate HTML Coverage Report

dotnet cake --target=Test-Coverage-Report

Opens a detailed HTML report at ./artifacts/coverage-report/index.html with:

  • Interactive file browser
  • Line-by-line coverage visualization
  • Coverage badges
  • Historical trends

Benchmarks

Performance benchmarks using BenchmarkDotNet to track and optimize critical operations:

Available Benchmarks

  • RoslynScriptingService - REPL execution performance
    • Simple expressions
    • Variable assignments
    • LINQ queries
    • Complex operations
  • CompilationService - Code compilation performance
    • Simple class compilation
    • Complex code compilation
    • Error handling
  • NuGetService - Package operations performance
    • Package search
    • Version lookup
    • README retrieval

Run Benchmarks

# Run all benchmarks (Release configuration)
dotnet cake --target=Benchmark

# Run specific benchmark
dotnet run --project tests/RoslynStone.Benchmarks --configuration Release -- --filter *RoslynScriptingService*

Results are saved to ./artifacts/benchmarks/ with:

  • Execution times (Min, Max, Mean, Median)
  • Memory allocations
  • Statistical analysis

See tests/RoslynStone.Benchmarks/README.md for detailed documentation.

Load Tests

Load tests validate the server can handle concurrent requests at scale:

Test Configuration

  • Concurrency: 300 concurrent requests per round
  • Rounds: 10 rounds per scenario
  • Scenarios: Expression evaluation, LINQ queries, NuGet search
  • Total Requests: 12,000 (300 × 10 × 4 scenarios)

Prerequisites

Start the server in HTTP mode:

cd src/RoslynStone.Api
MCP_TRANSPORT=http dotnet run

Run Load Tests

# Using Cake build script
dotnet cake --target=Load-Test

# Using dotnet CLI with custom configuration
dotnet run --project tests/RoslynStone.LoadTests -- http://localhost:7071 300 10

Arguments:

  1. Base URL (default: http://localhost:7071)
  2. Concurrency (default: 300)
  3. Rounds (default: 10)

Expected Results

A healthy server should achieve:

  • ✅ Success rate > 99%
  • ✅ Average response time < 100ms
  • ✅ Throughput > 1000 req/sec

See tests/RoslynStone.LoadTests/README.md for detailed documentation.

Continuous Integration

The CI pipeline runs on every push and pull request:

# Run full CI pipeline locally
dotnet cake --target=CI

CI includes:

  1. ✅ Code formatting check (CSharpier)
  2. ✅ Code quality analysis (ReSharper)
  3. ✅ Build verification
  4. ✅ Test execution with coverage
  5. ✅ Coverage threshold validation

Artifacts generated:

  • Test results (.trx files)
  • Coverage reports (Cobertura XML)
  • ReSharper inspection reports
  • Build logs

Project Structure

Core (Domain Layer)

  • Models: ExecutionResult, DocumentationInfo, CompilationError, PackageReference, PackageMetadata, PackageVersion, PackageSearchResult
  • Domain Types: Simple records and classes representing domain concepts

Infrastructure (Implementation Layer)

  • Tools: MCP tool implementations (ReplTools, NuGetTools) - Active operations
  • Resources: MCP resource implementations (DocumentationResource, NuGetSearchResource, NuGetPackageResource, ReplStateResource) - Passive data access
  • Services: RoslynScriptingService, DocumentationService, NuGetService, CompilationService, AssemblyExecutionService, ReplContextManager
  • Functional Helpers: Pure functions for diagnostics, transformations, and utilities

Api (Presentation Layer)

  • Program.cs: Host configuration with MCP server setup
  • Stdio Transport: JSON-RPC communication via stdin/stdout
  • HTTP Transport: HTTP/SSE communication for remote access
  • Logging: Configured to stderr to avoid protocol interference

Adding New MCP Tools

  1. Create tool method in Infrastructure/Tools with [McpServerTool] attribute
  2. Add to existing [McpServerToolType] class or create new one
  3. Use dependency injection for services (RoslynScriptingService, IReplContextManager, etc.)
  4. Include comprehensive XML documentation with <param> and <returns> tags
  5. Add [Description] attributes for MCP protocol metadata
  6. Tools are auto-discovered via WithToolsFromAssembly()

Example:

[McpServerToolType]
public class MyTools
{
    /// <summary>
    /// Execute custom operation
    /// </summary>
    /// <param name="service">Injected service</param>
    /// <param name="contextManager">Context manager for stateful operations</param>
    /// <param name="input">Input parameter</param>
    /// <param name="contextId">Optional context ID for session continuity</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>Result description</returns>
    [McpServerTool]
    [Description("Tool description for MCP")]
    public static async Task<object> MyTool(
        MyService service,
        IReplContextManager contextManager,
        [Description("Input description")] string input,
        [Description("Optional context ID from previous execution")] string? contextId = null,
        CancellationToken cancellationToken = default)
    {
        // Implementation
    }
}

Adding New MCP Resources

  1. Create resource class in Infrastructure/Resources implementing base resource patterns
  2. Add [McpServerResourceType] attribute to the class
  3. Implement URI parsing logic for your resource patterns
  4. Return structured data (not operations)
  5. Resources are auto-discovered via WithResourcesFromAssembly()

Example:

[McpServerResourceType]
public class MyDataResource
{
    /// <summary>
    /// Provides access to my data
    /// </summary>
    [McpServerResource("mydata://{id}")]
    [Description("Access my data by ID")]
    public static async Task<object> GetMyData(
        [Description("Data ID")] string id,
        MyDataService service,
        CancellationToken cancellationToken = default)
    {
        var data = await service.GetDataAsync(id, cancellationToken);
        return new { id, data };
    }
}

Testing and Debugging

MCP Inspector

The MCP Inspector is an interactive developer tool for testing and debugging MCP servers. It provides a web-based UI to explore available tools, test requests, and view responses in real-time.

Integrated with Aspire (Recommended)

When running with Aspire, the MCP Inspector is automatically started in development mode:

cd src/RoslynStone.AppHost
dotnet run

The inspector will be available at:

  • Inspector UI: http://localhost:6274 - Interactive web interface
  • Aspire Dashboard: http://localhost:18888 - Observability and logs

This provides a seamless development experience with both testing and observability in one place.

Standalone Inspector

To inspect the server without Aspire, use npx to run the inspector directly:

# From the repository root, run the compiled server through the inspector
npx @modelcontextprotocol/inspector dotnet run --project src/RoslynStone.Api/RoslynStone.Api.csproj

The inspector will start two services:

  • MCP Inspector UI at http://localhost:6274 - Interactive web interface
  • MCP Proxy at http://localhost:6277 - Protocol bridge

Using the Inspector

  1. Open http://localhost:6274 in your browser
  2. The server connection is automatically established
  3. Explore available tools in the left sidebar
  4. Test tools by clicking them and providing parameters
  5. View responses, including return values and output
  6. Export server configuration for Claude Desktop or other clients

Inspecting with Environment Variables

Pass environment variables to configure the server:

npx @modelcontextprotocol/inspector \
  -e DOTNET_ENVIRONMENT=Development \
  -e OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
  dotnet run --project src/RoslynStone.Api/RoslynStone.Api.csproj

Inspecting the Container

You can also inspect the containerized version:

# Inspect the container image
npx @modelcontextprotocol/inspector docker run -i --rm ghcr.io/dylanlangston/roslyn-stone:latest

Custom Ports

If you need to use different ports:

CLIENT_PORT=8080 SERVER_PORT=9000 npx @modelcontextprotocol/inspector \
  dotnet run --project src/RoslynStone.Api/RoslynStone.Api.csproj

Exporting Configuration

The inspector provides buttons to export server configurations:

  • Server Entry: Copies the launch configuration to clipboard for use in mcp.json
  • Compatible with Claude Desktop, Cursor, Claude Code, and other MCP clients

Example exported configuration:

{
  "command": "dotnet",
  "args": ["run", "--project", "/path/to/Roslyn-Stone/src/RoslynStone.Api/RoslynStone.Api.csproj"],
  "env": {
    "DOTNET_ENVIRONMENT": "Development"
  }
}

For more details, see the MCP Inspector documentation.

Additional Resources