Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 15 additions & 45 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
# Copilot Instructions — McpServer

**Agent Identity:** When posting to the MCP session log, use `sourceType: copilotcli`.
**Agent Identity:** When posting to the MCP session log, use `sourceType: copilotcli`.
For specific operational instructions (session bootstrap, turn logging lifecycle, helper command order), follow `AGENTS-README-FIRST.yaml`.

## Response Formatting

- Do not use table-style output in responses.
- Use concise bullets or short paragraphs instead.

## Terminal Usage

- Do NOT set focus to the terminal window.
- Do NOT write multiline commands to the terminal; use temporary scripts instead.
- Always use non-login pwsh and PowerShell commands.

## Session Logging Requirements

- Follow `AGENTS-README-FIRST.yaml` for workflow and helper command order.
- Persist session log changes immediately after each meaningful update; do not batch unsaved turn changes.
- For each turn, include as much detail as available: interpretation, response/status, actions (type/status/filePath), files modified, design decisions, requirements discovered, blockers, and context references.

## Build, Test, Lint

```powershell
Expand Down Expand Up @@ -54,51 +67,8 @@ pwsh ./scripts/Validate-McpConfig.ps1

### XML Documentation Required

`TreatWarningsAsErrors` and `GenerateDocumentationFile` are enabled globally in `Directory.Build.props`. All public types and members must have XML doc comments or the build fails (CS1591). Use `/// <inheritdoc />` for interface implementations. Test projects are exempt.
`TreatWarningsAsErrors` and `GenerateDocumentationFile` are enabled globally in `Directory.Build.props`. All public types and members must have XML doc comments or the build fails (CS1591). Use `/// <inheritdoc />` for interface implementations. Test projects are not exempt: test classes and test methods must include XML docs that state what is being tested, what data/fixtures are used, why that data/fixtures are used, and which requirement IDs are validated.

### Requirement Traceability Comments

All source files reference their FR/TR requirement IDs in doc comments (e.g., `/// <summary>TR-PLANNED-013: Constructor.</summary>`). When adding new functionality, reference the relevant requirement ID from `docs/Project/Functional-Requirements.md` and `docs/Project/Technical-Requirements.md`.

### DRY — No Duplication (TR-MCP-DRY-001)

Shared logic must be extracted to a single reusable location. No copy-pasted logic across files or scripts. See `docs/Project/Technical-Requirements.md` § TR-MCP-DRY-001.

### Async Patterns

All async methods use `.ConfigureAwait(false)`. Controllers and services accept `CancellationToken` parameters.

### Testing

- **Framework**: xUnit v3 with NSubstitute for mocking.
- **Integration tests** are isolated in `McpServer.Support.Mcp.IntegrationTests`; they use `CustomWebApplicationFactory` (sets environment to `"Test"`, uses EF in-memory database).
- **Unit tests** live in `*Tests` projects; they use temp files or in-memory state; always clean up in `Dispose`.
- Test projects have `InternalsVisibleTo` access to the main project.

### Controller Patterns

Controllers are `sealed`, use `[ApiController]` + `[Route("mcpserver/...")]`. Mutating endpoints return `TodoMutationResult`-style result objects. Not-found returns 404 with the result; validation errors return 400/409.

### Service Registration

Services follow interface + implementation pairs (`ITodoService`/`TodoService`). Strategy-pattern switching (TODO storage, tunnel providers) is done via factory delegates in `Program.cs` using `ActivatorUtilities.CreateInstance`.

### API Key Auth

`[ApiKeyAuthFilter]` protects mutating endpoints; `[SkipApiKeyAuth]` bypasses for read-only endpoints. When `Mcp:ApiKey` is empty, all requests pass (open mode).

### Marker File

On workspace start, `MarkerFileService` writes `AGENTS-README-FIRST.yaml` to the workspace root with port, endpoints, and connection prompt. Removed on stop. This is how AI agents discover the running server.

### Configuration Hierarchy

`PORT` env var → `Mcp:Instances:{name}:Port` → `Mcp:Port` → default 7147. Instance-level config always overrides base-level for all `Mcp:*` keys.

### Central Package Management

Package versions are managed in `Directory.Packages.props`. Project files use `<PackageReference Include="..." />` without version attributes.

### Logging

Serilog with console + optional Parseable HTTP sink + file fallback. Configuration in `Mcp:Parseable` section.
103 changes: 25 additions & 78 deletions .github/workflows/mcp-server-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,26 +108,14 @@ jobs:
Write-Host "PackageVersion: $version"
"version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8NoBOM -Append

- name: Publish MCP Server
run: dotnet publish src/McpServer.Support.Mcp/McpServer.Support.Mcp.csproj -c Release -o artifacts/mcp-server

- name: Build Director tool
run: dotnet build src/McpServer.Director/McpServer.Director.csproj -c Release

- name: Pack Director tool
run: dotnet pack src/McpServer.Director/McpServer.Director.csproj -c Release --no-build -p:PackageVersion=${{ steps.version.outputs.version }} -o artifacts/director-tool

- name: Upload MCP publish artifact
uses: actions/upload-artifact@v4
with:
name: mcp-server-publish
path: artifacts/mcp-server

- name: Upload Director tool package artifact
uses: actions/upload-artifact@v4
with:
name: director-tool-nupkg
path: artifacts/director-tool/*.nupkg
- name: Publish MCP Server
run: dotnet publish src/McpServer.Support.Mcp/McpServer.Support.Mcp.csproj -c Release -o artifacts/mcp-server

- name: Upload MCP publish artifact
uses: actions/upload-artifact@v4
with:
name: mcp-server-publish
path: artifacts/mcp-server

- name: Upload test results
if: always()
Expand Down Expand Up @@ -212,46 +200,10 @@ jobs:
if: always()
run: docker stop mcp-ci && docker rm mcp-ci || true

publish-web-ui-docker:
runs-on: ubuntu-latest
needs: [build-test-publish, docker-smoke]
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository_owner }}/mcpserver-web
tags: |
type=ref,event=branch
type=sha
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push web UI image
uses: docker/build-push-action@v6
with:
context: .
file: src/McpServer.Web/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

release-main:
runs-on: ubuntu-latest
needs: [windows-msix, multi-instance-smoke, docker-smoke]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
release-main:
runs-on: ubuntu-latest
needs: [windows-msix, multi-instance-smoke, docker-smoke]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Download MSIX artifact
uses: actions/download-artifact@v4
Expand Down Expand Up @@ -279,12 +231,13 @@ jobs:
docs/**/*.md
README.md

- name: Link check
uses: lycheeverse/lychee-action@v2
with:
args: --verbose --no-progress docs README.md
fail: true
failIfEmpty: false
- name: Link check
continue-on-error: true
uses: lycheeverse/lychee-action@v2
with:
args: --verbose --no-progress docs README.md
fail: false
failIfEmpty: false

docs-build:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -349,18 +302,12 @@ jobs:
with:
global-json-file: global.json

- name: Pack
run: dotnet pack src/McpServer.Client/McpServer.Client.csproj -c Release -p:PackageVersion=${{ needs.build-test-publish.outputs.package_version }} -o ./nupkg

- name: Download Director tool package artifact
uses: actions/download-artifact@v4
with:
name: director-tool-nupkg
path: nupkg

- name: Push to NuGet (main only)
if: github.ref == 'refs/heads/main'
run: dotnet nuget push ./nupkg/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate
- name: Pack
run: dotnet pack src/McpServer.Client/McpServer.Client.csproj -c Release -p:PackageVersion=${{ needs.build-test-publish.outputs.package_version }} -o ./nupkg

- name: Push to NuGet (main only)
if: github.ref == 'refs/heads/main'
run: dotnet nuget push ./nupkg/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate

- name: Push to GitHub Packages (non-main)
if: github.ref != 'refs/heads/main'
Expand Down
14 changes: 12 additions & 2 deletions .markdownlint-cli2.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
config:
MD013: false
config:
MD001: false
MD012: false
MD013: false
MD022: false
MD031: false
MD032: false
MD033: false
MD034: false
MD040: false
MD042: false
MD060: false
84 changes: 40 additions & 44 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
# Agent Instructions

## Session Start

1. Read `AGENTS-README-FIRST.yaml` in the repo root for the current API key and endpoints.
2. Verify the MCP server is running: `GET /health`.
3. Bootstrap helper modules from the Tool Registry (see `docs/context/module-bootstrap.md`).
4. Review recent session history: `Get-McpSessionLog -Limit 5` or `mcp_session_query 5`.
5. Review current tasks: `Get-McpTodo` or `mcp_todo_list`.
6. Post a session log entry before starting work on the user's request.

On every subsequent user message:

1. Post a session log entry before starting work.
2. Complete the user's request.
3. Update the entry with results, actions taken, and files modified.

## Rules

1. Post a session log entry before any work on a user request. Update it with results when done.
2. Use helper modules for session log and TODO operations. Do not make raw API calls — the modules handle workspace routing automatically.
3. Write decisions, requirements, and state to the session log, not just conversation.
4. Follow workspace conventions in `.github/copilot-instructions.md` for build, test, and architecture guidance.
5. When you need API schemas, module examples, or compliance rules, load them from `docs/context/` or use `context_search`.
6. Do not fabricate information. If you made a mistake, acknowledge it. Distinguish facts from speculation.
7. Prioritize correctness over speed. Do not ship code you have not verified compiles and is logically sound.
## Session Start

1. Read `AGENTS-README-FIRST.yaml` in the repo root for the current API key and endpoints.
2. For specific operational steps (session bootstrap, session log turn workflow, and helper command sequence), follow `AGENTS-README-FIRST.yaml`.

On every subsequent user message:

1. Follow `AGENTS-README-FIRST.yaml` for specific operational instructions.
2. Complete the user's request.

## Rules

1. `templates/prompt-templates.yaml` (`default-marker-prompt`) is the source of truth for specific agent instructions. `AGENTS-README-FIRST.yaml` is the rendered runtime instruction set.
2. Keep this file focused on durable workspace policy and conventions; avoid duplicating marker-file operational procedures.
3. Use helper modules for session log and TODO operations. Do not make raw API calls.
4. Persist session log updates immediately after each meaningful change (turn creation, action append, decision, requirement, blocker, file/context update). Do not defer saves.
5. Capture rich turn detail: interpretation, response, status, actions (type/status/filePath), contextList, filesModified, designDecisions, requirementsDiscovered, blockers, and relevant processing dialog.
6. Follow workspace conventions in `.github/copilot-instructions.md` for build, test, and architecture guidance.
7. When you need API schemas, module examples, or compliance rules, load them from `docs/context/` or use `context_search`.
8. Do not fabricate information. If you made a mistake, acknowledge it. Distinguish facts from speculation.
9. Prioritize correctness over speed. Do not ship code you have not verified compiles and is logically sound.

## Where Things Live

Expand Down Expand Up @@ -75,9 +72,9 @@ You represent the workspace owner. Your work directly reflects the owner's profe

### Source Attribution

- Document all web sources in the session log as actions with type "web_reference" (URL, title, usage).
- Add source URLs to the entry's contextList array.
- Attribute external code in both the session log and code comments.
- Document all web sources in the session log as actions with type "web_reference" (URL, title, usage).
- Add source URLs to the turn's contextList array.
- Attribute external code in both the session log and code comments.

## Requirements Tracking

Expand All @@ -89,33 +86,31 @@ When you discover or agree on new requirements during a session:
- `TR-per-FR-Mapping.md` — append mapping rows
- `Requirements-Matrix.md` — append status rows
- `Testing-Requirements.md` — append TEST-MCP-* entries
2. Include the requirement ID in your session log entry's tags.
2. Include the requirement ID in your session log turn's tags.
3. Capture requirements as they emerge. Do not defer to later.

## Design Decision Logging

When a design decision is made:

1. Log it as a session log dialog entry with category "decision".
1. Log it as a session log dialog item with category "decision".
2. Include: the decision, alternatives considered, rationale, and affected requirements.
3. Add a session log action with type "design_decision".
4. If the decision affects existing code or requirements, note what needs updating.

## Session Continuity

At the start of every session:

1. Read `AGENTS-README-FIRST.yaml` for connection details.
2. Query recent session logs (limit 5) for context.
3. Query current TODOs.
4. Read `docs/Project/Requirements-Matrix.md` to understand project state.
5. If resuming interrupted work, review the last session's pending decisions.

At regular intervals during long sessions (~10 interactions):

1. Push an updated session log with all entries so far.
2. Ensure all design decisions are captured.
3. Verify requirements docs are up to date.
## Session Continuity

At the start of every session:

1. Follow the session-start checklist in `AGENTS-README-FIRST.yaml`.
2. Read `docs/Project/Requirements-Matrix.md` to understand project state.
3. If resuming interrupted work, review the last session's pending decisions.

At regular intervals during long sessions (~10 interactions):

1. Follow marker-file update cadence and session logging requirements from `AGENTS-README-FIRST.yaml`.
2. Ensure all design decisions are captured.
3. Verify requirements docs are up to date.

## Glossary

Expand All @@ -132,3 +127,4 @@ At regular intervals during long sessions (~10 interactions):

- Do not use table-style output in responses.
- Use concise bullets or short paragraphs instead.

33 changes: 13 additions & 20 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,19 @@
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src

# Copy build infrastructure
COPY Directory.Build.props Directory.Build.targets Directory.Packages.props NuGet.config global.json ./

# Copy project files for restore
COPY src/McpServer.Support.Mcp/McpServer.Support.Mcp.csproj src/McpServer.Support.Mcp/
COPY src/McpServer.ServiceDefaults/McpServer.ServiceDefaults.csproj src/McpServer.ServiceDefaults/
COPY src/McpServer.Common.Copilot/McpServer.Common.Copilot.csproj src/McpServer.Common.Copilot/

# Restore (cached layer)
RUN dotnet restore src/McpServer.Support.Mcp/McpServer.Support.Mcp.csproj

# Copy source code
COPY src/McpServer.Support.Mcp/ src/McpServer.Support.Mcp/
COPY src/McpServer.ServiceDefaults/ src/McpServer.ServiceDefaults/
COPY src/McpServer.Common.Copilot/ src/McpServer.Common.Copilot/
COPY templates/ templates/

# Publish
RUN dotnet publish src/McpServer.Support.Mcp/McpServer.Support.Mcp.csproj \
-c Release -o /app/publish --no-restore
# Copy build infrastructure
COPY Directory.Build.props Directory.Build.targets Directory.Packages.props NuGet.config global.json ./

# Copy source and templates
COPY src/ src/
COPY templates/ templates/

# Restore (cached layer)
RUN dotnet restore src/McpServer.Support.Mcp/McpServer.Support.Mcp.csproj

# Publish
RUN dotnet publish src/McpServer.Support.Mcp/McpServer.Support.Mcp.csproj \
-c Release -o /app/publish --no-restore

# Stage 2: Runtime
FROM mcr.microsoft.com/dotnet/aspnet:9.0
Expand Down
2 changes: 1 addition & 1 deletion GitVersion.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mode: ContinuousDelivery
next-version: 0.2.57
next-version: 0.2.59
assembly-versioning-scheme: MajorMinorPatch
assembly-informational-format: '{SemVer}+Branch.{BranchName}.Sha.{ShortSha}'
branches:
Expand Down
Loading
Loading