Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteSome links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Build it as two protocol adapters around one language-service core. Let an LSP endpoint handle editor state—documents, versions, diagnostics, completion and navigation—while an MCP server exposes narrowly scoped tools and resources to an AI host. Keep parsing, indexing, configuration and cancellation in shared services, then choose stdio for a local process or HTTP for a remotely hosted service. This separation prevents editor lifecycle rules from leaking into model-facing tools and lets one implementation support both deployments.
The architecture that keeps LSP and MCP maintainable
LSP and MCP solve different problems. The Language Server Protocol carries editor requests and notifications such as document changes, diagnostics, hover and definitions. The Model Context Protocol standardizes how an AI application obtains context and invokes external tools. Do not treat MCP as a replacement for LSP.
A practical topology is:
Editor ⇄ LSP JSON-RPC ⇄ C# language-service core ⇄ MCP adapter ⇄ MCP host/model
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →The core owns source text, document versions, parsing, semantic analysis, project configuration, workspace indexing and cancellation. The LSP adapter owns editor-facing protocol types and lifecycle. The MCP adapter translates safe language-workflow operations into tools or resources. The official C# SDK is intended for .NET applications, services and libraries that implement or interact with MCP clients and servers; its client/server transport model supports this adapter approach.
#1 Best Overall
Choose the C# SDK package
Start with the package that matches the process you are shipping. Package maturity and prerelease flags can change, so check the current release channel before pinning a command in automation.
| Package | Use it for | Typical choice |
|---|---|---|
ModelContextProtocol.Core |
Low-level APIs or a client with minimum dependencies | Custom hosting, protocol plumbing, or client-only applications |
ModelContextProtocol |
Hosted clients and local stdio servers, including dependency injection and attribute-based discovery | Most new C# MCP servers |
ModelContextProtocol.AspNetCore |
HTTP-based MCP servers | ASP.NET Core hosting, authentication and remote deployment |
The normal starting point for a local server is ModelContextProtocol. The ASP.NET Core package references it and adds the HTTP hosting path. Microsoft’s getting-started material has shown installation with dotnet add package ModelContextProtocol --prerelease; use the flag only when the release you have selected requires it.
Create the solution and shared services
-
Create a solution with separate projects so protocol code does not become entangled with analysis code:
Free tools Windows power users keep installed
One-click scans. No signup required.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.dotnet new sln -n CSharpMcpLanguageServer dotnet new classlib -n LanguageService.Core dotnet new console -n LanguageMcp.Stdio dotnet sln add LanguageService.Core/LanguageService.Core.csproj dotnet sln add LanguageMcp.Stdio/LanguageMcp.Stdio.csproj dotnet add LanguageMcp.Stdio reference LanguageService.Core -
Add the MCP package to the stdio host. Confirm the current stable or prerelease channel first:
dotnet add LanguageMcp.Stdio package ModelContextProtocol -
Keep the core independent of transport. A minimal shape is:
Rank #2
namespace LanguageService.Core; public sealed record TextDocument(string Uri, int Version, string Text); public sealed class WorkspaceIndex { private readonly object gate = new(); private readonly Dictionary<string, TextDocument> documents = new(); public void OpenOrUpdate(TextDocument document) { lock (gate) { if (documents.TryGetValue(document.Uri, out var old) && document.Version <= old.Version) return; // Ignore an out-of-order notification. documents[document.Uri] = document; } } public bool TryGet(string uri, out TextDocument? document) { lock (gate) return documents.TryGetValue(uri, out document); } public IReadOnlyList<TextDocument> Snapshot() { lock (gate) return documents.Values.ToArray(); } }
In production, replace the dictionary with a workspace model that tracks projects, files, references and an incrementally updated symbol index. The important invariant is that a background analysis result may be applied only if it still corresponds to the document version that triggered it.
Host a local MCP server over stdio
The following host uses the SDK’s dependency injection and attribute discovery. It is a complete starting point for a local MCP process launched by an editor or AI client:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Server;
using LanguageService.Core;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddSingleton<WorkspaceIndex>();
builder.Services
.AddMcpServer()
.WithStdioServerTransport()
.WithToolsFromAssembly();
await builder.Build().RunAsync();
Define tools in the same assembly (or register the assembly that contains them). Keep every operation bounded by an explicitly configured workspace root:
using ModelContextProtocol.Server;
using LanguageService.Core;
[McpServerToolType]
public static class LanguageTools
{
[McpServerTool, Description("Return a short list of symbols matching a name in the configured workspace.")]
public static object[] FindSymbols(
WorkspaceIndex index,
[Description("Exact or partial symbol name")] string name,
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return index.Snapshot()
.Where(d => d.Text.Contains(name, StringComparison.OrdinalIgnoreCase))
.Select(d => new { uri = d.Uri, version = d.Version })
.Cast<object>()
.Take(100)
.ToArray();
}
}
The example deliberately returns a small, structured result rather than raw filesystem access. A real implementation should parse syntax trees, return symbol names and ranges, validate all arguments and reject paths outside the workspace.
Implement the LSP endpoint as a separate adapter
Use a maintained C# LSP library for JSON-RPC framing and protocol types rather than hand-writing every message. The LSP literature recommends delegating protocol details to an SDK where practical. Your handlers should map protocol events to the shared core:
- initialize: advertise only the capabilities you implement and record the client’s root and settings.
- initialized: start workspace discovery and publish progress if the client supports it.
- textDocument/didOpen: insert the complete text and version into the core.
- textDocument/didChange: apply ordered edits, reject or resynchronize stale versions, then schedule cancellable analysis.
- textDocument/didClose: release unsaved buffers while retaining files that remain part of the workspace.
- textDocument/publishDiagnostics: publish diagnostics tagged with the analyzed document version when the client supports versioned reports.
- completion, hover, definition, references and document symbols: query immutable snapshots of the index so a concurrent edit cannot mutate a response halfway through serialization.
- shutdown and exit: stop new work, cancel analysis, flush diagnostics and close transport in the order required by the LSP client.
Do not call MCP tools from an LSP handler merely to reuse code. Call the same core service directly. MCP calls can be slower, have different authorization, and may be unavailable when the editor is offline.
Implement MCP initialization before tools
MCP clients and servers negotiate capabilities during initialization. Follow this sequence before exposing useful operations:
- Accept the client’s initialize request and validate the protocol version you support.
- Return server information and only the capabilities that are actually enabled, such as tools, resources, prompts or completion.
- Wait for the client’s initialized notification before serving normal discovery traffic.
- Implement ping and return promptly so hosts can detect a dead process.
- Add cancellation tokens to parsing, indexing and every MCP operation that can exceed a few milliseconds.
- Report progress for indexing or large workspace queries when the negotiated capability permits it.
- Add task handling only when an operation genuinely needs multiple round trips; define polling, completion and failure states explicitly.
Capability negotiation, stdio, Streamable HTTP and SSE transports, ping, progress, cancellation and tasks are described in the MCP conceptual documentation. Treat the negotiated capabilities as a runtime contract: never send a notification or result shape that the client did not agree to receive.
Synchronize documents without race conditions
Version every buffer
Store the editor-provided integer version with each open document. A change whose base version is older than the stored version must not overwrite newer text. If edits arrive out of order, request a full resynchronization through the LSP mechanism supported by your client or mark the document temporarily unavailable for analysis.
Cancel obsolete analysis
Associate a CancellationTokenSource with each document’s pending analysis. Cancel it when a newer change arrives. Before publishing diagnostics or updating the symbol index, compare the result’s source version with the current version. This prevents a slow parse from replacing a newer, correct result.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Rank #4
Separate snapshots from mutable state
Build an immutable snapshot for completion, hover and navigation. Readers then see a consistent project graph while a writer updates the index. Use bounded queues for file watching and indexing; otherwise a generated-code directory can consume all memory and starve interactive requests.
Choose stdio or HTTP
| Decision | stdio | HTTP |
|---|---|---|
| Best fit | Local editor or AI client launches and supervises one process | Shared, remote or centrally managed service |
| Operational model | Process lifetime usually follows the client | Independent service with routing, authentication and deployment concerns |
| State | Easy to keep workspace state in memory for one client | Choose explicitly between per-session state and stateless workers |
| Failure handling | Restart the child process and rebuild its index | Use timeouts, retries and health checks without duplicating non-idempotent work |
| Security | OS process permissions and workspace configuration | Authentication, authorization, TLS and tenant isolation |
For a local language server, start with stdio. For a remotely reachable MCP endpoint, use ModelContextProtocol.AspNetCore and keep workspace identity in authenticated request context rather than trusting a path supplied by a model.
The SDK v2.0 announcement dated 2026-07-28 describes implementation of the 2026-07-28 MCP revision, including HTTP being stateless by default, a standardized HTTP surface and multi-round-trip requests. Re-check those semantics when designing session state, load balancing, authentication and retry behavior; do not assume an older stateful HTTP example still applies.
Security boundaries for model-facing tools
- Resolve every path against an allow-listed workspace root and reject traversal, symlink escapes and drive changes.
- Prefer read-only symbol, diagnostics and metadata tools. Put mutations behind separate, explicit tools with confirmation requirements.
- Validate lengths, selectors, project names and query limits before invoking the parser or filesystem.
- Never expose an unrestricted shell, process launcher or arbitrary file-write tool merely because the language server can access those APIs.
- Return structured errors that identify invalid arguments without disclosing secrets, environment variables or unrelated workspace files.
- Log authorization decisions and request identifiers, but send logs to stderr when using stdio so stdout remains protocol-clean.
Test both protocols before release
Unit-test the core with version races and cancellation, then test each adapter against a real JSON-RPC client. Your minimum matrix should include:
- Correct framing for every request, notification and response, including Unicode and large payloads.
- Malformed JSON, unknown methods, missing fields and invalid capability declarations.
- Initialize, initialized, ping, shutdown and process-exit behavior.
- Out-of-order document versions, overlapping edits and a slow analysis canceled by a newer edit.
- Diagnostics, completion, hover, definitions, references and empty-workspace responses.
- MCP tool and resource discovery, invalid arguments, cancellation, progress and task polling where implemented.
- Client disconnects, stdio restarts, HTTP timeouts, reconnects and duplicate requests.
- Workspace-boundary violations and authorization failures for every tool that accepts a URI or path.
Run editor-to-model end-to-end tests after the adapter tests. The LSP and MCP implementations can each pass isolated tests while their shared index still publishes stale data or leaks a workspace between sessions.
Best Value
Performance, reliability and cost considerations
Keep interactive work bounded
Completion and hover should use an already-built snapshot. Schedule full indexing in the background, cap concurrent parses and return partial results only when the client understands them. Cache syntax trees by document version and invalidate dependent projects when references change.
Make retries safe
Read-only tools can usually be retried after a transport failure. A mutation must carry an idempotency key or be rejected on retry, otherwise an AI host may apply it twice. For HTTP, include request correlation IDs and enforce per-tenant timeouts.
Control resource growth
Limit open-document size, symbol-result count, queued files and task retention. Dispose cancellation sources and file watchers on shutdown. Measure parse latency, index queue depth, MCP request duration and cancellation rate; the protocol specifications do not provide a universal performance target, so establish budgets for your own workspace sizes.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteTroubleshooting common failures
| Symptom | Likely cause | Fix |
|---|---|---|
| The client reports invalid JSON immediately | Diagnostic text was written to stdout in a stdio server | Send logs to stderr and reserve stdout for MCP framing. |
| Tools do not appear after initialization | Tool attributes were not discovered or the capability was not advertised | Call the assembly-discovery registration, verify the tool type is public, and inspect the initialize result. |
| Diagnostics revert after typing | A slower analysis published a stale version | Attach the source version to each job and discard results that are no longer current. |
| HTTP clients lose context between requests | The service assumed stateful sessions while the selected MCP HTTP revision is stateless by default | Persist required state in an authenticated session store or design every request to carry its context. |
| Cancellation has no effect | The token is not passed into parser, indexer or downstream MCP calls | Thread the token through every async method and check it before expensive loops and publication. |
| A tool can read files outside the project | URI normalization occurs after authorization or symlinks are ignored | Canonicalize first, enforce the allow-list, then open the file using the validated path. |
| The server hangs during shutdown | Background watchers or tasks keep the host alive | Cancel hosted services, await their completion and close the transport after pending responses finish. |
Or skip the browser setup
If your workflow also needs reliable screenshots of documentation, test pages or generated UI, ScreenshotNeo provides a one-request website screenshot API and MCP server. It removes cookie and consent banners, newsletter popups and chat widgets before capture; bot checks, blank pages, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status. AI agents can call its take_screenshot, get_page_info and capture_pdf tools through MCP.
Use the API documentation at https://screenshotneo.com/docs/ for the full option set. A basic call is:
curl -G 'https://api.screenshotneo.com/v1/shot' -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Equivalent clients:
import requests
r = requests.get('https://api.screenshotneo.com/v1/shot', params={'access_key': 'YOUR_API_KEY', 'url': 'https://stripe.com'}, timeout=90)
open('shot.webp', 'wb').write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
There is a free allowance of 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Frequently Asked Questions
Where should protocol logs go when the server uses stdio?
Write diagnostics to stderr or a file. Stdout is reserved exclusively for protocol messages, so even one startup banner can corrupt framing.
When is a separate MCP process preferable to an in-process adapter?
Use a separate process when you need independent restarts, stronger permission boundaries or different release cycles. An in-process adapter is simpler when the editor host already controls the same workspace and failure domain.
How should an MCP tool report a canceled operation?
Honor the cancellation token, stop work promptly and return the SDK’s structured cancellation/error result rather than emitting a partial success that the client may treat as complete.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

