Skip to content

Commit c4db428

Browse files
Copilotstephentoub
andcommitted
Refocus instructions on library implementation and architecture
Co-authored-by: stephentoub <[email protected]>
1 parent 780e1a9 commit c4db428

File tree

1 file changed

+114
-28
lines changed

1 file changed

+114
-28
lines changed

.github/copilot-instructions.md

Lines changed: 114 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@ The SDK consists of three main packages:
3636
- Support both builder patterns and options configuration
3737

3838
### JSON Serialization
39-
- Use `System.Text.Json` for all JSON operations
40-
- Use `McpJsonUtilities.DefaultOptions` for consistent serialization
41-
- Support source generation for Native AOT compatibility
42-
- Set `JsonIgnoreCondition.WhenWritingNull` for optional properties
39+
- Use `System.Text.Json` exclusively for all JSON operations
40+
- Use `McpJsonUtilities.DefaultOptions` for consistent serialization settings across the SDK
41+
- Support source generation for Native AOT compatibility via `McpJsonUtilities` source generators
42+
- Set `JsonIgnoreCondition.WhenWritingNull` for optional properties to minimize payload size
43+
- Use `JsonSerializerDefaults.Web` for camelCase property naming
44+
- Protocol types are decorated with `[JsonSerializable]` attributes for AOT support
45+
- Custom converters: `CustomizableJsonStringEnumConverter` for flexible enum serialization
4346

4447
### Async Patterns
4548
- All I/O operations should be async
@@ -53,18 +56,38 @@ The SDK consists of three main packages:
5356
- Support all standard MCP capabilities (e.g. tools, prompts, resources, sampling)
5457
- Implement proper error handling with `McpException` and `McpErrorCode`
5558

59+
### Error Handling
60+
- Throw `McpException` for MCP protocol-level errors with appropriate `McpErrorCode`
61+
- Use standard error codes: `InvalidRequest`, `MethodNotFound`, `InvalidParams`, `InternalError`
62+
- Let domain exceptions bubble up and convert to `InternalError` at transport boundary
63+
- Include detailed error messages in exception `Message` property for debugging
64+
- Errors are automatically converted to JSON-RPC error responses by the server infrastructure
65+
5666
## Testing
5767

5868
### Test Organization
59-
- Unit tests in `tests/ModelContextProtocol.Tests`
60-
- Integration tests in `tests/ModelContextProtocol.AspNetCore.Tests`
61-
- Test helpers in `tests/Common`
62-
- Filter manual tests with `[Trait("Execution", "Manual")]`
63-
64-
### Test Infrastructure
65-
- Use xUnit for all tests
69+
- Unit tests in `tests/ModelContextProtocol.Tests` for core functionality
70+
- Integration tests in `tests/ModelContextProtocol.AspNetCore.Tests` for HTTP/SSE transports
71+
- Shared test utilities in `tests/Common/Utils/`
72+
- Test servers in `tests/ModelContextProtocol.Test*Server/` for integration scenarios
73+
- Filter manual tests with `[Trait("Execution", "Manual")]` - these require external dependencies
74+
75+
### Test Infrastructure and Helpers
76+
- **LoggedTest**: Base class for tests that need logging output captured to xUnit test output
77+
- Provides `ILoggerFactory` and `ITestOutputHelper` for test logging
78+
- Use when debugging or when tests need to verify log output
79+
- **TestServerTransport**: In-memory transport for testing client-server interactions without network I/O
80+
- **MockLoggerProvider**: For capturing and asserting on log messages
81+
- **XunitLoggerProvider**: Routes `ILogger` output to xUnit's `ITestOutputHelper`
82+
- **KestrelInMemoryTransport** (AspNetCore.Tests): In-memory Kestrel connection for HTTP transport testing without network stack
83+
84+
### Test Best Practices
85+
- Inherit from `LoggedTest` for tests needing logging infrastructure
86+
- Use `TestServerTransport` for in-memory client-server testing
87+
- Mock external dependencies (filesystem, HTTP clients) rather than calling real services
88+
- Use `CancellationTokenSource` with timeouts to prevent hanging tests
89+
- Dispose resources properly (servers, clients, transports) using `IDisposable` or `await using`
6690
- Run tests with: `dotnet test --filter '(Execution!=Manual)'`
67-
- Tests should be isolated and not depend on external services (except manual tests)
6891

6992
## Build and Development
7093

@@ -75,8 +98,8 @@ The SDK consists of three main packages:
7598
- **Clean**: `dotnet clean` or `make clean`
7699

77100
### SDK Requirements
78-
- The project uses .NET SDK preview versions
79-
- Target frameworks: .NET 8.0, .NET 9.0, .NET Standard 2.0
101+
- The project currently uses .NET SDK 10.0 RC (this is temporary while waiting for .NET 10 to go GA)
102+
- Target frameworks: .NET 10.0, .NET 9.0, .NET 8.0, .NET Standard 2.0
80103
- Support Native AOT compilation
81104

82105
### Project Structure
@@ -86,10 +109,40 @@ The SDK consists of three main packages:
86109
- Documentation: `docs/`
87110
- Build artifacts: `artifacts/` (not committed)
88111

89-
## Common Patterns
90-
91-
### MCP Server Tools
92-
Tools are exposed using attributes:
112+
## Architecture and Design Patterns
113+
114+
### Server Implementation Architecture
115+
- **McpServer** is the core server implementation in `ModelContextProtocol.Core/Server/`
116+
- **IMcpServerBuilder** pattern provides fluent API for configuring servers via DI
117+
- Server primitives (tools, prompts, resources) are discovered via reflection using attributes
118+
- Support both attribute-based registration (`WithTools<T>()`) and instance-based (`WithTools(target)`)
119+
- Use `McpServerFactory` to create server instances with configured options
120+
121+
### Tool/Prompt/Resource Discovery
122+
- Tools, prompts, and resources use attribute-based discovery: `[McpServerTool]`, `[McpServerPrompt]`, `[McpServerResource]`
123+
- Type-level attributes (`[McpServerToolType]`, etc.) mark classes containing server primitives
124+
- Discovery supports both static and instance methods (public and non-public)
125+
- For Native AOT compatibility, use generic `WithTools<T>()` methods instead of reflection-based variants
126+
- `AIFunctionMcpServerTool`, `AIFunctionMcpServerPrompt`, and `AIFunctionMcpServerResource` wrap `AIFunction` for integration with Microsoft.Extensions.AI
127+
128+
### Request Processing Pipeline
129+
- Requests flow through `McpServer.Methods.cs` which handles JSON-RPC message routing
130+
- Use `McpRequestFilter` for cross-cutting concerns (logging, auth, validation)
131+
- `RequestContext` provides access to current request state and services
132+
- `RequestServiceProvider` enables scoped dependency injection per request
133+
- Filters can short-circuit request processing or transform requests/responses
134+
135+
### Transport Layer Abstraction
136+
- Transport implementations handle message serialization and connection management
137+
- Core transports: `StdioServerTransport`, `StreamServerTransport`, `SseResponseStreamTransport`, `StreamableHttpServerTransport`
138+
- Transports must implement bidirectional JSON-RPC message exchange
139+
- SSE (Server-Sent Events) transport for unidirectional server→client streaming
140+
- Streamable HTTP for request/response with streamed progress updates
141+
142+
## Implementation Patterns
143+
144+
### Tool Implementation
145+
Tools are methods marked with `[McpServerTool]`:
93146
```csharp
94147
[McpServerToolType]
95148
public class MyTools
@@ -99,13 +152,18 @@ public class MyTools
99152
[Description("Parameter description")] string param,
100153
CancellationToken cancellationToken)
101154
{
102-
// Implementation
155+
// Implementation - use Description attributes for parameter documentation
156+
// Return string, TextContent, ImageContent, EmbeddedResource, or arrays of these
103157
}
104158
}
105159
```
160+
- Tools support dependency injection in constructors for instance methods
161+
- Parameters are automatically deserialized from JSON using `System.Text.Json`
162+
- Use `[Description]` attributes on parameters to generate tool schemas
163+
- Return types: `string`, `TextContent`, `ImageContent`, `EmbeddedResource`, or collections of content types
106164

107-
### MCP Server Prompts
108-
Prompts are exposed similarly:
165+
### Prompt Implementation
166+
Prompts return `ChatMessage` or arrays thereof:
109167
```csharp
110168
[McpServerPromptType]
111169
public static class MyPrompts
@@ -115,17 +173,45 @@ public static class MyPrompts
115173
new(ChatRole.User, $"Prompt template: {content}");
116174
}
117175
```
176+
- Prompts can accept arguments to customize generated messages
177+
- Return single `ChatMessage` or `ChatMessage[]` for multi-turn prompts
178+
- Use `ChatRole.User`, `ChatRole.Assistant`, or `ChatRole.System` appropriately
118179

119-
### Client Usage
180+
### Resource Implementation
181+
Resources provide access to data with URI templates:
120182
```csharp
121-
var client = await McpClient.CreateAsync(
122-
new StdioClientTransport(new() { Command = "...", Arguments = [...] }),
123-
clientOptions: new() { /* ... */ },
124-
loggerFactory: loggerFactory);
183+
[McpServerResourceType]
184+
public class MyResources
185+
{
186+
[McpServerResource("file:///{path}"), Description("Reads file content")]
187+
public static async Task<string> ReadFile(string path, CancellationToken cancellationToken)
188+
{
189+
// Resource URI matching uses UriTemplate syntax
190+
// Extract parameters from URI and return content
191+
}
192+
}
193+
```
194+
- Use URI templates to define resource paths with parameters
195+
- Resources support subscription for dynamic content updates
196+
- Return content types similar to tools
125197

126-
var tools = await client.ListToolsAsync();
127-
var result = await client.CallToolAsync("tool-name", arguments, cancellationToken);
198+
### Filters and Middleware
199+
Implement `McpRequestFilter` for request/response interception:
200+
```csharp
201+
public class LoggingFilter : McpRequestFilter
202+
{
203+
public override async ValueTask InvokeAsync(RequestContext context, Func<ValueTask> next)
204+
{
205+
// Pre-processing
206+
await next(); // Call next filter or handler
207+
// Post-processing
208+
}
209+
}
128210
```
211+
- Filters execute in registration order
212+
- Can short-circuit by not calling `next()`
213+
- Access request context, services, and can modify responses
214+
- Use for cross-cutting concerns: logging, auth, validation, caching
129215

130216
## OpenTelemetry Integration
131217

0 commit comments

Comments
 (0)